diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 60de16d3..e24971ce 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -40,6 +40,7 @@ module.exports = { BUILD_MODE: "readonly", DEBUG_MODE: "readonly", IS_BETA_VERSION: "readonly", + __MK_GLOBAL__: "readonly", // YOUTUBE PAGE API ytplayer: "readonly", }, diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21fc5771..8a687627 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,7 @@ # adopted from https://github.com/MihailRis/VoxelEngine-Cpp name: Build and Release -on: - push: - tags: - - "*" +on: [push] permissions: contents: write @@ -24,16 +21,12 @@ jobs: path: vot pattern: vot-* merge-multiple: true - - name: Grab and store version - run: | - tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$") - echo "VERSION=$tag_name" >> $GITHUB_ENV - name: Create release uses: softprops/action-gh-release@v1 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ github.ref }} - name: ${{ env.VERSION }} + name: ${{ github.sha }} draft: true prerelease: false files: | diff --git a/README-EN.md b/README-EN.md index ad3d89ac..abc97ab1 100644 --- a/README-EN.md +++ b/README-EN.md @@ -21,19 +21,22 @@ The voice-over translation of the video is now available not only in YandexBrows These domains can be set in the extension settings (only those domains that can be changed without rebuilding are listed here): #### Proxy-server +- [vot.toil.cc](https://vot.toil.cc/health) (Load balancer between proxy servers) - [vot.deno.dev](https://github.com/FOSWLY/vot-worker) - [vot-worker.onrender.com](https://github.com/FOSWLY/vot-worker) - [vot-new.toil-dump.workers.dev](https://github.com/FOSWLY/vot-worker) (⚠️ doesn't work in Russia) #### M3U8 Proxy-server -- [m3u8proxy.toil-dump.workers.dev](https://github.com/FOSWLY/m3u8CloudflareWorkerProxy) (⚠️ doesn't work in Russia) +- [m3u8-proxy.toil.cc](https://github.com/FOSWLY/m3u8-proxy-worker) +- [m3u8-proxy.toiloff.workers.dev](https://github.com/FOSWLY/m3u8-proxy-worker) (⚠️ doesn't work in Russia. It's not recommended for use due to low limits.) ## List of supported sites: You can see all the restrictions related to site support in [wiki](https://github.com/ilyhalight/voice-over-translation/wiki/%5BEN%5D-Supported-sites). - **[YouTube](https://www.youtube.com)** - **[Twitch](https://www.twitch.tv)** - **[VK](https://vk.com)** -- **[Twitter](https://twitter.com/)** +- **[OK](https://ok.ru/)** +- **[[⚠️] Twitter](https://twitter.com/)** - **[9GAG](https://9gag.com/gag/)** - **[Rutube](https://rutube.ru/)** - **[Bilibili](https://bilibili.com/)** @@ -44,14 +47,19 @@ You can see all the restrictions related to site support in [wiki](https://githu - **[Bitchute](https://www.bitchute.com/)** - **[Coursera](https://www.coursera.org/)** - **[[⚠️] Udemy](https://www.udemy.com/)** -- **[[❌] Facebook*](https://facebook.com/)** +- **[[⚠️] Facebook*](https://facebook.com/)** - **[TikTok](https://tiktok.com/)** - **[Rumble](https://rumble.com/)** - **[EPorner](https://www.eporner.com/)** - **[Peertube](https://tube.shanti.cafe/)** - **[Dailymotion](https://www.dailymotion.com/)** - **[Trovo](https://trovo.live/)** -- **[Yandex Disk](https://disk.yandex.ru/)** +- **[[⚠️] Yandex Disk](https://disk.yandex.ru/)** +- **[Google Drive](https://drive.google.com/)** +- **[Banned Video](https://banned.video/)** +- **[Weverse](https://weverse.io/)** +- **[Egghead](https://egghead.io)** +- **[Youku](https://youku.com)** - **[ProxiTok](https://proxitok.pabloferreiro.es/)** - **[[⚠️] Invidious](https://yewtu.be)** - **[[⚠️] Piped](https://piped.video)** @@ -181,6 +189,6 @@ Example of changing styles: ⚠️ - They are not priority extensions. These extensions, due to the "cloudflare" version of the user script, do not have cross-site synchronization of settings, and are also (practically) not tested before the release of a new version of the user script. -![example btn](https://github.com/ilyhalight/voice-over-translation/blob/master/img/example_en.jpg "btn") +![example btn](https://github.com/ilyhalight/voice-over-translation/blob/master/img/example_en.png "btn") *: Banned on the territory of the Russian Federation diff --git a/README.md b/README.md index 07596580..dbca159e 100644 --- a/README.md +++ b/README.md @@ -22,19 +22,22 @@ Эти домены могут быть установлены в настройках расширения (здесь указаны только те домены, которые можно изменить без пересборки): #### Proxy-сервер +- [vot.toil.cc](https://vot.toil.cc/health) (Балансировщик между прокси серверами) - [vot.deno.dev](https://github.com/FOSWLY/vot-worker) - [vot-worker.onrender.com](https://github.com/FOSWLY/vot-worker) - [vot-new.toil-dump.workers.dev](https://github.com/FOSWLY/vot-worker) (⚠️ не работает в РФ) #### M3U8 Proxy-сервер -- [m3u8proxy.toil-dump.workers.dev](https://github.com/FOSWLY/m3u8CloudflareWorkerProxy) (⚠️ не работает в РФ) +- [m3u8-proxy.toil.cc](https://github.com/FOSWLY/m3u8-proxy-worker) +- [m3u8-proxy.toiloff.workers.dev](https://github.com/FOSWLY/m3u8-proxy-worker) (⚠️ не работает в РФ. Не рекомендуется к использованию из-за низких лимитов.) ## Список поддерживаемых сайтов: Все ограничения, связанные с поддержкой сайтов вы можете увидеть в [вики](https://github.com/ilyhalight/voice-over-translation/wiki/%5BRU%5D-Supported-sites). - **[YouTube](https://www.youtube.com)** - **[Twitch](https://www.twitch.tv)** - **[VK](https://vk.com)** -- **[Twitter](https://twitter.com/)** +- **[OK](https://ok.ru/)** +- **[[⚠️] Twitter](https://twitter.com/)** - **[9GAG](https://9gag.com/gag/)** - **[Rutube](https://rutube.ru/)** - **[Bilibili](https://bilibili.com/)** @@ -45,14 +48,19 @@ - **[Bitchute](https://www.bitchute.com/)** - **[Coursera](https://www.coursera.org/)** - **[[⚠️] Udemy](https://www.udemy.com/)** -- **[[❌] Facebook*](https://facebook.com/)** +- **[[⚠️] Facebook*](https://facebook.com/)** - **[TikTok](https://tiktok.com/)** - **[Rumble](https://rumble.com/)** - **[EPorner](https://www.eporner.com/)** - **[Peertube](https://tube.shanti.cafe/)** - **[Dailymotion](https://www.dailymotion.com/)** - **[Trovo](https://trovo.live/)** -- **[Yandex Disk](https://disk.yandex.ru/)** +- **[[⚠️] Yandex Disk](https://disk.yandex.ru/)** +- **[Google Drive](https://drive.google.com/)** +- **[Banned Video](https://banned.video/)** +- **[Weverse](https://weverse.io/)** +- **[Egghead](https://egghead.io)** +- **[Youku](https://youku.com)** - **[ProxiTok](https://proxitok.pabloferreiro.es/)** - **[[⚠️] Invidious](https://yewtu.be)** - **[[⚠️] Piped](https://piped.video)** @@ -182,6 +190,6 @@ npm i ⚠️ - Не являются приоритетными расширениями. Эти расширения из-за "cloudflare" версии юзерскрипта не имеют межсайтовой синхронизации настроек, а так же (практически) не тестируются перед выходом новой версии юзерскрипта. -![example btn](https://github.com/ilyhalight/voice-over-translation/blob/master/img/example.jpg "btn") +![example btn](https://github.com/ilyhalight/voice-over-translation/blob/master/img/example.png "btn") *: Запрещена на территории РФ diff --git a/changelog.md b/changelog.md index d6d819ec..052e337f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,89 @@ + + +# 1.5.1 +- Добавлена поддержка Одноклассников от @SashaXser в #476 +- Добавлена поддержка Google Drive (только публичные ссылки, например: `https://drive.google.com/file/d/FILE_ID`) +- Добавлена поддержка Banned Video (banned.video) +- Добавлена поддержка Egghead от @SashaXser в #531 +- Добавлена поддержка Youku от @SashaXser в #531 +- Добавлена поддержка корп. видео для `player.vimeo.com` (поддержка параметра app_id). Для использования перевода на `player.vimeo.com` нужно полностью отключить CSP. +- Добавлена поддержка Facebook (работает только с ссылками, которые содержат `/video/` или `/reel/`). Для использования перевода нужно полностью отключить CSP. +- Добавлена поддержка Weverse (работает только с ссылками, которые содержат `/live/` или `/media/`) +- Добавлена поддержка Newgrounds от @SashaXser в #523 +- Добавлено определение языка в VK по субтитрам и обновление зависимостей от @SashaXser в #531 +- Исправлена работа YouTube Embed через JS API (#544) +- Исправлена работа Bitchute от @SashaXser в #531 (#542) +- Улучшена очистка описания на Youtube от @SashaXser в #476 +- Улучшена логика инициализации БД от @SashaXser в #531 +- Улучшено получение ID видео для Dailymotion от @SashaXser в #476 +- Улучшение оптимизации от @SashaXser в #499 +- Улучшено добавление фраз локализации при сборке от @SashaXser в #499 +- Функция форматирования строк заменена на стандартный `replace` от @SashaXser в #499 +- Исправлен баг, когда стримы могли не переводиться, если они идут более 4 часов от @SashaXser в #499 +- Исправлен баг с отключением перевода на стримах от @SashaXser в #499 +- Исправлена ошибка из-за которой значение автогромкости могло иметь слишком много знаков после запятой +- Исправлена ошибка из-за которой значение автогромкости по умолчанию было 0.15%, а не 15% +- Время отображения кнопки перевода уменьшено до 1 секунды +- Убраны пути `/s/` и `/d/` из определения айди видео в Яндекс Диске (скрипт не запускался на этих путях, поэтому для конечного пользователя ничего не изменилось) +- HLS заменен на облегченную версию HLS light от @SashaXser в #506 +- В утилитах для сайтов экспорт изменен на эспорт по умолчанию +- Теперь, полученные переводы кешируются до перезагрузки страницы. Благодаря этому удалось избавиться от лишних запросов к серверу, а так же это избавило от проблем, когда из-за изменения качества приходилось заново ждать перевод (например на weverse) +- Старая реализация установки громкости звука в "stopTranslate" изменена на актуальную - "this.setVideoVolume" +- Объединен некоторый повторяющийся код +- Webpack-Userscript изменен на Webpack-Monkey +- Стандартный домен worker прокси-сервера изменен на `vot.toil.cc` (Балансировщик между прокси серверами) +- Стандартный домен M3U8 Proxy Worker изменен на `m3u8-proxy.toil.cc`, дабы избавиться от ограничений cloudflare (слишком маленький лимит запросов для m3u8 + недоступность в РФ). Если вы все равно хотите использовать M3U8 Proxy Worker, который хостится на cloudflare, то прошу перейти на `m3u8-proxy.toiloff.workers.dev` т.к. воркер на старом домене будет выключен спустя некоторое время для уменьшения числа запросов к основному worker proxy. + +# 1.5.1-beta7 +- Исправлена работа YouTube Embed через JS API (#544) +- Исправлена работа Bitchute от @SashaXser в #531 (#542) +- Добавлена поддержка Egghead от @SashaXser в #531 +- Добавлена поддержка Youku от @SashaXser в #531 +- Улучшена логика инициализации БД от @SashaXser в #531 +- Добавлено определение языка в VK по субтитрам и обновление зависимостей от @SashaXser в #531 +- Убрана устаревшая логика fullscreen от @SashaXser в #531 +- Webpack-Userscript изменен на Webpack-Monkey +- Стандартный домен worker прокси-сервера изменен на `vot.toil.cc` (Балансировщик между прокси серверами) + +# 1.5.1-beta6 +- Теперь, полученные переводы кешируются до перезагрузки страницы. Благодаря этому удалось избавиться от лишних запросов к серверу, а так же это избавило от проблем, когда из-за изменения качества приходилось заново ждать перевод (например на weverse) +- Старая реализация установки громкости звука в "stopTranslate" изменена на актуальную - "this.setVideoVolume" +- Объединен некоторый повторяющийся код + +# 1.5.1-beta5 +- Добавлена поддержка Weverse (работает только с ссылками, которые содержат `/live/` или `/media/`) +- Добавлена поддержка Newgrounds от @SashaXser в #523 +- Небольшие правки в коде от @SashaXser в #523 +- В утилитах для сайтов экспорт изменен на эспорт по умолчанию + +# 1.5.1-beta4 +- Добавлена поддержка Google Drive (только публичные ссылки, например: `https://drive.google.com/file/d/FILE_ID`) +- Добавлена поддержка Banned Video (banned.video) +- Добавлена поддержка корп. видео для `player.vimeo.com` (поддержка параметра app_id). Для использования перевода на `player.vimeo.com` нужно полностью отключить CSP. +- Добавлена поддержка Facebook (работает только с ссылками, которые содержат `/video/` или `/reel/`). Для использования перевода нужно полностью отключить CSP. + +# 1.5.1-beta3 +- HLS заменен на облегченную версию HLS light от @SashaXser в #506 +- Убраны пути `/s/` и `/d/` из определения айди видео в Яндекс Диске (скрипт не запускался на этих путях, поэтому для конечного пользователя ничего не изменилось) +- Исправлена ошибка из-за которой значение автогромкости по умолчанию было 0.15%, а не 15% +- Исправлена ошибка из-за которой значение автогромкости могло иметь слишком много знаков после запятой + +# 1.5.1-beta2 +Все изменения были внесены @SashaXser в #499 + +- Исправлен баг с отключением перевода на стримах +- Исправлен баг, когда стримы могли не переводиться, если они идут более 4 часов +- Функция форматирования строк заменена на стандартный `replace` +- Улучшено добавление фраз локализации при сборке +- Улучшение оптимизации +- Другие правки + +# 1.5.1-beta1 (от @SashaXser в #476) +- Добавлена поддержка Одноклассников +- Улучшена очистка описания на Youtube +- Улучшено получение ID видео для Dailymotion +- Другие мелкие улучшения кода + # 1.5.0.5 - Исправлен перевод для Coursera - Обновлен Yandex Protobuf @@ -9,10 +95,10 @@ - Стандартный прокси-воркер изменен на `https://vot-worker.onrender.com` # 1.5.0.2 -- Улучшена очистка описания на Youtube от @SashaXser в #46 +- Улучшена очистка описания на Youtube от @SashaXser в #467 # 1.5.0.1 -- Фикс работы с Chromium <88 и Firefox<86. В этих браузерах (для Cent Browser и других старых браузеров) +- Фикс работы с Chromium <88 и Firefox<86 (для Cent Browser и других старых браузеров) # 1.5.0 - Добавлена эксперементальная поддержка трансляций (На 23.12.2023 не работает в РФ из-за ограничений на российский айпи от cloudflare worker (позже исправлю). С задержкой как повезет, но в большинстве случаев довольно терпимо +-0-2 секунды от оригинала, но иногда бывает отставание до 10 секунд, но перезапуск перевода помогает уменьшить задержку) @@ -124,7 +210,7 @@ - Фикс Coursera (#444) # 1.5.0-beta10 -- Добавлена поддержка Yandex Disk (только публичные ссылки, например: `https://disk.yandex.ru/s/FILE_ID`) +- Добавлена поддержка Yandex Disk (только публичные ссылки, например: `https://disk.yandex.ru/i/FILE_ID`) - Добавлена поддержка Trovo (клипы или уже завершенные трансляции) - Добавлена частичная поддержка Dailymotion ([34#issuecomment-1533772639](https://github.com/ilyhalight/voice-over-translation/issues/34#issuecomment-1533772639)) diff --git a/dist/vot-cloudflare-min.user.js b/dist/vot-cloudflare-min.user.js index 76a823d2..67316400 100644 --- a/dist/vot-cloudflare-min.user.js +++ b/dist/vot-cloudflare-min.user.js @@ -1,125 +1,130 @@ // ==UserScript== -// @name [VOT Cloudflare] - Voice Over Translation -// @name:de [VOT Cloudflare] - Voice-Over-Video-Übersetzung -// @name:es [VOT Cloudflare] - Traducción de vídeo en off -// @name:fr [VOT Cloudflare] - Traduction vidéo voix-off -// @name:it [VOT Cloudflare] - Traduzione Video fuori campo -// @name:ru [VOT Cloudflare] - Закадровый перевод видео -// @name:zh [VOT Cloudflare] - 画外音视频翻译 -// @description A small extension that adds a Yandex Browser video translation to other browsers +// @name [VOT Cloudflare] - Voice Over Translation +// @name:de [VOT Cloudflare] - Voice-Over-Video-Übersetzung +// @name:es [VOT Cloudflare] - Traducción de vídeo en off +// @name:fr [VOT Cloudflare] - Traduction vidéo voix-off +// @name:it [VOT Cloudflare] - Traduzione Video fuori campo +// @name:ru [VOT Cloudflare] - Закадровый перевод видео +// @name:zh [VOT Cloudflare] - 画外音视频翻译 +// @description A small extension that adds a Yandex Browser video translation to other browsers // @description:de Eine kleine Erweiterung, die eine Voice-over-Übersetzung von Videos aus dem Yandex-Browser zu anderen Browsern hinzufügt // @description:es Una pequeña extensión que agrega una traducción de voz en off de un video de Yandex Browser a otros navegadores // @description:fr Une petite extension qui ajoute la traduction vocale de la vidéo du Navigateur Yandex à d'autres navigateurs // @description:it Una piccola estensione che aggiunge la traduzione vocale del video dal browser Yandex ad altri browser // @description:ru Небольшое расширение, которое добавляет закадровый перевод видео из Яндекс Браузера в другие браузеры // @description:zh 一个小扩展,它增加了视频从Yandex浏览器到其他浏览器的画外音翻译 -// @version 1.5.0.5 -// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD -// @supportURL https://github.com/ilyhalight/voice-over-translation/issues -// @match *://*.youtube.com/* -// @match *://*.youtube-nocookie.com/* -// @match *://*.youtubekids.com/* -// @match *://*.twitch.tv/* -// @match *://*.xvideos.com/* -// @match *://*.pornhub.com/* -// @match *://*.vk.com/* -// @match *://*.vk.ru/* -// @match *://invidious.snopyta.org/* -// @match *://invidious.kavin.rocks/* -// @match *://vid.puffyan.us/* -// @match *://invidious.namazso.eu/* -// @match *://inv.riverside.rocks/* -// @match *://yt.artemislena.eu/* -// @match *://invidious.flokinet.to/* -// @match *://invidious.esmailelbob.xyz/* -// @match *://invidious.nerdvpn.de/* -// @match *://invidious.slipfox.xyz/* -// @match *://invidio.xamh.de/* -// @match *://invidious.dhusch.de/* -// @match *://*.piped.video/* -// @match *://piped.tokhmi.xyz/* -// @match *://piped.moomoo.me/* -// @match *://piped.syncpundit.io/* -// @match *://piped.mha.fi/* -// @match *://watch.whatever.social/* -// @match *://piped.garudalinux.org/* -// @match *://efy.piped.pages.dev/* -// @match *://watch.leptons.xyz/* -// @match *://piped.lunar.icu/* -// @match *://yt.dc09.ru/* -// @match *://piped.mint.lgbt/* -// @match *://*.il.ax/* -// @match *://piped.privacy.com.de/* -// @match *://piped.esmailelbob.xyz/* -// @match *://piped.projectsegfau.lt/* -// @match *://piped.in.projectsegfau.lt/* -// @match *://piped.us.projectsegfau.lt/* -// @match *://piped.privacydev.net/* -// @match *://piped.palveluntarjoaja.eu/* -// @match *://piped.smnz.de/* -// @match *://piped.adminforge.de/* -// @match *://piped.qdi.fi/* -// @match *://piped.hostux.net/* -// @match *://piped.chauvet.pro/* -// @match *://piped.jotoma.de/* -// @match *://piped.pfcd.me/* -// @match *://piped.frontendfriendly.xyz/* -// @match *://*.yewtu.be/* -// @match *://inv.vern.cc/* -// @match *://*.vimeo.com/* -// @match *://*.9gag.com/* -// @match *://*.twitter.com/* -// @match *://*.facebook.com/* -// @match *://*.rutube.ru/* -// @match *://*.bilibili.com/* -// @match *://my.mail.ru/* -// @match *://*.bitchute.com/* -// @match *://*.coursera.org/learn/* -// @match *://*.udemy.com/course/* -// @match *://*.tiktok.com/* -// @match *://proxitok.pabloferreiro.es/* -// @match *://proxitok.pussthecat.org/* -// @match *://tok.habedieeh.re/* -// @match *://proxitok.esmailelbob.xyz/* -// @match *://proxitok.privacydev.net/* -// @match *://tok.artemislena.eu/* -// @match *://tok.adminforge.de/* -// @match *://tik.hostux.net/* -// @match *://tt.vern.cc/* -// @match *://cringe.whatever.social/* -// @match *://proxitok.lunar.icu/* -// @match *://proxitok.privacy.com.de/* -// @match *://rumble.com/* -// @match *://*.eporner.com/* -// @match *://peertube.1312.media/* -// @match *://tube.shanti.cafe/* -// @match *://bee-tube.fr/* -// @match *://video.sadmin.io/* -// @match *://dalek.zone/* -// @match *://review.peertube.biz/* -// @match *://peervideo.club/* -// @match *://tube.la-dina.net/* -// @match *://peertube.tmp.rcp.tf/* -// @match *://geo.dailymotion.com/* -// @match *://trovo.live/* -// @match *://disk.yandex.ru/i/* -// @match *://coursehunter.net/* -// @connect api.browser.yandex.ru -// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare-min.user.js -// @grant GM_xmlhttpRequest -// @grant GM_info -// @grant GM_setValue -// @grant GM_getValue -// @grant GM_deleteValue -// @grant GM_listValues -// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues -// @icon https://translate.yandex.ru/icons/favicon.ico -// @inject-into page -// @namespace vot-cloudflare-min -// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js -// @require https://cdn.jsdelivr.net/npm/hls.js@1 -// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare-min.user.js +// @grant GM_addStyle +// @grant GM_deleteValue +// @grant GM_listValues +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_info +// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js +// @require https://cdn.jsdelivr.net/npm/hls.js/dist/hls.light.min.js +// @match *://*.youtube.com/* +// @match *://*.youtube-nocookie.com/* +// @match *://*.youtubekids.com/* +// @match *://*.twitch.tv/* +// @match *://*.xvideos.com/* +// @match *://*.pornhub.com/* +// @match *://*.vk.com/* +// @match *://*.vk.ru/* +// @match *://invidious.snopyta.org/* +// @match *://invidious.kavin.rocks/* +// @match *://vid.puffyan.us/* +// @match *://invidious.namazso.eu/* +// @match *://inv.riverside.rocks/* +// @match *://yt.artemislena.eu/* +// @match *://invidious.flokinet.to/* +// @match *://invidious.esmailelbob.xyz/* +// @match *://invidious.nerdvpn.de/* +// @match *://invidious.slipfox.xyz/* +// @match *://invidio.xamh.de/* +// @match *://invidious.dhusch.de/* +// @match *://*.piped.video/* +// @match *://piped.tokhmi.xyz/* +// @match *://piped.moomoo.me/* +// @match *://piped.syncpundit.io/* +// @match *://piped.mha.fi/* +// @match *://watch.whatever.social/* +// @match *://piped.garudalinux.org/* +// @match *://efy.piped.pages.dev/* +// @match *://watch.leptons.xyz/* +// @match *://piped.lunar.icu/* +// @match *://yt.dc09.ru/* +// @match *://piped.mint.lgbt/* +// @match *://*.il.ax/* +// @match *://piped.privacy.com.de/* +// @match *://piped.esmailelbob.xyz/* +// @match *://piped.projectsegfau.lt/* +// @match *://piped.in.projectsegfau.lt/* +// @match *://piped.us.projectsegfau.lt/* +// @match *://piped.privacydev.net/* +// @match *://piped.palveluntarjoaja.eu/* +// @match *://piped.smnz.de/* +// @match *://piped.adminforge.de/* +// @match *://piped.qdi.fi/* +// @match *://piped.hostux.net/* +// @match *://piped.chauvet.pro/* +// @match *://piped.jotoma.de/* +// @match *://piped.pfcd.me/* +// @match *://piped.frontendfriendly.xyz/* +// @match *://*.yewtu.be/* +// @match *://inv.vern.cc/* +// @match *://*.vimeo.com/* +// @match *://*.9gag.com/* +// @match *://*.twitter.com/* +// @match *://*.facebook.com/* +// @match *://*.rutube.ru/* +// @match *://*.bilibili.com/* +// @match *://my.mail.ru/* +// @match *://*.bitchute.com/* +// @match *://*.coursera.org/learn/* +// @match *://*.udemy.com/course/* +// @match *://*.tiktok.com/* +// @match *://proxitok.pabloferreiro.es/* +// @match *://proxitok.pussthecat.org/* +// @match *://tok.habedieeh.re/* +// @match *://proxitok.esmailelbob.xyz/* +// @match *://proxitok.privacydev.net/* +// @match *://tok.artemislena.eu/* +// @match *://tok.adminforge.de/* +// @match *://tik.hostux.net/* +// @match *://tt.vern.cc/* +// @match *://cringe.whatever.social/* +// @match *://proxitok.lunar.icu/* +// @match *://proxitok.privacy.com.de/* +// @match *://rumble.com/* +// @match *://*.eporner.com/* +// @match *://peertube.1312.media/* +// @match *://tube.shanti.cafe/* +// @match *://bee-tube.fr/* +// @match *://video.sadmin.io/* +// @match *://dalek.zone/* +// @match *://review.peertube.biz/* +// @match *://peervideo.club/* +// @match *://tube.la-dina.net/* +// @match *://peertube.tmp.rcp.tf/* +// @match *://geo.dailymotion.com/* +// @match *://*.ok.ru/* +// @match *://trovo.live/* +// @match *://disk.yandex.ru/i/* +// @match *://coursehunter.net/* +// @match *://youtube.googleapis.com/embed/* +// @match *://*.banned.video/* +// @match *://*.weverse.io/* +// @match *://*.newgrounds.com/* +// @match *://*.egghead.io/* +// @match *://*.youku.com/* +// @connect api.browser.yandex.ru +// @namespace vot-cloudflare-min +// @version 1.5.1 +// @icon https://translate.yandex.ru/icons/favicon.ico +// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD +// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues +// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare-min.user.js +// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare-min.user.js +// @supportURL https://github.com/ilyhalight/voice-over-translation/issues // ==/UserScript== -/*! For license information please see vot-cloudflare-min.js.LICENSE.txt */ -(()=>{var t={"./node_modules/bowser/es5.js":function(t){t.exports=function(t){var e={};function o(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,o),i.l=!0,i.exports}return o.m=t,o.c=e,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)o.d(n,i,function(e){return t[e]}.bind(null,i));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=90)}({17:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n=o(18),i=function(){function t(){}return t.getFirstMatch=function(t,e){var o=e.match(t);return o&&o.length>0&&o[1]||""},t.getSecondMatch=function(t,e){var o=e.match(t);return o&&o.length>1&&o[2]||""},t.matchAndReturnConst=function(t,e,o){if(t.test(e))return o},t.getWindowsVersionName=function(t){switch(t){case"NT":return"NT";case"XP":case"NT 5.1":return"XP";case"NT 5.0":return"2000";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return}},t.getMacOSVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),10===e[0])switch(e[1]){case 5:return"Leopard";case 6:return"Snow Leopard";case 7:return"Lion";case 8:return"Mountain Lion";case 9:return"Mavericks";case 10:return"Yosemite";case 11:return"El Capitan";case 12:return"Sierra";case 13:return"High Sierra";case 14:return"Mojave";case 15:return"Catalina";default:return}},t.getAndroidVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),!(1===e[0]&&e[1]<5))return 1===e[0]&&e[1]<6?"Cupcake":1===e[0]&&e[1]>=6?"Donut":2===e[0]&&e[1]<2?"Eclair":2===e[0]&&2===e[1]?"Froyo":2===e[0]&&e[1]>2?"Gingerbread":3===e[0]?"Honeycomb":4===e[0]&&e[1]<1?"Ice Cream Sandwich":4===e[0]&&e[1]<4?"Jelly Bean":4===e[0]&&e[1]>=4?"KitKat":5===e[0]?"Lollipop":6===e[0]?"Marshmallow":7===e[0]?"Nougat":8===e[0]?"Oreo":9===e[0]?"Pie":void 0},t.getVersionPrecision=function(t){return t.split(".").length},t.compareVersions=function(e,o,n){void 0===n&&(n=!1);var i=t.getVersionPrecision(e),a=t.getVersionPrecision(o),r=Math.max(i,a),s=0,l=t.map([e,o],(function(e){var o=r-t.getVersionPrecision(e),n=e+new Array(o+1).join(".0");return t.map(n.split("."),(function(t){return new Array(20-t.length).join("0")+t})).reverse()}));for(n&&(s=r-Math.min(i,a)),r-=1;r>=s;){if(l[0][r]>l[1][r])return 1;if(l[0][r]===l[1][r]){if(r===s)return 0;r-=1}else if(l[0][r]1?i-1:0),r=1;r0){var r=Object.keys(o),l=s.default.find(r,(function(t){return e.isOS(t)}));if(l){var d=this.satisfies(o[l]);if(void 0!==d)return d}var c=s.default.find(r,(function(t){return e.isPlatform(t)}));if(c){var u=this.satisfies(o[c]);if(void 0!==u)return u}}if(a>0){var h=Object.keys(i),p=s.default.find(h,(function(t){return e.isBrowser(t,!0)}));if(void 0!==p)return this.compareVersion(i[p])}},e.isBrowser=function(t,e){void 0===e&&(e=!1);var o=this.getBrowserName().toLowerCase(),n=t.toLowerCase(),i=s.default.getBrowserTypeByAlias(n);return e&&i&&(n=i.toLowerCase()),n===o},e.compareVersion=function(t){var e=[0],o=t,n=!1,i=this.getBrowserVersion();if("string"==typeof i)return">"===t[0]||"<"===t[0]?(o=t.substr(1),"="===t[1]?(n=!0,o=t.substr(2)):e=[],">"===t[0]?e.push(1):e.push(-1)):"="===t[0]?o=t.substr(1):"~"===t[0]&&(n=!0,o=t.substr(1)),e.indexOf(s.default.compareVersions(i,o,n))>-1},e.isOS=function(t){return this.getOSName(!0)===String(t).toLowerCase()},e.isPlatform=function(t){return this.getPlatformType(!0)===String(t).toLowerCase()},e.isEngine=function(t){return this.getEngineName(!0)===String(t).toLowerCase()},e.is=function(t,e){return void 0===e&&(e=!1),this.isBrowser(t,e)||this.isOS(t)||this.isPlatform(t)},e.some=function(t){var e=this;return void 0===t&&(t=[]),t.some((function(t){return e.is(t)}))},t}();e.default=d,t.exports=e.default},92:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=/version\/(\d+(\.?_?\d+)+)/i,r=[{test:[/googlebot/i],describe:function(t){var e={name:"Googlebot"},o=i.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/opera/i],describe:function(t){var e={name:"Opera"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opr\/|opios/i],describe:function(t){var e={name:"Opera"},o=i.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/SamsungBrowser/i],describe:function(t){var e={name:"Samsung Internet for Android"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Whale/i],describe:function(t){var e={name:"NAVER Whale Browser"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MZBrowser/i],describe:function(t){var e={name:"MZ Browser"},o=i.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/focus/i],describe:function(t){var e={name:"Focus"},o=i.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/swing/i],describe:function(t){var e={name:"Swing"},o=i.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/coast/i],describe:function(t){var e={name:"Opera Coast"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(t){var e={name:"Opera Touch"},o=i.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/yabrowser/i],describe:function(t){var e={name:"Yandex Browser"},o=i.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/ucbrowser/i],describe:function(t){var e={name:"UC Browser"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Maxthon|mxios/i],describe:function(t){var e={name:"Maxthon"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/epiphany/i],describe:function(t){var e={name:"Epiphany"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/puffin/i],describe:function(t){var e={name:"Puffin"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sleipnir/i],describe:function(t){var e={name:"Sleipnir"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/k-meleon/i],describe:function(t){var e={name:"K-Meleon"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/micromessenger/i],describe:function(t){var e={name:"WeChat"},o=i.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/qqbrowser/i],describe:function(t){var e={name:/qqbrowserlite/i.test(t)?"QQ Browser Lite":"QQ Browser"},o=i.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/msie|trident/i],describe:function(t){var e={name:"Internet Explorer"},o=i.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/\sedg\//i],describe:function(t){var e={name:"Microsoft Edge"},o=i.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/edg([ea]|ios)/i],describe:function(t){var e={name:"Microsoft Edge"},o=i.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/vivaldi/i],describe:function(t){var e={name:"Vivaldi"},o=i.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/seamonkey/i],describe:function(t){var e={name:"SeaMonkey"},o=i.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sailfish/i],describe:function(t){var e={name:"Sailfish"},o=i.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,t);return o&&(e.version=o),e}},{test:[/silk/i],describe:function(t){var e={name:"Amazon Silk"},o=i.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/phantom/i],describe:function(t){var e={name:"PhantomJS"},o=i.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/slimerjs/i],describe:function(t){var e={name:"SlimerJS"},o=i.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e={name:"BlackBerry"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e={name:"WebOS Browser"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/bada/i],describe:function(t){var e={name:"Bada"},o=i.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/tizen/i],describe:function(t){var e={name:"Tizen"},o=i.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/qupzilla/i],describe:function(t){var e={name:"QupZilla"},o=i.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/firefox|iceweasel|fxios/i],describe:function(t){var e={name:"Firefox"},o=i.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/electron/i],describe:function(t){var e={name:"Electron"},o=i.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MiuiBrowser/i],describe:function(t){var e={name:"Miui"},o=i.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/chromium/i],describe:function(t){var e={name:"Chromium"},o=i.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/chrome|crios|crmo/i],describe:function(t){var e={name:"Chrome"},o=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/GSA/i],describe:function(t){var e={name:"Google Search"},o=i.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e={name:"Android Browser"},o=i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/playstation 4/i],describe:function(t){var e={name:"PlayStation 4"},o=i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/safari|applewebkit/i],describe:function(t){var e={name:"Safari"},o=i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/.*/i],describe:function(t){var e=-1!==t.search("\\(")?/^(.*)\/(.*)[ \t]\((.*)/:/^(.*)\/(.*) /;return{name:i.default.getFirstMatch(e,t),version:i.default.getSecondMatch(e,t)}}}];e.default=r,t.exports=e.default},93:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=o(18),r=[{test:[/Roku\/DVP/],describe:function(t){var e=i.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,t);return{name:a.OS_MAP.Roku,version:e}}},{test:[/windows phone/i],describe:function(t){var e=i.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.WindowsPhone,version:e}}},{test:[/windows /i],describe:function(t){var e=i.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,t),o=i.default.getWindowsVersionName(e);return{name:a.OS_MAP.Windows,version:e,versionName:o}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(t){var e={name:a.OS_MAP.iOS},o=i.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,t);return o&&(e.version=o),e}},{test:[/macintosh/i],describe:function(t){var e=i.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,t).replace(/[_\s]/g,"."),o=i.default.getMacOSVersionName(e),n={name:a.OS_MAP.MacOS,version:e};return o&&(n.versionName=o),n}},{test:[/(ipod|iphone|ipad)/i],describe:function(t){var e=i.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,t).replace(/[_\s]/g,".");return{name:a.OS_MAP.iOS,version:e}}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e=i.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,t),o=i.default.getAndroidVersionName(e),n={name:a.OS_MAP.Android,version:e};return o&&(n.versionName=o),n}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e=i.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,t),o={name:a.OS_MAP.WebOS};return e&&e.length&&(o.version=e),o}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e=i.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,t)||i.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,t)||i.default.getFirstMatch(/\bbb(\d+)/i,t);return{name:a.OS_MAP.BlackBerry,version:e}}},{test:[/bada/i],describe:function(t){var e=i.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.Bada,version:e}}},{test:[/tizen/i],describe:function(t){var e=i.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.Tizen,version:e}}},{test:[/linux/i],describe:function(){return{name:a.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:a.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(t){var e=i.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.PlayStation4,version:e}}}];e.default=r,t.exports=e.default},94:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=o(18),r=[{test:[/googlebot/i],describe:function(){return{type:"bot",vendor:"Google"}}},{test:[/huawei/i],describe:function(t){var e=i.default.getFirstMatch(/(can-l01)/i,t)&&"Nova",o={type:a.PLATFORMS_MAP.mobile,vendor:"Huawei"};return e&&(o.model=e),o}},{test:[/nexus\s*(?:7|8|9|10).*/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Nexus"}}},{test:[/ipad/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/kftt build/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Amazon",model:"Kindle Fire HD 7"}}},{test:[/silk/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Amazon"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet}}},{test:function(t){var e=t.test(/ipod|iphone/i),o=t.test(/like (ipod|iphone)/i);return e&&!o},describe:function(t){var e=i.default.getFirstMatch(/(ipod|iphone)/i,t);return{type:a.PLATFORMS_MAP.mobile,vendor:"Apple",model:e}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:"Nexus"}}},{test:[/[^-]mobi/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(t){return"blackberry"===t.getBrowserName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:"BlackBerry"}}},{test:function(t){return"bada"===t.getBrowserName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(t){return"windows phone"===t.getBrowserName()},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:"Microsoft"}}},{test:function(t){var e=Number(String(t.getOSVersion()).split(".")[0]);return"android"===t.getOSName(!0)&&e>=3},describe:function(){return{type:a.PLATFORMS_MAP.tablet}}},{test:function(t){return"android"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(t){return"macos"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.desktop,vendor:"Apple"}}},{test:function(t){return"windows"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(t){return"linux"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(t){return"playstation 4"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:function(t){return"roku"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.tv}}}];e.default=r,t.exports=e.default},95:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=o(18),r=[{test:function(t){return"microsoft edge"===t.getBrowserName(!0)},describe:function(t){if(/\sedg\//i.test(t))return{name:a.ENGINE_MAP.Blink};var e=i.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,t);return{name:a.ENGINE_MAP.EdgeHTML,version:e}}},{test:[/trident/i],describe:function(t){var e={name:a.ENGINE_MAP.Trident},o=i.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){return t.test(/presto/i)},describe:function(t){var e={name:a.ENGINE_MAP.Presto},o=i.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=t.test(/gecko/i),o=t.test(/like gecko/i);return e&&!o},describe:function(t){var e={name:a.ENGINE_MAP.Gecko},o=i.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:a.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(t){var e={name:a.ENGINE_MAP.WebKit},o=i.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}}];e.default=r,t.exports=e.default}})},"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss":(t,e,o)=>{"use strict";o.d(e,{Z:()=>s});var n=o("./node_modules/css-loader/dist/runtime/noSourceMaps.js"),i=o.n(n),a=o("./node_modules/css-loader/dist/runtime/api.js"),r=o.n(a)()(i());r.push([t.id,'.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}',""]);const s=r},"./node_modules/css-loader/dist/runtime/api.js":t=>{"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var o="",n=void 0!==e[5];return e[4]&&(o+="@supports (".concat(e[4],") {")),e[2]&&(o+="@media ".concat(e[2]," {")),n&&(o+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),o+=t(e),n&&(o+="}"),e[2]&&(o+="}"),e[4]&&(o+="}"),o})).join("")},e.i=function(t,o,n,i,a){"string"==typeof t&&(t=[[null,t,void 0]]);var r={};if(n)for(var s=0;s0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=a),o&&(c[2]?(c[1]="@media ".concat(c[2]," {").concat(c[1],"}"),c[2]=o):c[2]=o),i&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=i):c[4]="".concat(i)),e.push(c))}},e}},"./node_modules/css-loader/dist/runtime/noSourceMaps.js":t=>{"use strict";t.exports=function(t){return t[1]}},"./node_modules/requestidlecallback-polyfill/index.js":()=>{window.requestIdleCallback=window.requestIdleCallback||function(t){var e=Date.now();return setTimeout((function(){t({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-e))}})}),1)},window.cancelIdleCallback=window.cancelIdleCallback||function(t){clearTimeout(t)}},"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":t=>{"use strict";var e=[];function o(t){for(var o=-1,n=0;n{"use strict";var e={};t.exports=function(t,o){var n=function(t){if(void 0===e[t]){var o=document.querySelector(t);if(window.HTMLIFrameElement&&o instanceof window.HTMLIFrameElement)try{o=o.contentDocument.head}catch(t){o=null}e[t]=o}return e[t]}(t);if(!n)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");n.appendChild(o)}},"./node_modules/style-loader/dist/runtime/insertStyleElement.js":t=>{"use strict";t.exports=function(t){var e=document.createElement("style");return t.setAttributes(e,t.attributes),t.insert(e,t.options),e}},"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js":(t,e,o)=>{"use strict";t.exports=function(t){var e=o.nc;e&&t.setAttribute("nonce",e)}},"./node_modules/style-loader/dist/runtime/styleDomAPI.js":t=>{"use strict";t.exports=function(t){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=t.insertStyleElement(t);return{update:function(o){!function(t,e,o){var n="";o.supports&&(n+="@supports (".concat(o.supports,") {")),o.media&&(n+="@media ".concat(o.media," {"));var i=void 0!==o.layer;i&&(n+="@layer".concat(o.layer.length>0?" ".concat(o.layer):""," {")),n+=o.css,i&&(n+="}"),o.media&&(n+="}"),o.supports&&(n+="}");var a=o.sourceMap;a&&"undefined"!=typeof btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),e.styleTagTransform(n,t,e.options)}(e,t,o)},remove:function(){!function(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t)}(e)}}}},"./node_modules/style-loader/dist/runtime/styleTagTransform.js":t=>{"use strict";t.exports=function(t,e){if(e.styleSheet)e.styleSheet.cssText=t;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(t))}}},"./src/config/config.js":(t,e,o)=>{"use strict";o.d(e,{EY:()=>c,I1:()=>r,Rr:()=>s,e6:()=>i,ez:()=>a,jm:()=>u,kF:()=>d,rm:()=>h,sN:()=>l});var n=o("./src/utils/utils.js");const i="m3u8proxy.toil-dump.workers.dev",a="uk"===n.KQ?"vot-new.toil-dump.workers.dev":"vot-worker.onrender.com",r="xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm",s="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36",l=.15,d="yandex",c="yandex",u={yandex:"https://translate.toil.cc/detect",rustServer:"https://rust-server-531j.onrender.com/detect"},h={yandex:"https://translate.toil.cc/translate"}},"./src/localization/localizationProvider.js":(t,e,o)=>{"use strict";o.d(e,{Z:()=>r,V:()=>s});const n=JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}');var i=o("./src/utils/debug.js"),a=o("./src/utils/storage.js");const r=["auto","en","ru","af","am","ar","az","bg","bn","bs","ca","cs","cy","da","de","el","es","et","eu","fa","fi","fr","gl","hi","hr","hu","hy","id","it","ja","jv","kk","km","kn","ko","lo","mk","ml","mn","ms","mt","my","ne","nl","pa","pl","pt","ro","si","sk","sl","sq","sr","su","sv","sw","tr","uk","ur","uz","vi","zh","zu"],s=new class{lang="en";locale={};gmValues=["locale-phrases","locale-lang","locale-version","locale-lang-override"];constructor(){const t=a.i.syncGet("locale-lang-override","auto");this.lang=t&&"auto"!==t?t:(navigator.language||navigator.userLanguage)?.substr(0,2)?.toLowerCase()??"en",this.setLocaleFromJsonString(a.i.syncGet("locale-phrases",""))}reset(){this.gmValues.forEach((t=>a.i.syncDelete(t)))}async update(t=!1){(t||2!==await a.i.get("locale-version",0,!0)||await a.i.get("locale-lang")!==this.lang)&&(i.Z.log("Updating locale..."),await fetch(`https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/src/localization/locales/${this.lang}.json`).then((t=>{if(200===t.status)return t.text();throw t.status})).then((async t=>{await a.i.set("locale-phrases",t),this.setLocaleFromJsonString(t);const e=this.getFromLocale(this.locale,"__version__");"number"==typeof e&&await a.i.set("locale-version",e),await a.i.set("locale-lang",this.lang)})).catch((async t=>{console.error("[VOT] [localizationProvider] failed get locale, cause:",t),this.setLocaleFromJsonString(await a.i.get("locale-phrases",""))})))}setLocaleFromJsonString(t){try{this.locale=JSON.parse(t)??{}}catch(t){console.error("[VOT] [localizationProvider]",t),this.locale={}}}getFromLocale(t,e){const o=e.split(".").reduce(((t,e)=>{if("object"==typeof t&&t)return t[e]}),t);return void 0===o&&console.warn("[VOT] [localizationProvider] locale",t,"doesn't contain key",e),o}getDefault(t){return this.getFromLocale(n,t)??t}get(t){return this.getFromLocale(this.locale,t)??this.getFromLocale(n,t)??t}}},"./src/utils/debug.js":(t,e,o)=>{"use strict";o.d(e,{Z:()=>n});const n={log:(...t)=>{}}},"./src/utils/storage.js":(t,e,o)=>{"use strict";o.d(e,{i:()=>i});var n=o("./src/utils/debug.js");const i=new class{constructor(){this.gmSupport="function"==typeof GM_getValue,n.Z.log(`GM Storage Status: ${this.gmSupport}`)}syncGet(t,e=void 0,o=!1){if(this.gmSupport)return GM_getValue(t,e);let n=window.localStorage.getItem(t);if("udemyData"===t&&"string"==typeof n)try{n=JSON.parse(n)}catch{n=e}return o?Number(n)??Number(e):n??e}async get(t,e=void 0,o=!1){return this.gmSupport?await GM_getValue(t,e):new Promise((n=>{n(this.syncGet(t,e,o))}))}syncSet(t,e){return this.gmSupport?GM_setValue(t,e):("udemyData"===t&&(e=JSON.stringify(e)),window.localStorage.setItem(t,e))}async set(t,e){return this.gmSupport?await GM_setValue(t,e):new Promise((o=>{o(this.syncSet(t,e))}))}syncDelete(t){return this.gmSupport?GM_deleteValue(t):window.localStorage.removeItem(t)}async delete(t){return this.gmSupport?await GM_deleteValue(t):new Promise((e=>{e(this.syncDelete(t))}))}syncList(){return this.gmSupport?GM_listValues():["autoTranslate","dontTranslateLanguage","dontTranslateYourLang","autoSetVolumeYandexStyle","showVideoSlider","syncVolume","subtitlesMaxLength","highlightWords","responseLanguage","defaultVolume","udemyData","audioProxy","showPiPButton","locale-version","locale-lang","locale-phrases"]}async list(){return this.gmSupport?await GM_listValues():new Promise((t=>{t(this.syncList())}))}}},"./src/utils/utils.js":(t,e,o)=>{"use strict";o.d(e,{KQ:()=>a,PG:()=>l,QZ:()=>u,_v:()=>r,eL:()=>d,gJ:()=>s,qq:()=>c});var n=o("./src/localization/localizationProvider.js");const i=navigator.language||navigator.userLanguage,a=i?.substr(0,2)?.toLowerCase()??"en";String.prototype.format||(String.prototype.format=function(){var t=arguments;return this.replace(/{(\d+)}/g,(function(e,o){return void 0!==t[o]?t[o]:e}))});const r=t=>new Promise((e=>setTimeout(e,t))),s=(t,e)=>{const o=new URL(window.location.href);switch(t){case"piped":case"invidious":case"youtube":return o.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1]||o.searchParams.get("v");case"vk":return o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)?o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1):o.searchParams.get("z")?o.searchParams.get("z").split("/")[0]:!(!o.searchParams.get("oid")||!o.searchParams.get("id"))&&`video-${Math.abs(o.searchParams.get("oid"))}_${o.searchParams.get("id")}`;case"nine_gag":case"9gag":case"gag":return o.pathname.match(/gag\/([^/]+)/)?.[1];case"twitch":if(/^m\.twitch\.tv$/.test(window.location.hostname)){const t=document.head.querySelector('link[rel="canonical"]');return t?.href.match(/videos\/([^/]+)/)?.[0]||o.pathname.slice(1)}if(/^player\.twitch\.tv$/.test(window.location.hostname))return`videos/${o.searchParams.get("video")}`;if(/^clips\.twitch\.tv$/.test(window.location.hostname)){const t=document.querySelector(".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']");return!!t&&`${t.href.replace("https://www.twitch.tv/","")}/clip/${o.searchParams.get("clip")}`}return o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)?o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]:o.pathname.match(/(?:videos)\/([^/]+)/)?.[0];case"proxytok":return o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];case"tiktok":{let t=o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];if(!t){const o=e.closest(".xgplayer-playing, .tiktok-web-player"),n=o?.closest('div[data-e2e="recommend-list-item-container"]'),i=n?.querySelector('a[data-e2e="video-author-avatar"]');if(o&&i){const e=o.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1),n=i.href?.match(/.*(@.*)$/)?.at(1);e&&n&&(t=`${n}/video/${e}`)}}return t}case"vimeo":return o.pathname.match(/[^/]+\/[^/]+$/)?.[0]||o.pathname.match(/[^/]+$/)?.[0];case"xvideos":return o.pathname.match(/[^/]+\/[^/]+$/)?.[0];case"pornhub":return o.searchParams.get("viewkey")||o.pathname.match(/embed\/([^/]+)/)?.[1];case"twitter":return o.pathname.match(/status\/([^/]+)/)?.[1];case"udemy":case"rumble":return o.pathname;case"facebook":return!!o.searchParams.get("v")&&o.searchParams.get("v");case"rutube":return o.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1];case"coub":return o.pathname.includes("/view")?o.pathname.match(/view\/([^/]+)/)?.[1]:o.pathname.includes("/embed")?o.pathname.match(/embed\/([^/]+)/)?.[1]:document.querySelector(".coub.active")?.dataset?.permalink;case"bilibili":{const t=o.searchParams.get("bvid");if(t)return t;{let t=o.pathname.match(/video\/([^/]+)/)?.[1];return t&&o.search&&null!==o.searchParams.get("p")&&(t+=`/?p=${o.searchParams.get("p")}`),t}}case"mail_ru":if(o.pathname.startsWith("/v/")||o.pathname.startsWith("/mail/"))return o.pathname;if(o.pathname.match(/video\/embed\/([^/]+)/)){const t=document.querySelector(".b-video-controls__mymail-link");return!!t&&t?.href.split("my.mail.ru")?.[1]}return!1;case"bitchute":return o.pathname.match(/video\/([^/]+)/)?.[1];case"coursera":return o.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0];case"eporner":return o.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0];case"peertube":return o.pathname.match(/\/w\/([^/]+)/)?.[0];case"dailymotion":{const t=Array.from(document.scripts).filter((t=>t.innerText.trim().includes("window.__PLAYER_CONFIG__ = {")));if(!t.length)return!1;try{let e=t[0].innerText.trim().replace("window.__PLAYER_CONFIG__ = ","");e.endsWith("};")&&(e=e.substring(0,e.length-1));const o=JSON.parse(e),n=o.context.embedder??o.context.http_referer;return console.log(n,o),n.match(/\/video\/([^/]+)/)?.[1]}catch(t){return console.error("[VOT]",t),!1}}case"trovo":{if(!o.pathname.startsWith("/s/"))return!1;const t=o.searchParams.get("vid");if(!t)return!1;const e=o.pathname.match(/([^/]+)\/([\d]+)/)?.[0];return!!e&&`${e}?vid=${t}`}case"yandexdisk":return o.pathname.match(/\/[i|s|d]\/([^/]+)/)?.[1];case"coursehunter":{const t=o.pathname.match(/\/course\/([^/]+)/)?.[1];return!!t&&t+o.search}default:return!1}};function l(t){const e=Math.floor(t/60),o=Math.floor(t%60);return e>=60?n.V.get("translationTakeMoreThanHour"):e>=10&&e%10?n.V.get("translationTakeApproximatelyMinutes").format(e):1==e||0==e&&o>0?n.V.get("translationTakeAboutMinute"):n.V.get("translationTakeApproximatelyMinute").format(e)}function d(t){return t.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]}function c(){return"pictureInPictureEnabled"in document&&document.pictureInPictureEnabled}function u(){return"undefined"!=typeof Hls&&Hls?.isSupported()?new Hls({debug:!1,lowLatencyMode:!0,backBufferLength:90}):void 0}},"./src/yandexRequest-cloudflare.js":(t,e,o)=>{"use strict";o.r(e),o.d(e,{default:()=>r});var n=o("./src/config/config.js"),i=o("./src/utils/debug.js"),a=o("./src/utils/storage.js");const r=async function(t,e,o,r){let s,l;try{i.Z.log("yandexRequest:",t);const r={method:"POST",mode:"cors",cache:"no-cache",headers:{"Content-Type":"application/json"},redirect:"follow",referrerPolicy:"no-referrer",body:JSON.stringify({headers:{Accept:"application/x-protobuf","Accept-Language":"en","Content-Type":"application/x-protobuf","User-Agent":n.Rr,Pragma:"no-cache","Cache-Control":"no-cache","Sec-Fetch-Mode":"no-cors",...o},body:Array.from(e)})},d=await a.i.get("proxyWorkerHost",n.ez);s=await fetch(`https://${d}${t}`,r),i.Z.log("yandexRequest:",s.status,s),l=await s.arrayBuffer()}catch(t){console.error("[VOT]",t),s={status:-1},l=t}r(200==s.status,l)}}},e={};function o(n){var i=e[n];if(void 0!==i)return i.exports;var a=e[n]={id:n,exports:{}};return t[n].call(a.exports,a,a.exports,o),a.exports}o.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return o.d(e,{a:e}),e},o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.nc=void 0,(()=>{"use strict";var t=o("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"),e=o.n(t),n=o("./node_modules/style-loader/dist/runtime/styleDomAPI.js"),i=o.n(n),a=o("./node_modules/style-loader/dist/runtime/insertBySelector.js"),r=o.n(a),s=o("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"),l=o.n(s),d=o("./node_modules/style-loader/dist/runtime/insertStyleElement.js"),c=o.n(d),u=o("./node_modules/style-loader/dist/runtime/styleTagTransform.js"),h=o.n(u),p=o("./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss"),g={};g.styleTagTransform=h(),g.setAttributes=l(),g.insert=r().bind(null,"head"),g.domAPI=i(),g.insertStyleElement=c(),e()(p.Z,g),p.Z&&p.Z.locals&&p.Z.locals;var v=o("./src/localization/localizationProvider.js");class m extends Error{constructor(t){super(v.V.getDefault(t)),this.name="VOTLocalizedError",this.unlocalizedMessage=t,this.localizedMessage=v.V.get(t)}}var b=o("./src/utils/debug.js");const f=["ru","en","zh","ko","lt","lv","ar","fr","it","es","de","ja"],y=["kk","bn","pt","cs","hi","mr","te","tr","ms","vi","ta","jv","ur","fa","gu","id","uk","da","fi","uz","pl","sv","az","sq","am","hy","af","eu","my","bg","bs","cy","hu","gl","el","zu","kn","ca","km","lo","mk","ml","mt","mn","ne","nl","pa","ro","sr","si","sk","sl","sw","su","hr","et"],w=["ru","en","kk"];var x=o("./src/utils/utils.js"),S=o("./src/config/config.js"),k=o("./src/utils/storage.js");async function T(t,e){const o=new AbortController,n=setTimeout((()=>o.abort()),3e3);try{return await fetch(t,{...e,signal:o.signal})}catch(t){return console.error("Fetch timed-out. Error:",t),t}finally{clearTimeout(n)}}const V={async translate(t,e){try{const o=await T(S.rm.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.text[0]}catch(e){return console.error("Error translating text:",e),t}},async detect(t,e){try{const o=await T(S.jm.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.lang??"en"}catch(t){return console.error("Error translating text:",t),"en"}}},M={async detect(t){try{const e=await fetch(S.jm.rustServer,{method:"POST",body:t});if(e instanceof Error)throw e;return await e.text()}catch(t){return console.error("Error getting lang from text:",t),"en"}}};async function L(t,e="",o="ru"){if("yandex"===await k.i.get("translationService",S.kF)){const n=e&&o?`${e}-${o}`:o;return await V.translate(t,n)}return t}const O=["yandex"],P=["yandex","rust-server"];function E(){return/^m\.youtube\.com$/.test(window.location.hostname)}function C(){return window.location.pathname.startsWith("/shorts/")?E()?document.querySelector("#movie_player"):document.querySelector("#shorts-player"):document.querySelector("#movie_player")}function A(){const t=C();return t?.getPlayerResponse?t?.getPlayerResponse?.call()??null:t?.data?.playerResponse??null}function B(){const t=C();return t?.getVideoData?t?.getVideoData?.call()??null:t?.data?.playerResponse?.videoDetails??null}const _=function(){const t=C();return t?.getVolume?t.getVolume.call()/100:1},F=function(){const t=A();let e=t?.captions?.playerCaptionsTracklistRenderer?.captionTracks??[];return e=e.reduce(((t,e)=>{if("languageCode"in e){const o=e?.languageCode?(0,x.eL)(e?.languageCode):void 0,n=e?.url||e?.baseUrl;o&&n&&t.push({source:"youtube",language:o,isAutoGenerated:"asr"===e?.kind,url:`${n.startsWith("http")?n:`${window.location.origin}/${n}`}&fmt=json3`})}return t}),[]),b.Z.log("youtube subtitles:",e),e},q=async function(){const t=C(),e=A(),o=B(),{author:n,title:i}=o??{},{shortDescription:a,isLive:r,isLiveContent:s,isUpcoming:l}=e?.videoDetails??{},d=!(!r&&!l||s);let c=await async function(t,e,o,n){if(!window.location.hostname.includes("m.youtube.com")&&t?.getAudioTrack){const e=t.getAudioTrack(),o=e?.getLanguageInfo();if("und"!==o?.id)return(0,x.eL)(o.id.split(".")[0])}const i=e?.captions?.playerCaptionsTracklistRenderer?.captionTracks;if(i?.length){const t=i.find((t=>"asr"===t.kind));if(t&&t.languageCode)return(0,x.eL)(t.languageCode)}if(!n||!o)return"en";const a=[/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g,/Auto-generated by YouTube/g,/Provided to YouTube by/g,/Released on/g,/Bitcoin/g,/USDT/g,/Paypal/g],r=[n.split("\n\n").filter((t=>!a.some((e=>e.test(t))))).join("\n\n").replace(/[^\p{L}\s]/gu," ").trim().replace(/\s+/g," ").slice(0,250),o].join(" ");return await async function(t){switch(await k.i.get("detectService",S.EY)){case"yandex":return await V.detect(t);case"rust-server":return await M.detect(t);default:return"en"}}(r)}(t,e,i,a);f.includes(c)||(c="en");const u={isLive:!!r,isPremiere:d,title:i,description:a,author:n,detectedLanguage:c};return b.Z.log("youtube video data:",u),console.log("[VOT] Detected language: ",u.detectedLanguage),u},z=function(t){const e=C();if(e?.setVolume)return e.setVolume(Math.round(100*t)),!0},R=function(t,e){b.Z.log("videoSeek",e);const o=(C()?.getProgressState()?.seekableEnd||t.currentTime)-e;t.currentTime=o},D=new protobuf.Type("VideoTranslationHelpObject").add(new protobuf.Field("target",1,"string")).add(new protobuf.Field("targetUrl",2,"string")),I=new protobuf.Type("VideoTranslationRequest").add(new protobuf.Field("url",3,"string")).add(new protobuf.Field("deviceId",4,"string")).add(new protobuf.Field("firstRequest",5,"bool")).add(new protobuf.Field("duration",6,"double")).add(new protobuf.Field("unknown2",7,"int32")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("unknown3",9,"int32")).add(new protobuf.Field("unknown4",10,"int32")).add(new protobuf.Field("translationHelp",11,"VideoTranslationHelpObject","repeated")).add(new protobuf.Field("responseLanguage",14,"string")).add(new protobuf.Field("unknown5",15,"int32")).add(new protobuf.Field("unknown6",16,"int32")).add(new protobuf.Field("unknown7",17,"int32")),j=new protobuf.Type("VideoSubtitlesRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")),N=new protobuf.Type("VideoStreamRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")).add(new protobuf.Field("responseLanguage",3,"string")),$=new protobuf.Type("VideoStreamPingRequest").add(new protobuf.Field("pingId",1,"int32")),H=new protobuf.Type("VideoTranslationResponse").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("duration",2,"double")).add(new protobuf.Field("status",4,"int32")).add(new protobuf.Field("remainingTime",5,"int32")).add(new protobuf.Field("unknown0",6,"int32")).add(new protobuf.Field("unknown1",7,"string")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("message",9,"string")),Z=new protobuf.Type("VideoSubtitlesObject").add(new protobuf.Field("language",1,"string")).add(new protobuf.Field("url",2,"string")).add(new protobuf.Field("unknown2",3,"int32")).add(new protobuf.Field("translatedLanguage",4,"string")).add(new protobuf.Field("translatedUrl",5,"string")).add(new protobuf.Field("unknown5",6,"int32")).add(new protobuf.Field("unknown6",7,"int32")),U=new protobuf.Type("VideoSubtitlesResponse").add(new protobuf.Field("unknown0",1,"int32")).add(new protobuf.Field("subtitles",2,"VideoSubtitlesObject","repeated")),W=new protobuf.Type("VideoStreamObject").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("timestamp",2,"int64")),G=new protobuf.Type("VideoStreamResponse").add(new protobuf.Field("interval",1,"int32")).add(new protobuf.Field("translatedInfo",2,"VideoStreamObject")).add(new protobuf.Field("pingId",3,"int32")),Y=(new protobuf.Root).define("yandex").add(D).add(I).add(H).add(j).add(Z).add(U).add($).add(N).add(W).add(G),K=(t,e,o,n,i)=>Y.VideoTranslationRequest.encode({url:t,firstRequest:!0,duration:e,unknown2:1,language:o,unknown3:0,unknown4:0,translationHelp:i,responseLanguage:n,unknown5:0,unknown6:1,unknown7:0}).finish(),Q=t=>Y.VideoTranslationResponse.decode(new Uint8Array(t)),J=(t,e)=>Y.VideoSubtitlesRequest.encode({url:t,language:e}).finish(),X=t=>Y.VideoSubtitlesResponse.decode(new Uint8Array(t)),tt=t=>Y.VideoStreamPingRequest.encode({pingId:t}).finish(),et=(t,e,o)=>Y.VideoStreamRequest.encode({url:t,language:e,responseLanguage:o}).finish(),ot=t=>Y.VideoStreamResponse.decode(new Uint8Array(t)),nt=["invidious.snopyta.org","yewtu.be","invidious.kavin.rocks","vid.puffyan.us","invidious.namazso.eu","inv.riverside.rocks","yt.artemislena.eu","invidious.flokinet.to","invidious.esmailelbob.xyz","y.com.sb","invidious.nerdvpn.de","inv.vern.cc","invidious.slipfox.xyz","invidio.xamh.de","invidious.dhusch.de"],it=["piped.video","piped.tokhmi.xyz","piped.moomoo.me","piped.syncpundit.io","piped.mha.fi","watch.whatever.social","piped.garudalinux.org","efy.piped.pages.dev","watch.leptons.xyz","piped.lunar.icu","yt.dc09.ru","piped.mint.lgbt","il.ax","piped.privacy.com.de","piped.esmailelbob.xyz","piped.projectsegfau.lt","piped.in.projectsegfau.lt","piped.us.projectsegfau.lt","piped.privacydev.net","piped.palveluntarjoaja.eu","piped.smnz.de","piped.adminforge.de","piped.qdi.fi","piped.hostux.net","piped.chauvet.pro","piped.jotoma.de","piped.pfcd.me","piped.frontendfriendly.xyz"];function at(t){const e=document.createElement("vot-block");return e.classList.add("vot-icon-button"),e.innerHTML=t,e}function rt(t){const e=parseFloat(t.value),o=""===t.min?0:parseFloat(t.min),n=(e-o)/((""===t.max?100:parseFloat(t.max))-o);t.parentElement.setAttribute("style",`--vot-progress: ${n}`)}function st(t,e="",o=" ",n=!1){const i=document.createElement("vot-block");i.classList.add("vot-textfield");const a=document.createElement(n?"textarea":"input");a.placeholder=o,a.value=e;const r=document.createElement("span");return r.innerHTML=t,i.appendChild(a),i.appendChild(r),{container:i,input:a,label:r}}function lt(t){const e=document.createElement("vot-block");e.classList.add("vot-dialog-container"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-dialog-backdrop");const n=document.createElement("vot-block");n.classList.add("vot-dialog");const i=document.createElement("vot-block");i.classList.add("vot-dialog-content-wrapper");const a=document.createElement("vot-block");a.classList.add("vot-dialog-header-container");const r=document.createElement("vot-block");r.classList.add("vot-dialog-body-container");const s=document.createElement("vot-block");s.classList.add("vot-dialog-footer-container");const l=document.createElement("vot-block");l.classList.add("vot-dialog-title-container");const d=at('');d.classList.add("vot-dialog-close-button"),o.onclick=d.onclick=()=>{e.hidden=!0};const c=document.createElement("vot-block");return c.classList.add("vot-dialog-title"),c.innerHTML=t,e.appendChild(o),e.appendChild(n),n.appendChild(i),i.appendChild(a),i.appendChild(r),i.appendChild(s),a.appendChild(l),a.appendChild(d),l.appendChild(c),{container:e,backdrop:o,dialog:n,contentWrapper:i,headerContainer:a,bodyContainer:r,footerContainer:s,titleContainer:l,closeButton:d,title:c}}function dt(t,e,o,n={}){const i=n.onSelectCb||function(){},a=n.labelElement||"";let r=[];const s=document.createElement("vot-block");s.classList.add("vot-select"),a&&s.appendChild(a);const l=document.createElement("vot-block");l.classList.add("vot-select-outer");const d=document.createElement("span");d.classList.add("vot-select-title"),d.innerText=t,void 0===t&&(d.innerText=o.find((t=>!0===t.selected))?.label);const c=document.createElement("vot-block");return c.classList.add("vot-select-arrow-icon"),c.innerHTML='',l.append(d,c),l.onclick=()=>{const t=lt(e);t.container.classList.add("vot-dialog-temp"),t.container.hidden=!1,document.documentElement.appendChild(t.container);const n=document.createElement("vot-block");n.classList.add("vot-select-content-list");for(const t of o){const e=document.createElement("vot-block");e.classList.add("vot-select-content-item"),e.innerText=t.label,e.dataset.votSelected=t.selected,e.dataset.votValue=t.value,t.disabled&&(e.inert=!0),e.onclick=async a=>{a.target.inert||(n.childNodes.forEach((t=>t.dataset.votSelected=!1)),o.forEach((e=>e.selected=e.value===t.value)),e.dataset.votSelected=!0,d.innerText=t.label,await i(a))},n.appendChild(e)}const a=st(v.V.get("searchField"));a.input.oninput=t=>{const e=t.target.value.toLowerCase();Array.from(r).forEach((t=>t.hidden=!t.innerText.toLowerCase().includes(e)))},t.bodyContainer.append(a.container,n),r=n.childNodes,t.backdrop.onclick=t.closeButton.onclick=()=>{t.container.remove(),r=[]}},s.append(l),{container:s,title:d,arrowIcon:c,labelElement:a,setTitle:t=>{d.innerText=t},setSelected:t=>{Array.from(r).filter((t=>!t.inert)).forEach((e=>e.dataset.votSelected=e.dataset.votValue===t)),o.forEach((e=>e.selected=String(e.value)===t))},updateItems:t=>{o=t}}}const ct={createHeader:function(t,e=4){const o=document.createElement("vot-block");return o.classList.add("vot-header"),o.classList.add(`vot-header-level-${e}`),o.innerHTML=t,o},createInformation:function(t,e){const o=document.createElement("vot-block");o.classList.add("vot-info");const n=document.createElement("vot-block");n.innerHTML=t;const i=document.createElement("vot-block");return i.innerHTML=e,o.appendChild(n),o.appendChild(i),{container:o,header:n,value:i}},createButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-button"),e.innerHTML=t,e},createTextButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-text-button"),e.innerHTML=t,e},createOutlinedButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-outlined-button"),e.innerHTML=t,e},createIconButton:at,createCheckbox:function(t,e=!1){const o=document.createElement("label");o.classList.add("vot-checkbox");const n=document.createElement("input");n.type="checkbox",n.checked=Boolean(e);const i=document.createElement("span");return i.innerHTML=t,o.appendChild(n),o.appendChild(i),{container:o,input:n,label:i}},createSlider:function(t,e=50,o=0,n=100){const i=document.createElement("vot-block");i.classList.add("vot-slider");const a=document.createElement("input");a.type="range",a.min=o,a.max=n,a.value=e;const r=document.createElement("span");return r.innerHTML=t,i.appendChild(a),i.appendChild(r),a.addEventListener("input",(t=>rt(t.target))),rt(a),{container:i,input:a,label:r}},createTextfield:st,createDialog:lt,createVOTButton:function(t){const e=document.createElement("vot-block");e.classList.add("vot-segmented-button");const o=document.createElement("vot-block");o.classList.add("vot-segment"),o.classList.add("vot-translate-button"),o.innerHTML='';const n=document.createElement("vot-block");n.classList.add("vot-separator");const i=document.createElement("vot-block");i.classList.add("vot-segment-only-icon"),i.innerHTML='';const a=document.createElement("vot-block");a.classList.add("vot-separator");const r=document.createElement("vot-block");r.classList.add("vot-segment-only-icon"),r.innerHTML='';const s=document.createElement("span");return s.classList.add("vot-segment-label"),s.innerHTML=t,e.appendChild(o),e.appendChild(n),e.appendChild(i),e.appendChild(a),e.appendChild(r),o.appendChild(s),{container:e,translateButton:o,separator:n,pipButton:i,separator2:a,menuButton:r,label:s}},createVOTMenu:function(t){const e=document.createElement("vot-block");e.classList.add("vot-menu"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-menu-content-wrapper");const n=document.createElement("vot-block");n.classList.add("vot-menu-header-container");const i=document.createElement("vot-block");i.classList.add("vot-menu-body-container");const a=document.createElement("vot-block");a.classList.add("vot-menu-footer-container");const r=document.createElement("vot-block");r.classList.add("vot-menu-title-container");const s=document.createElement("vot-block");return s.classList.add("vot-menu-title"),s.innerHTML=t,e.appendChild(o),o.appendChild(n),o.appendChild(i),o.appendChild(a),n.appendChild(r),r.appendChild(s),{container:e,contentWrapper:o,headerContainer:n,bodyContainer:i,footerContainer:a,titleContainer:r,title:s}},createVOTSelectLabel:function(t){const e=document.createElement("span");return e.classList.add("vot-select-label"),e.innerText=t,e},createVOTSelect:dt,createVOTLanguageSelect:function(t){const e=t.fromTitle||"#UNDEFINED",o=t.fromDialogTitle||"#UNDEFINED",n=t.fromItems||[],i=t.fromOnSelectCB||function(){},a=t.toTitle||"#UNDEFINED",r=t.toDialogTitle||"#UNDEFINED",s=t.toItems||[],l=t.toOnSelectCB||function(){},d=document.createElement("vot-block");d.classList.add("vot-lang-select");const c=dt(e,o,n,{onSelectCb:i}),u=document.createElement("vot-block");u.classList.add("vot-lang-select-icon"),u.innerHTML='';const h=dt(a,r,s,{onSelectCb:l});return d.append(c.container,u,h.container),{container:d,fromSelect:c,icon:u,toSelect:h}},updateSlider:rt};function ut(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}var ht=o("./node_modules/bowser/es5.js");function pt(t){const e=([1e7]+1e3+4e3+8e3+1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)));return t?e:e.toUpperCase()}async function gt(t){const e=new TextEncoder("utf-8"),o=await window.crypto.subtle.importKey("raw",e.encode(S.I1),{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign","verify"]),n=await window.crypto.subtle.sign("HMAC",o,t);return Array.from(new Uint8Array(n),(t=>t.toString(16).padStart(2,"0"))).join("")}function vt(t){const e=t.startMs+t.durationMs;return t.tokens.reduce(((o,n,i)=>{const a=t.tokens[i+1],r=o[o.length-1],s=r?.alignRange?.end??0,l=s+n.text.length;if(o.push(Object.assign(Object.assign({},n),{alignRange:{start:s,end:l}})),a){const t=n.startMs+n.durationMs,i=a.startMs?a.startMs-t:e-t;o.push({text:" ",startMs:t,durationMs:i,alignRange:{start:l,end:l+1}})}return o}),[])}function mt(t,e){const o=t.text.split(new RegExp("([\n \t])")).reduce(((t,o)=>{if(o.length){const n=t[t.length-1]??e,i=n?.alignRange?.end??0,a=i+o.length;t.push({text:o,alignRange:{start:i,end:a}})}return t}),[]),n=Math.floor(t.durationMs/o.length),i=t.startMs+t.durationMs;return o.map(((e,a)=>{const r=a===o.length-1,s=t.startMs+n*a,l=r?i-s:n;return Object.assign(Object.assign({},e),{startMs:s,durationMs:l})}))}class bt{dragging=!1;subtitlesContainerRect=null;containerRect=null;offsetX=null;offsetY=null;lastContent=null;highlightWords=!1;subtitles=null;maxLength=300;maxLengthRegexp=/.{1,300}(?:\s|$)/g;constructor(t,e,o){this.site=o,this.video=t,"youtube"===this.site.host&&"mobile"!==this.site.additionalData?this.container=e.parentElement:this.container=e,this.votSubtitlesContainer=document.createElement("vot-block"),this.votSubtitlesContainer.classList.add("vot-subtitles-widget"),this.container.appendChild(this.votSubtitlesContainer),this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onMouseMoveBound=this.onMouseMove.bind(this),this.onTimeUpdateBound=this.onTimeUpdate.bind(this),document.addEventListener("mousedown",this.onMouseDownBound),document.addEventListener("mouseup",this.onMouseUpBound),document.addEventListener("mousemove",this.onMouseMoveBound),this.video?.addEventListener("timeupdate",this.onTimeUpdateBound)}release(){this.video?.removeEventListener("timeupdate",this.onTimeUpdateBound),document.removeEventListener("mousedown",this.onMouseDownBound),document.removeEventListener("mouseup",this.onMouseUpBound),document.removeEventListener("mousemove",this.onMouseMoveBound),this.votSubtitlesContainer.remove()}onMouseDown(t){this.votSubtitlesContainer.contains(t.target)&&(this.subtitlesContainerRect=this.votSubtitlesContainer.getBoundingClientRect(),this.containerRect=this.container.getBoundingClientRect(),this.offsetX=t.clientX-this.subtitlesContainerRect.x,this.offsetY=t.clientY-this.subtitlesContainerRect.y,this.dragging=!0)}onMouseUp(){this.dragging=!1}onMouseMove(t){if(this.dragging){t.preventDefault();const e=t.clientX-this.offsetX,o=t.clientY-this.offsetY,n=o>=this.containerRect.top,i=o+this.subtitlesContainerRect.height<=this.containerRect.bottom,a=e>=this.containerRect.left,r=e+this.subtitlesContainerRect.width<=this.containerRect.right;this.votSubtitlesContainer.style.top=n&&i?o-this.containerRect.y+"px":n?this.containerRect.height-this.subtitlesContainerRect.height+"px":"0px",this.votSubtitlesContainer.style.left=a&&r?e-this.containerRect.x+"px":a?this.containerRect.width-this.subtitlesContainerRect.width+"px":"0px"}}onTimeUpdate(){this.update()}setContent(t){t&&this.video?(this.subtitles=t,this.update()):(this.subtitles=null,this.votSubtitlesContainer.innerHTML="")}setMaxLength(t){"number"==typeof t&&t&&(this.maxLength=t,this.maxLengthRegexp=new RegExp(`.{1,${t}}(?:\\s|$)`,"g"),this.update())}setHighlightWords(t){this.highlightWords!==!!t&&(this.highlightWords=!!t,this.update())}update(){if(!this.video)return;let t="",e=this.highlightWords&&this.subtitles?.containsTokens;const o=1e3*this.video.currentTime,n=this.subtitles?.subtitles?.findLast((t=>t.startMsthis.maxLength){let t=[],n=0,i=0,a=0;for(let o=0;othis.maxLength){let r=e.slice(n,i+1);r.at(0)&&" "===r.at(0).text&&(r=r.slice(1)),r.at(-1)&&" "===r.at(-1).text&&(r=r.slice(0,r.length-1)),t.push({startMs:e[n].startMs,durationMs:e[i].startMs+e[i].durationMs-e[n].startMs,tokens:r}),n=o,a=0}i=o}for(let n=0;ne||o>n.startMs-100&&e-o<275?'class="passed"':""}>${n.text}`}}else if(n.text.length>this.maxLength){let e=n.text.match(this.maxLengthRegexp),i=n.durationMs/e.length;for(let a=0;a${t.replace("\\n","
")}`:"")}}const ft=async function(){const t=window.course_id??document.querySelector('input[name="course_id"]')?.value,e=window.lessons??await async function(t){const e=await fetch(`https://coursehunter.net/api/v1/course/${t}/lessons`);return await e.json()}(t),o=parseInt(document.querySelector(".lessons-item_active")?.dataset?.index??1),n=e?.[o-1],{file:i,duration:a}=n;return b.Z.log("coursehunter course data:",e),{url:i,duration:a}};function yt(){return wt()?.player}function wt(){return document.querySelector(".vjs-v6")}const xt=async function(t="en"){let e=null;const o=yt(),{duration:n}=o?.cache_||{},{courseId:i,tracks:a,sources:r}=o?.options_||{},s=function(t){const e=t?.find((t=>"video/mp4"===t.type));return e?.src}(r),l=await async function(t){const e=await fetch(`https://www.coursera.org/api/onDemandCourses.v1/${t}`),o=await e.json();return o?.elements?.[0]}(i);let d=l?.primaryLanguageCodes?.[0];d=d?(0,x.eL)(d):"en",f.includes(d)||(d="en");const c=function(t,e,o){let n=t?.find((t=>(0,x.eL)(t.srclang)===e));return n||(n=t?.find((t=>(0,x.eL)(t.srclang)===o))||t?.[0]),n?.src}(a,d,t);console.log(`videoURL: ${s}, subtitlesURL: ${c}`),c&&s?e=[{target:"video_file_url",targetUrl:s},{target:"subtitles_file_url",targetUrl:`https://www.coursera.org${c}`}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${s}, subtitlesURL: ${c}`);const u={duration:n,detectedLanguage:d,translationHelp:e};return b.Z.log("coursera video data:",u),console.log("[VOT] Detected language: ",u.detectedLanguage),u},St="https://www.udemy.com/api-2.0";async function kt(t){const e=await fetch(`${St}/courses/${t}/?`+new URLSearchParams({"fields[course]":"locale",use_remote_version:"true",caching_intent:"true"}));return await e.json()}async function Tt(t,e,o){if(!(t.expires+2592e6>(new Date).getTime()&&t.accessToken))return void console.error(v.V.get("udemyAccessTokenExpired"));const n=`Bearer ${t.accessToken}`,i=await fetch(`${St}/users/me/subscribed-courses/${e}/lectures/${o}/?`+new URLSearchParams({"fields[lecture]":"asset","fields[asset]":"length,media_sources,captions"}),{headers:{"x-udemy-authorization":n,authorization:n}});return await i.json()}function Vt(){return Lt()?.player}function Mt(){const t=document.querySelector(".ud-app-loader[data-module-id='course-taking']")?.dataset?.moduleArgs;return t?JSON.parse(t):(console.error(v.V.get("udemyModuleArgsNotFound")),{})}function Lt(){return document.querySelector(".vjs-v7")}const Ot=async function(t,e="en"){let o=null;const n=Vt();b.Z.log("udemyData",t);const i=Mt();b.Z.log("moduleData: ",i);const a=i.courseId,r=window.location.pathname.match(/learn\/lecture\/([^/]+)/)?.[1];b.Z.log(`CourseId: ${a}, lectureId: ${r}`);const s=await kt(a);b.Z.log("courseLang Data:",s);const l=await Tt(t,a,r);console.log("lecture Data:",l);let d=s?.locale?.locale;d=d?(0,x.eL)(d):"en",f.includes(d)||(d="en");const c=l?.asset?.length||n?.cache_?.duration,u=function(t){const e=t?.find((t=>"video/webm"===t.type||"video/mp4"===t.type));return e?.src}(l?.asset?.media_sources)||function(){const t=Lt()?.querySelector("video")?.src;return!t?.startsWith("blob:")&&t}(),h=function(t,e,o){let n=t?.find((t=>(0,x.eL)(t.locale_id)===e));return n||(n=t?.find((t=>(0,x.eL)(t.locale_id)===o))||t?.[0]),n?.url}(l?.asset?.captions,d,e);console.log(`videoURL: ${u}, subtitlesURL: ${h}`),h&&u?o=[{target:"video_file_url",targetUrl:u},{target:"subtitles_file_url",targetUrl:h}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${u}, subtitlesURL: ${h}`);const p={duration:c,detectedLanguage:d,translationHelp:o};return b.Z.log("udemy video data:",p),console.log("[VOT] Detected language: ",p.detectedLanguage),p};o("./node_modules/requestidlecallback-polyfill/index.js");class Pt{constructor(){this.listeners=new Set}hasListener(t){return this.listeners.has(t)}dispatchToListener(t,...e){try{t(...e)}catch(t){console.error("[VOT]",t)}}addListener(t){if(this.hasListener(t))throw new Error("[VOT] The listener has already been added.");this.listeners.add(t)}removeListener(t){if(!this.hasListener(t))throw new Error("[VOT] The listener has not been added yet.");this.listeners.delete(t)}dispatch(...t){for(const e of Array.from(this.listeners))this.dispatchToListener(e,...t)}}function Et(t){return Array.from(t).map((t=>{const e=[];return t instanceof HTMLVideoElement&&e.push(t),t instanceof HTMLElement&&e.push(...Array.from(t.querySelectorAll("video"))),t?.shadowRoot?.querySelectorAll&&e.push(...Array.from(t.shadowRoot.querySelectorAll("video"))),e})).flat()}const Ct=[{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:"shorts-video #player"},{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:".player-container"},{host:"youtube",url:"https://youtu.be/",match:/^(www.)?youtube(-nocookie|kids)?.com$/,selector:".html5-video-container:not(#inline-player *)"},{host:"tiktok",url:"https://www.tiktok.com/",match:/^(www.)?tiktok.com$/,selector:null},{host:"proxytok",url:"https://www.tiktok.com/",match:["proxitok.pabloferreiro.es","proxitok.pussthecat.org","tok.habedieeh.re","proxitok.esmailelbob.xyz","proxitok.privacydev.net","tok.artemislena.eu","tok.adminforge.de","tik.hostux.net","tt.vern.cc","cringe.whatever.social","proxitok.lunar.icu","proxitok.privacy.com.de"],selector:".column.has-text-centered"},{additionalData:"mobile",host:"twitch",url:"https://twitch.tv/",match:/^m.twitch.tv$/,selector:"main > div > section > div > div > div"},{host:"twitch",url:"https://twitch.tv/",match:t=>t.host.includes("clips.twitch.tv")||t.host.includes("player.twitch.tv")&&null===t.searchParams.get("channel")||t.host.includes("twitch.tv")&&(t.pathname.startsWith("/videos")||t.pathname.startsWith("/embed")||t.pathname.includes("/clip")),selector:".video-ref"},{host:"xvideos",url:"https://www.xvideos.com/",match:/^www.xvideos.com$/,selector:".video-bg-pic"},{host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:/^[a-z]+.pornhub.com$/,selector:".mainPlayerDiv > .video-element-wrapper-js > div"},{additionalData:"embed",host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:t=>t.host.includes("pornhub.com")&&t.pathname.startsWith("/embed/"),selector:"#player"},{additionalData:"mobile",host:"vk",url:"https://vk.com/video?z=",match:/^m.vk.(com|ru)$/,selector:"vk-video-player",shadowRoot:!0},{host:"vk",url:"https://vk.com/video?z=",match:/^(www.|m.)?vk.(com|ru)$/,selector:".videoplayer_media"},{host:"vimeo",url:"https://vimeo.com/",match:/^(player.)?vimeo.com$/,selector:".player"},{host:"nine_gag",url:"https://9gag.com/gag/",match:/^9gag.com$/,selector:".video-post"},{host:"coub",url:"https://coub.com/view/",match:/^coub.com$/,selector:".viewer__player"},{host:"bitchute",url:"https://www.bitchute.com/video/",match:/^(www.)?bitchute.com$/,selector:".plyr__video-wrapper"},{host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:".video-player > div > div > div:nth-child(2)"},{additionalData:"embed",host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:"#app > div > div"},{host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m|player).bilibili.com$/,selector:".bpx-player-video-wrap"},{additionalData:"old",host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m).bilibili.com$/,selector:null},{host:"twitter",url:"https://twitter.com/i/status/",match:/^twitter.com$/,selector:'div[data-testid="videoComponent"] > div:nth-child(1) > div'},{host:"mail_ru",url:"https://my.mail.ru/",match:/^my.mail.ru$/,selector:"#b-video-wrapper"},{host:"coursera",url:"https://www.coursera.org/",match:/coursera.org$/,selector:".vjs-v6"},{host:"udemy",url:"https://www.udemy.com",match:/udemy.com$/,selector:'div[data-purpose="curriculum-item-viewer-content"] > section > div > div > div > div:nth-of-type(2)'},{host:"invidious",url:"https://youtu.be/",match:nt,selector:"#player"},{host:"piped",url:"https://youtu.be/",match:it,selector:".shaka-video-container"},{host:"rumble",url:"https://rumble.com",match:/^rumble.com$/,selector:"#videoPlayer > .videoPlayer-Rumble-cls > div"},{host:"eporner",url:"https://www.eporner.com/",match:/^(www.)?eporner.com$/,selector:".vjs-v7"},{host:"peertube",url:"tube.shanti.cafe",match:["peertube.1312.media","tube.shanti.cafe","bee-tube.fr","video.sadmin.io","dalek.zone","review.peertube.biz","peervideo.club","tube.la-dina.net","peertube.tmp.rcp.tf"],selector:".vjs-v7"},{host:"dailymotion",url:"https://www.dailymotion.com/video/",match:/^geo.dailymotion.com$/,selector:".player"},{host:"trovo",url:"https://trovo.live/s/",match:/^trovo.live$/,selector:".player-video"},{host:"yandexdisk",url:"https://disk.yandex.ru/i/",match:/^disk.yandex.ru$/,selector:"yaplayertag > div:nth-of-type(1)"},{host:"coursehunter",url:"https://coursehunter.net/course/",match:/^coursehunter.net$/,selector:"#oframeplayer > pjsdiv:nth-of-type(1)"}],At=ht.getParser(window.navigator.userAgent).getResult(),Bt=[...nt,...it],_t=["playing","ratechange","play","waiting","pause"];function Ft(t,e,o=!1){return t.map((t=>({label:`${o&&!w.includes(t)?"❌ ":""}${v.V.get("langs")[t]??t.toUpperCase()}`,value:t,selected:e===t})))}var qt=!1;class zt{translateFromLang="en";translateToLang=x.KQ;timer;ytData="";videoData="";firstPlay=!0;audio=new Audio;hls=(0,x.QZ)();downloadTranslationUrl=null;downloadSubtitlesUrl=null;autoRetry;streamPing;volumeOnStart;tempOriginalVolume;tempVolume;subtitlesList=[];subtitlesListVideoId=null;videoLastSrcObject=null;constructor(t,e,o){b.Z.log("[VideoHandler] add video:",t,"container:",e,this),this.video=t,this.container=e,this.site=o,this.handleSrcChangedBound=this.handleSrcChanged.bind(this),this.srcObserver=new MutationObserver(this.handleSrcChangedBound),this.srcObserver.observe(this.video,{attributeFilter:["src","currentSrc"]}),this.srcObjectInterval=setInterval((async()=>{this.videoLastSrcObject!==this.video.srcObject&&(this.videoLastSrcObject=this.video.srcObject,await this.handleSrcChanged())}),100),this.stopTranslationBound=this.stopTranslation.bind(this),this.handleVideoEventBound=this.handleVideoEvent.bind(this),this.changeOpacityOnEventBound=this.changeOpacityOnEvent.bind(this),this.resetTimerBound=this.resetTimer.bind(this),this.init()}async init(){if(this.initialized)return;this.data={autoTranslate:await k.i.get("autoTranslate",0,!0),dontTranslateLanguage:await k.i.get("dontTranslateLanguage",x.KQ),dontTranslateYourLang:await k.i.get("dontTranslateYourLang",1,!0),autoSetVolumeYandexStyle:await k.i.get("autoSetVolumeYandexStyle",1,!0),autoVolume:await k.i.get("autoVolume",S.sN,!0)/100,showVideoSlider:await k.i.get("showVideoSlider",1,!0),syncVolume:await k.i.get("syncVolume",0,!0),subtitlesMaxLength:await k.i.get("subtitlesMaxLength",300,!0),highlightWords:await k.i.get("highlightWords",0,!0),responseLanguage:await k.i.get("responseLanguage",x.KQ),defaultVolume:await k.i.get("defaultVolume",100,!0),udemyData:await k.i.get("udemyData",{accessToken:"",expires:0}),audioProxy:await k.i.get("audioProxy","uk"===x.KQ?1:0,!0),showPiPButton:await k.i.get("showPiPButton",0,!0),translateAPIErrors:await k.i.get("translateAPIErrors",1,!0),translationService:await k.i.get("translationService",S.kF),detectService:await k.i.get("detectService",S.EY),m3u8ProxyHost:await k.i.get("m3u8ProxyHost",S.e6),proxyWorkerHost:await k.i.get("proxyWorkerHost",S.ez)},this.videoData=await this.getVideoData(),console.log("[db] data from db: ",this.data),this.subtitlesWidget=new bt(this.video,this.container,this.site),this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength),this.subtitlesWidget.setHighlightWords(this.data.highlightWords),this.initUI(),this.initUIEvents();const t=!this.video.src&&!this.video.currentSrc&&!this.video.srcObject;this.votButton.container.hidden=t,t&&(this.votMenu.container.hidden=t),await this.updateSubtitles(),await this.changeSubtitlesLang("disabled"),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage??"ru"),this.translateToLang=this.data.responseLanguage??"ru",this.initExtraEvents(),this.initialized=!0}transformBtn(t="none",e){this.votButton.container.dataset.status=t,this.votButton.label.innerHTML=e}initUI(){this.votButton=ct.createVOTButton(v.V.get("translateVideo")),this.container.appendChild(this.votButton.container),this.votButton.pipButton.hidden=!(0,x.qq)()||!this.data?.showPiPButton,this.votButton.separator2.hidden=!(0,x.qq)()||!this.data?.showPiPButton,this.votButton.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votMenu=ct.createVOTMenu(v.V.get("VOTSettings")),this.container.appendChild(this.votMenu.container),this.votDownloadButton=ct.createIconButton(''),this.votDownloadButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadButton),this.votDownloadSubtitlesButton=ct.createIconButton(''),this.votDownloadSubtitlesButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadSubtitlesButton),this.votSettingsButton=ct.createIconButton(''),this.votMenu.headerContainer.appendChild(this.votSettingsButton),this.votTranslationLanguageSelect=ct.createVOTLanguageSelect({fromTitle:v.V.get("langs")[this.video.detectedLanguage],fromDialogTitle:v.V.get("videoLanguage"),fromItems:[{label:v.V.get("langs").auto,value:"auto",selected:""},...Ft(f,this.videoData.detectedLanguage)],fromOnSelectCB:async t=>{b.Z.log("[fromOnSelectCB] select from language",t.target.dataset.votValue),this.videoData=await this.getVideoData(),this.setSelectMenuValues(t.target.dataset.votValue,this.videoData.responseLanguage)},toTitle:v.V.get("langs")[this.video.responseLanguage],toDialogTitle:v.V.get("translationLanguage"),toItems:[...Ft(f,this.videoData.responseLanguage,!0),{label:"─────────",value:"separator",disabled:!0},...Ft(y,this.videoData.responseLanguage,!0)],toOnSelectCB:async t=>{const e=t.target.dataset.votValue;b.Z.log("[toOnSelectCB] select to language",e),this.data.responseLanguage=this.translateToLang=e,await k.i.set("responseLanguage",this.data.responseLanguage),b.Z.log("Response Language value changed. New value: ",this.data.responseLanguage),this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage)}}),this.votMenu.bodyContainer.appendChild(this.votTranslationLanguageSelect.container),this.votSubtitlesSelect=ct.createVOTSelect(v.V.get("VOTSubtitlesDisabled"),v.V.get("VOTSubtitles"),[{label:v.V.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1}],{onSelectCb:async t=>{await this.changeSubtitlesLang(t.target.dataset.votValue)},labelElement:ct.createVOTSelectLabel(v.V.get("VOTSubtitles"))}),this.votMenu.bodyContainer.appendChild(this.votSubtitlesSelect.container),this.votVideoVolumeSlider=ct.createSlider(`${v.V.get("VOTVolume")}: ${100*this.getVideoVolume()}%`,100*this.getVideoVolume()),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoVolumeSlider.container),this.votVideoTranslationVolumeSlider=ct.createSlider(`${v.V.get("VOTVolumeTranslation")}: ${this.data?.defaultVolume??100}%`,this.data?.defaultVolume??100),this.votVideoTranslationVolumeSlider.container.hidden="success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoTranslationVolumeSlider.container),this.votMenu.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votSettingsDialog=ct.createDialog(v.V.get("VOTSettings")),document.documentElement.appendChild(this.votSettingsDialog.container),this.votTranslationHeader=ct.createHeader(v.V.get("translationSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationHeader),this.votAutoTranslateCheckbox=ct.createCheckbox(v.V.get("VOTAutoTranslate"),this.data?.autoTranslate??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoTranslateCheckbox.container),this.votDontTranslateYourLangSelect=ct.createVOTSelect(v.V.get("langs")[k.i.syncGet("dontTranslateLanguage",x.KQ)],v.V.get("VOTDontTranslateYourLang"),Ft(f,k.i.syncGet("dontTranslateLanguage",x.KQ)),{onSelectCb:async t=>{this.data.dontTranslateLanguage=t.target.dataset.votValue,await k.i.set("dontTranslateLanguage",this.data.dontTranslateLanguage)},labelElement:ct.createCheckbox(v.V.get("VOTDontTranslateYourLang"),this.data?.dontTranslateYourLang??!0).container}),this.votSettingsDialog.bodyContainer.appendChild(this.votDontTranslateYourLangSelect.container),this.votAutoSetVolumeCheckbox=ct.createCheckbox(`${v.V.get("VOTAutoSetVolume")}`,this.data?.autoSetVolumeYandexStyle??!0),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeCheckbox.container),this.votAutoSetVolumeSlider=ct.createSlider(`${100*(this.data?.autoVolume??S.sN)}%`,100*(this.data?.autoVolume??S.sN),0,100),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeSlider.container),this.votShowVideoSliderCheckbox=ct.createCheckbox(v.V.get("VOTShowVideoSlider"),this.data?.showVideoSlider??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votShowVideoSliderCheckbox.container),this.votUdemyDataTextfield=ct.createTextfield(v.V.get("VOTUdemyData"),this.data?.udemyData?.accessToken??""),this.votUdemyDataTextfield.container.hidden="udemy"!==this.site.host,this.votSettingsDialog.bodyContainer.appendChild(this.votUdemyDataTextfield.container),this.votSyncVolumeCheckbox=ct.createCheckbox(v.V.get("VOTSyncVolume"),this.data?.syncVolume??!1),this.votSyncVolumeCheckbox.container.hidden="youtube"!==this.site.host||"mobile"===this.site.additionalData,this.votSettingsDialog.bodyContainer.appendChild(this.votSyncVolumeCheckbox.container),this.votTranslationServiceSelect=ct.createVOTSelect(k.i.syncGet("translationService",S.kF),v.V.get("VOTTranslationService"),Ft(O,k.i.syncGet("translationService",S.kF)),{onSelectCb:async t=>{this.data.translationService=t.target.dataset.votValue,await k.i.set("translationService",this.data.translationService)},labelElement:ct.createCheckbox(v.V.get("VOTTranslateAPIErrors"),this.data.translateAPIErrors??!0).container}),this.votTranslationServiceSelect.container.hidden="ru"===v.V.lang,this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationServiceSelect.container),this.votDetectServiceSelect=ct.createVOTSelect(k.i.syncGet("detectService",S.EY),v.V.get("VOTDetectService"),Ft(P,k.i.syncGet("detectService",S.EY)),{onSelectCb:async t=>{this.data.detectService=t.target.dataset.votValue,await k.i.set("detectService",this.data.detectService)},labelElement:ct.createVOTSelectLabel(v.V.get("VOTDetectService"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votDetectServiceSelect.container),this.votSubtitlesHeader=ct.createHeader(v.V.get("subtitlesSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader),this.votSubtitlesMaxLengthSlider=ct.createSlider(`${v.V.get("VOTSubtitlesMaxLength")}: ${this.data?.subtitlesMaxLength??300}`,this.data?.subtitlesMaxLength??300,50,300),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesMaxLengthSlider.container),this.votSubtitlesHighlightWordsCheckbox=ct.createCheckbox(v.V.get("VOTHighlightWords"),this.data?.highlightWords??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHighlightWordsCheckbox.container),this.votProxyHeader=ct.createHeader(v.V.get("proxySettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader),this.votM3u8ProxyHostTextfield=ct.createTextfield(v.V.get("VOTM3u8ProxyHost"),this.data?.m3u8ProxyHost,S.e6),this.votSettingsDialog.bodyContainer.appendChild(this.votM3u8ProxyHostTextfield.container),this.votProxyWorkerHostTextfield=ct.createTextfield(v.V.get("VOTProxyWorkerHost"),this.data?.proxyWorkerHost,S.ez),this.votProxyWorkerHostTextfield.container.hidden=!1,this.votSettingsDialog.bodyContainer.appendChild(this.votProxyWorkerHostTextfield.container),this.votAudioProxyCheckbox=ct.createCheckbox(v.V.get("VOTAudioProxy"),this.data?.audioProxy??!1),this.votAudioProxyCheckbox.container.hidden=!1,this.votSettingsDialog.bodyContainer.appendChild(this.votAudioProxyCheckbox.container),this.votAboutHeader=ct.createHeader(v.V.get("about")),this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader),this.votLanguageSelect=ct.createVOTSelect(v.V.get("langs")[k.i.syncGet("locale-lang-override","auto")],v.V.get("VOTMenuLanguage"),Ft(v.Z,k.i.syncGet("locale-lang-override","auto")),{onSelectCb:async t=>{await k.i.set("locale-lang-override",t.target.dataset.votValue)},labelElement:ct.createVOTSelectLabel(v.V.get("VOTMenuLanguage"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votLanguageSelect.container),this.votShowPiPButtonCheckbox=ct.createCheckbox(v.V.get("VOTShowPiPButton"),this.data?.showPiPButton??!1),this.votShowPiPButtonCheckbox.container.hidden=!(0,x.qq)(),this.votSettingsDialog.bodyContainer.appendChild(this.votShowPiPButtonCheckbox.container),this.votVersionInfo=ct.createInformation(`${v.V.get("VOTVersion")}:`,`cloudflare ${GM_info.script.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votVersionInfo.container),this.votAuthorsInfo=ct.createInformation(`${v.V.get("VOTAuthors")}:`,GM_info.script.author),this.votSettingsDialog.bodyContainer.appendChild(this.votAuthorsInfo.container),this.votLoaderInfo=ct.createInformation(`${v.V.get("VOTLoader")}:`,`${GM_info.scriptHandler} v${GM_info.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votLoaderInfo.container),this.votBrowserInfo=ct.createInformation(`${v.V.get("VOTBrowser")}:`,`${At.browser.name} ${At.browser.version} (${At.os.name} ${At.os.version})`),this.votSettingsDialog.bodyContainer.appendChild(this.votBrowserInfo.container),this.votResetSettingsButton=ct.createButton(v.V.get("resetSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votResetSettingsButton)}initUIEvents(){this.votButton.translateButton.addEventListener("click",(async()=>{if(this.audio.src)return b.Z.log("[click translationBtn] audio.src is not empty"),void this.stopTraslate();try{b.Z.log("[click translationBtn] trying execute translation");const t=(0,x.gJ)(this.site.host,this.video);if(!t)throw new m("VOTNoVideoIDFound");await this.translateExecutor(t)}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.votDownloadButton.addEventListener("click",(()=>{this.downloadTranslationUrl&&window.open(this.downloadTranslationUrl,"_blank").focus()})),this.votDownloadSubtitlesButton.addEventListener("click",(()=>{console.log(this.downloadSubtitlesUrl),this.downloadSubtitlesUrl&&window.open(this.downloadSubtitlesUrl,"_blank").focus()})),this.votSettingsButton.addEventListener("click",(()=>{this.votSettingsDialog.container.hidden=!this.votSettingsDialog.container.hidden,(void 0===document.fullscreen||document.fullscreen)&&(document.webkitExitFullscreen&&document.webkitExitFullscreen(),document.mozCancelFullscreen&&document.mozCancelFullscreen(),document.exitFullscreen&&document.exitFullscreen())})),this.votVideoVolumeSlider.input.addEventListener("input",(t=>{const e=Number(t.target.value);if(this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`,this.setVideoVolume(e/100),1===this.data.syncVolume){const t=Number(this.votVideoTranslationVolumeSlider.input.value),o=ut(this.audio,e,t,this.tempOriginalVolume);this.votVideoTranslationVolumeSlider.input.value=o,this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,ct.updateSlider(this.votVideoTranslationVolumeSlider.input),this.tempVolume=o,this.tempOriginalVolume=e}})),this.votVideoTranslationVolumeSlider.input.addEventListener("input",(async t=>{this.data.defaultVolume=Number(t.target.value),await k.i.set("defaultVolume",this.data.defaultVolume),this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${this.data.defaultVolume}%`,this.audio.volume=this.data.defaultVolume/100,1===this.data.syncVolume&&this.syncTranslationWithVideo(this.data.defaultVolume)})),this.votAutoTranslateCheckbox.input.addEventListener("change",(async t=>{this.data.autoTranslate=Number(t.target.checked),await k.i.set("autoTranslate",this.data.autoTranslate),b.Z.log("autoTranslate value changed. New value: ",this.data.autoTranslate)})),this.votDontTranslateYourLangSelect.labelElement.addEventListener("change",(async t=>{this.data.dontTranslateYourLang=Number(t.target.checked),await k.i.set("dontTranslateYourLang",this.data.dontTranslateYourLang),b.Z.log("dontTranslateYourLang value changed. New value: ",this.data.dontTranslateYourLang)})),this.votAutoSetVolumeCheckbox.input.addEventListener("change",(async t=>{this.data.autoSetVolumeYandexStyle=Number(t.target.checked),await k.i.set("autoSetVolumeYandexStyle",this.data.autoSetVolumeYandexStyle),b.Z.log("autoSetVolumeYandexStyle value changed. New value: ",this.data.autoSetVolumeYandexStyle)})),this.votAutoSetVolumeSlider.input.addEventListener("input",(async t=>{const e=Number(t.target.value);this.data.autoVolume=e/100,await k.i.set("autoVolume",e),this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`})),this.votShowVideoSliderCheckbox.input.addEventListener("change",(async t=>{this.data.showVideoSlider=Number(t.target.checked),await k.i.set("showVideoSlider",this.data.showVideoSlider),b.Z.log("showVideoSlider value changed. New value: ",this.data.showVideoSlider),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status})),this.votUdemyDataTextfield.input.addEventListener("change",(async t=>{this.data.udemyData={accessToken:t.target.value,expires:(new Date).getTime()},await k.i.set("udemyData",this.data.udemyData),b.Z.log("udemyData value changed. New value: ",this.data.udemyData),window.location.reload()})),this.votSyncVolumeCheckbox.input.addEventListener("change",(async t=>{this.data.syncVolume=Number(t.target.checked),await k.i.set("syncVolume",this.data.syncVolume),b.Z.log("syncVolume value changed. New value: ",this.data.syncVolume)})),this.votTranslationServiceSelect.labelElement.addEventListener("change",(async t=>{this.data.translateAPIErrors=Number(t.target.checked),await k.i.set("translateAPIErrors",this.data.translateAPIErrors),b.Z.log("translateAPIErrors value changed. New value: ",this.data.translateAPIErrors)})),this.votSubtitlesMaxLengthSlider.input.addEventListener("input",(async t=>{this.data.subtitlesMaxLength=Number(t.target.value),await k.i.set("subtitlesMaxLength",this.data.subtitlesMaxLength),this.votSubtitlesMaxLengthSlider.label.querySelector("strong").innerHTML=`${this.data.subtitlesMaxLength}`,this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength)})),this.votSubtitlesHighlightWordsCheckbox.input.addEventListener("change",(async t=>{this.data.highlightWords=Number(t.target.checked),await k.i.set("highlightWords",this.data.highlightWords),b.Z.log("highlightWords value changed. New value: ",this.data.highlightWords),this.subtitlesWidget.setHighlightWords(this.data.highlightWords)})),this.votShowPiPButtonCheckbox.input.addEventListener("change",(async t=>{this.data.showPiPButton=Number(t.target.checked),await k.i.set("showPiPButton",this.data.showPiPButton),b.Z.log("showPiPButton value changed. New value: ",this.data.showPiPButton),this.votButton.pipButton.hidden=!(0,x.qq)()||!this.data.showPiPButton,this.votButton.separator2.hidden=!(0,x.qq)()||!this.data.showPiPButton})),this.votM3u8ProxyHostTextfield.input.addEventListener("change",(async t=>{this.data.m3u8ProxyHost=t.target.value||S.e6,await k.i.set("m3u8ProxyHost",this.data.m3u8ProxyHost),b.Z.log("m3u8ProxyHost value changed. New value: ",this.data.m3u8ProxyHost)})),this.votProxyWorkerHostTextfield.input.addEventListener("change",(async t=>{this.data.proxyWorkerHost=t.target.value||S.ez,await k.i.set("proxyWorkerHost",this.data.proxyWorkerHost),b.Z.log("proxyWorkerHost value changed. New value: ",this.data.proxyWorkerHost),window.location.reload()})),this.votAudioProxyCheckbox.input.addEventListener("change",(async t=>{this.data.audioProxy=Number(t.target.checked),await k.i.set("audioProxy",this.data.audioProxy),b.Z.log("audioProxy value changed. New value: ",this.data.audioProxy)})),this.votResetSettingsButton.addEventListener("click",(async()=>{v.V.reset(),(await k.i.list()).filter((t=>!v.V.gmValues.includes(t))).forEach((t=>k.i.syncDelete(t))),window.location.reload()}))}releaseExtraEvents(){clearInterval(this.resizeInterval),this.resizeObserver?.disconnect(),"youtube"===this.site.host&&"mobile"!==this.site.additionalData&&this.syncVolumeObserver?.disconnect(),this.extraEvents?.forEach((t=>{t.element.removeEventListener(t.event,t.handler)}))}initExtraEvents(){this.extraEvents=[];const t=(t,e,o)=>{this.extraEvents.push({element:t,event:e,handler:o}),t.addEventListener(e,o)},e=(e,o,n)=>{o.forEach((o=>{t(e,o,n)}))};if(this.resizeObserver=new ResizeObserver((t=>{t.forEach((t=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${t.contentRect.height}px`)}))})),this.resizeObserver.observe(this.video),this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`),this.resizeInterval=setInterval((()=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`)}),500),"youtube"===this.site.host&&"mobile"!==this.site.additionalData){this.syncVolumeObserver=new MutationObserver((t=>{t.forEach((t=>{"attributes"===t.type&&"aria-valuenow"===t.attributeName&&this.syncVideoVolumeSlider()}))}));const t=document.querySelector(".ytp-volume-panel");t&&this.syncVolumeObserver.observe(t,{attributes:!0,childList:!1,subtree:!0,attributeOldValue:!0})}let o;document.addEventListener("click",(t=>{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),c=a.contains(e),u=r?.contains(e)??!1;b.Z.log(`[document click] ${s} ${l} ${d} ${c} ${u}`),s||l||c||u||(d||this.logout(0),this.votMenu.container.hidden=!0)})),o="pornhub"===this.site.host?"embed"===this.site.additionalData?document.querySelector("#player"):this.container.querySelector(".video-element-wrapper-js > div"):"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),t(this.video,"abort",(()=>{b.Z.log("lipsync mode is abort"),this.stopTranslation(),this.videoData=""})),t(this.video,"progress",(async()=>{if(!this.firstPlay||1!==this.data.autoTranslate)return;const t=(0,x.gJ)(this.site.host,this.video);if(!t)throw new m("VOTNoVideoIDFound");try{await this.translateExecutor(t),this.firstPlay=!1}catch(t){console.error("[VOT]",t),"VOTLocalizedError"===t?.name?this.transformBtn("error",t.localizedMessage):this.transformBtn("error",t),this.firstPlay=!1}}))}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)}),2e3)}changeOpacityOnEvent(t){clearTimeout(this.timer),this.logout(1),t.stopPropagation()}async changeSubtitlesLang(t){if(b.Z.log("[onchange] subtitles",t),this.votSubtitlesSelect.setSelected(t),"disabled"===t)this.votSubtitlesSelect.setTitle(v.V.get("VOTSubtitlesDisabled")),this.subtitlesWidget.setContent(null),this.votDownloadSubtitlesButton.hidden=!0,this.downloadSubtitlesUrl=null;else{const e=await async function(t){let e=!1,o=await Promise.race([new Promise((async t=>{await(0,x._v)(5e3),e||console.error("[VOT] Failed to fetch subtitles. Reason: timeout"),e=!0,t([])})),new Promise((async o=>{b.Z.log("Fetching subtitles:",t),await fetch(t.url).then((t=>t.json())).then((t=>{e=!0,o(t)})).catch((t=>{console.error("[VOT] Failed to fetch subtitles. Reason:",t),e=!0,o({containsTokens:!1,subtitles:[]})}))}))]);return"youtube"===t.source&&(o=function(t){const e={containsTokens:!1,subtitles:[]};if("object"!=typeof t||!("events"in t)||!Array.isArray(t.events))return console.error("[VOT] Failed to format youtube subtitles",t),e;for(let o=0;ot.utf8.replace(/^ +| +$/g,""))).join(" ");let i=t.events[o].dDurationMs;t.events[o+1]&&t.events[o].tStartMs+t.events[o].dDurationMs>t.events[o+1].tStartMs&&(i=t.events[o+1].tStartMs-t.events[o].tStartMs),"\n"!==n&&e.subtitles.push({text:n,startMs:t.events[o].tStartMs,durationMs:i})}return e}(o)),o.subtitles=function(t,e){const o=[];let n;for(const i of t.subtitles){let a;if(i?.tokens?.length){if("yandex"!==e)return console.warn("[VOT] Unsupported subtitles tokens type: ",e),t.containsTokens=!1,null;a=vt(i)}else a=mt(i,n);n=a[a.length-1],o.push(Object.assign(Object.assign({},i),{tokens:a}))}return t.containsTokens=!0,o}(o,t.source),console.log("[VOT] subtitles:",o),o}(this.subtitlesList.at(parseInt(t)));this.subtitlesWidget.setContent(e),this.votDownloadSubtitlesButton.hidden=!1,this.downloadSubtitlesUrl=this.subtitlesList.at(parseInt(t))?.url}}async updateSubtitlesLangSelect(){const t=[{label:v.V.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1},...this.subtitlesList.map(((t,e)=>({label:(v.V.get("langs")[t.language]??t.language.toUpperCase())+(t.translatedFromLanguage?` ${v.V.get("VOTTranslatedFrom")} ${v.V.get("langs")[t.translatedFromLanguage]??t.translatedFromLanguage.toUpperCase()}`:"")+("yandex"!==t.source?` ${t.source}`:"")+(t.isAutoGenerated?` (${v.V.get("VOTAutogenerated")})`:""),value:e,selected:!1,disabled:!1})))];this.votSubtitlesSelect.updateItems(t),await this.changeSubtitlesLang(t[0].value)}async updateSubtitles(){await this.changeSubtitlesLang("disabled");const t=(0,x.gJ)(this.site.host,this.video);if(!t)return console.error(`[VOT] ${v.V.getDefault("VOTNoVideoIDFound")}`),this.subtitlesList=[],this.subtitlesListVideoId=null,void await this.updateSubtitlesLangSelect();this.subtitlesListVideoId!==t&&(this.videoData.detectedLanguage||(this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage)),this.subtitlesList=await async function(t,e,n){const i="youtube"===t.host?F():[];let a=!1;const r=[...await Promise.race([new Promise((async t=>{await(0,x._v)(5e3),a||console.error("[VOT] Failed get yandex subtitles. Reason: timeout"),a=!0,t([])})),new Promise((i=>{!async function(t,e,n){try{b.Z.log("requestVideoSubtitles");const i=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;b.Z.log("Inited yandexRequest...");const a=J(t,e);await i("/video-subtitles/get-subtitles",a,{"Vsubs-Signature":await gt(a),"Sec-Vsubs-Token":pt(!1)},n)}catch(t){console.error("[VOT]",t),n(!1)}}(`${t.url}${e}`,n,((t,e)=>{b.Z.log("[exec callback] Requesting video subtitles"),t||(console.error("[VOT] Failed get yandex subtitles"),a=!0,i([]));const o=X(e);console.log("[VOT] Subtitles response: ",o);let n=o.subtitles??[];n=n.reduce(((t,e)=>(e.language&&!t.find((t=>{if("yandex"===t.source&&t.language===e.language&&!t.translatedFromLanguage)return t}))&&t.push({source:"yandex",language:e.language,url:e.url}),e.translatedLanguage&&t.push({source:"yandex",language:e.translatedLanguage,translatedFromLanguage:e.language,url:e.translatedUrl}),t)),[]),a=!0,i(n)}))}))]),...i].sort(((t,e)=>{if(t.source!==e.source)return"yandex"===t.source?-1:1;if(t.language!==e.language&&(t.language===x.KQ||e.language===x.KQ))return t.language===x.KQ?-1:1;if("yandex"===t.source){if(t.translatedFromLanguage!==e.translatedFromLanguage)return t.translatedFromLanguage&&e.translatedFromLanguage?t.translatedFromLanguage===n?-1:1:t.language===e.language?t.translatedFromLanguage?1:-1:t.translatedFromLanguage?-1:1;if(!t.translatedFromLanguage)return t.language===n?-1:1}return"youtube"===t.source&&t.isAutoGenerated!==e.isAutoGenerated?t.isAutoGenerated?1:-1:0}));return console.log("[VOT] subtitles list",r),r}(this.site,t,this.videoData.detectedLanguage),this.subtitlesList?this.subtitlesListVideoId=t:await this.changeSubtitlesLang("disabled"),await this.updateSubtitlesLangSelect())}getVideoVolume(){let t=this.video?.volume;return"youtube"===this.site.host&&(t=_()||t),t}setVideoVolume(t){"youtube"===this.site.host&&z(t)||(this.video.volume=t)}syncVideoVolumeSlider(){const t=Math.round(100*this.getVideoVolume());this.votVideoVolumeSlider.input.value=t,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${t}%`,ct.updateSlider(this.votVideoVolumeSlider.input),1===this.data.syncVolume&&(this.tempOriginalVolume=Number(t))}setSelectMenuValues(t,e){this.votTranslationLanguageSelect.fromSelect.setTitle(v.V.get("langs")[t]),this.votTranslationLanguageSelect.toSelect.setTitle(v.V.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}syncTranslationWithVideo(t){const e=Number(this.votVideoVolumeSlider.input.value),o=ut(this.video,t,e,this.tempVolume);this.votVideoVolumeSlider.input.value=o,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,ct.updateSlider(this.votVideoVolumeSlider.input),this.tempOriginalVolume=o,this.tempVolume=t}async getVideoData(){const t={translationHelp:null,isStream:!1};if(t.duration=this.video?.duration||343,t.videoId=(0,x.gJ)(this.site.host,this.video),t.detectedLanguage=this.translateFromLang,t.responseLanguage=this.translateToLang,!t.videoId)return this.ytData={},t;if(window.location.hostname.includes("youtube.com"))this.ytData=await q(),t.isStream=this.ytData.isLive,""!==this.ytData.author&&(t.detectedLanguage=this.ytData.detectedLanguage,t.responseLanguage=this.translateToLang);else if(window.location.hostname.includes("rutube")||window.location.hostname.includes("my.mail.ru"))t.detectedLanguage="ru";else if(window.location.hostname.includes("bilibili.com"))t.detectedLanguage="zh";else if(window.location.hostname.includes("coursera.org")){const e=await xt(this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else if(window.location.hostname.includes("coursehunter.net")){const e=await ft();t.translationHelp={url:e.url},t.duration=e.duration||t.duration}else if(window.location.hostname.includes("udemy.com")){const e=await Ot(this.data.udemyData,this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else"vk"!==this.site.host&&"piped"!==this.site.host&&"invidious"!==this.site.host&&"bitchute"!==this.site.host&&"rumble"!==this.site.host&&"peertube"!==this.site.host&&"dailymotion"!==this.site.host&&"trovo"!==this.site.host&&"yandexdisk"!==this.site.host&&"coursehunter"!==this.site.host||(t.detectedLanguage="auto");return t}videoValidator(){if("youtube"===this.site.host){if(b.Z.log("VideoValidator videoData: ",this.videoData),1===this.data.dontTranslateYourLang&&this.videoData.detectedLanguage===this.data.dontTranslateLanguage&&this.videoData.responseLanguage===this.data.dontTranslateLanguage)throw new m("VOTDisableFromYourLang");if(this.videoData.duration>14400)throw new m("VOTVideoIsTooLong")}return!0}lipSync(t=!1){if(b.Z.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"===t&&(b.Z.log("lipsync mode is pause"),this.audio.pause()),"stop"===t&&(b.Z.log("lipsync mode is stop"),this.audio.pause()),"waiting"===t&&(b.Z.log("lipsync mode is waiting"),this.audio.pause()),"playing"===t&&(b.Z.log("lipsync mode is playing"),this.audio.play());else{b.Z.log("lipsync mode is play");const t=this.audio.play();void 0!==t&&t.catch((t=>{if(console.error("[VOT]",t),"NotAllowedError"===t.name)throw this.transformBtn("error",v.V.get("grantPermissionToAutoPlay")),new m("grantPermissionToAutoPlay");if("NotSupportedError"===t.name)throw this.transformBtn("error",Bt.includes(window.location.hostname)?v.V.get("neededAdditionalExtension"):v.V.get("audioFormatNotSupported")),Bt.includes(window.location.hostname)?new m("neededAdditionalExtension"):new m("audioFormatNotSupported")}))}else b.Z.log("lipsync mode is not set")}handleVideoEvent(t){b.Z.log(`video ${t.type}`),this.lipSync(t.type)}stopTraslate(){_t.forEach((t=>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",v.V.get("translateVideo")),this.volumeOnStart&&(b.Z.log(`Volume on start: ${this.volumeOnStart}`),"youtube"===this.site.host?z(this.volumeOnStart):this.video.volume=this.volumeOnStart),clearInterval(this.streamPing),this.hls?.destroy(),this.hls=(0,x.QZ)()}async translateExecutor(t){this.videoData.detectedLanguage||(this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage)),b.Z.log("Run videoValidator"),this.videoValidator(),b.Z.log("Run translateFunc"),this.translateFunc(t,this.videoData.isStream,this.videoData.detectedLanguage,this.videoData.responseLanguage,this.videoData.translationHelp)}translateFunc(t,e,n,i,a){console.log("[VOT] Video Data: ",this.videoData);const r=a?.url?a.url:`${this.site.url}${t}`;if(this.videoValidator(),e)return b.Z.log("Executed stream translation"),void function(t,e,n,i){b.Z.log(`Translate stream (url: ${t}, requestLang: ${e}, responseLang: ${n})`),async function(t,e,n,i){try{b.Z.log("requestStreamTranslation");const a=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;b.Z.log("Inited yandexRequest...");const r=et(t,e,n);await a("/stream-translation/translate-stream",r,{"Vtrans-Signature":await gt(r),"Sec-Vtrans-Token":pt(!1)},i)}catch(t){console.error("[VOT]",t),i(!1)}}(t,e,n,((t,e)=>{if(b.Z.log("[exec callback] Requesting stream translation"),!t)return void i(!1,v.V.get("requestTranslationFailed"));const o=ot(e);switch(console.log("[VOT] Stream Translation response: ",o),o.interval){case 10:i(!1,o.interval,v.V.get("translationTakeFewMinutes"));break;case 20:i(!0,o.interval,o||v.V.get("audioNotReceived"));break;case 0:i(!1,o.interval,v.V.get("streamNoConnectionToServer"))}}))}(r,n,i,(async(r,s,l)=>{if(b.Z.log("[exec callback] translateStream callback"),(0,x.gJ)(this.site.host,this.video)!==t)return;if(!r||!l.translatedInfo)return"VOTLocalizedError"===l?.name?this.transformBtn("error",l.localizedMessage):1===this.data.translateAPIErrors&&"ru"!==v.V.lang?(this.transformBtn("error",`${v.V.get("VOTTranslatingError")}...`),this.transformBtn("error",await L(l,"ru",v.V.lang))):this.transformBtn("error",l),void(10===s&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,n,i,a)),1e3*s)));this.transformBtn("success",v.V.get("disableTranslate")),console.log(l);const d=l.pingId;b.Z.log(`Stream pingId: ${d}`),this.streamPing=setInterval((async()=>await async function(t,e){try{b.Z.log("requestStreamPing");const n=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;b.Z.log("Inited yandexRequest...");const i=tt(t);await n("/stream-translation/ping-stream",i,{"Vtrans-Signature":await gt(i),"Sec-Vtrans-Token":pt(!1)},e)}catch(t){console.error("[VOT]",t),e(!1)}}(d,(t=>b.Z.log("Stream ping result: ",t)))),1e3*s),b.Z.log(l.translatedInfo.url);const c=`https://${this.data.m3u8ProxyHost}/?all=yes&origin=${encodeURIComponent("https://strm.yandex.ru")}&referer=${encodeURIComponent("https://strm.yandex.ru")}&url=${encodeURIComponent(l.translatedInfo.url)}`;if(b.Z.log(c),this.hls)this.hls.on(Hls.Events.MEDIA_ATTACHED,(function(){b.Z.log("audio and hls.js are now bound together !")})),this.hls.on(Hls.Events.MANIFEST_PARSED,(function(t,e){b.Z.log("manifest loaded, found "+e.levels.length+" quality level")})),this.hls.loadSource(c),this.hls.attachMedia(this.audio),this.hls.on(Hls.Events.ERROR,(function(t,e){if(e.fatal)switch(e.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",e);break;default:this.hls.destroy()}})),b.Z.log(this.hls);else{if(!this.audio.canPlayType("application/vnd.apple.mpegurl"))throw new m("audioFormatNotSupported");this.audio.src=c}R(this.video,10),this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),this.video.src||this.video.currentSrc||this.video.srcObject?(this.video&&!this.video.paused&&this.lipSync("play"),_t.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),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").innerHTML=100*this.data.autoVolume+"%",ct.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=c):this.stopTranslation()}));if(["udemy","coursera"].includes(this.site.host)&&!a)throw new m("VOTTranslationHelpNull");!function(t,e,n,i,a,r){b.Z.log(`Translate video (url: ${t}, duration: ${e}, requestLang: ${n}, responseLang: ${i})`),b.Z.log("translationHelp:",a),qt?b.Z.log("translationPanding return"):(qt=!0,async function(t,e,n,i,a,r){try{b.Z.log("requestVideoTranslation");const s=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;b.Z.log("Inited yandexRequest...");const l=K(t,e,n,i,a);await s("/video-translation/translate",l,{"Vtrans-Signature":await gt(l),"Sec-Vtrans-Token":pt(!1)},r)}catch(t){console.error("[VOT]",t),r(!1)}}(t,e,n,i,a,((t,e)=>{if(qt=!1,b.Z.log("[exec callback] Requesting video translation"),!t)return void r(!1,v.V.get("requestTranslationFailed"));const o=Q(e);switch(console.log("[VOT] Translation response: ",o),o.status){case 0:r(!1,o.message);break;case 1:r(!!o.url,o.url||v.V.get("audioNotReceived"));break;case 2:r(!1,o.remainingTime?(0,x.PG)(o.remainingTime):v.V.get("translationTakeFewMinutes"));break;case 3:case 6:r(!1,v.V.get("videoBeingTranslated"))}})))}(r,this.videoData.duration,n,i,a,(async(o,r)=>{if(b.Z.log("[exec callback] translateVideo callback"),(0,x.gJ)(this.site.host,this.video)!==t)return;if(!o)return"VOTLocalizedError"===r?.name?this.transformBtn("error",r.localizedMessage):1!==this.data.translateAPIErrors||r.includes(v.V.get("translationTake"))||"ru"===v.V.lang?this.transformBtn("error",r):(this.transformBtn("error",v.V.get("VOTTranslatingError")),this.transformBtn("error",await L(r,"ru",v.V.lang))),r.includes(v.V.get("translationTake"))&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,n,i,a)),6e4)),void console.error("[VOT]",r);if(this.audio.src=r,1===this.data.audioProxy&&r.startsWith("https://")){const t=r.replace("https://vtrans.s3-private.mds.yandex.net/tts/prod/",""),e=`https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${t}`;console.log(`[VOT] Audio proxied via ${e}`),this.audio.src=e}if(this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),"twitter"===this.site.host&&document.querySelector('div[data-testid="app-bar-back"][role="button"]').addEventListener("click",this.stopTranslationBound),!this.video.src&&!this.video.currentSrc&&!this.video.srcObject)return void this.stopTranslation();const s=["twitch","vimeo","facebook","rutube","twitter","bilibili","mail_ru","rumble","eporner"];for(let t=0;t{t.forEach((t=>{"attributes"===t.type&&"src"===t.attributeName&&t.target===this.video&&""!==t.target.src&&(this.stopTranslation(),this.firstPlay=!0)}))})).observe(this.container,{attributes:!0,childList:!1,subtree:!0,attributeOldValue:!0});break}this.video&&!this.video.paused&&this.lipSync("play"),_t.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),this.transformBtn("success",v.V.get("disableTranslate")),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").innerHTML=100*this.data.autoVolume+"%",ct.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=r}))}stopTranslation(){this.stopTraslate(),this.syncVideoVolumeSlider()}async waitInitialization(){let t=!1;return await Promise.race([new Promise((async e=>{await(0,x._v)(1e3),t||console.error("[VOT] Initialization timeout"),t=!0,e(!1)})),new Promise((async e=>{for(;!this.initialized;)await(0,x._v)(100);t=!0,e(!0)}))])}async handleSrcChanged(){if(b.Z.log("[VideoHandler] src changed",this),!await this.waitInitialization())return;this.stopTranslation(),this.videoData=await this.getVideoData(),this.firstPlay=!0;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.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage??"ru"),this.translateToLang=this.data.responseLanguage??"ru"}async release(){b.Z.log("[VideoHandler] release"),await this.waitInitialization()&&(this.initialized=!1,this.stopTranslation(),this.releaseExtraEvents(),this.subtitlesWidget.release(),this.srcObserver.disconnect(),clearInterval(this.srcObjectInterval),this.votButton.container.remove(),this.votMenu.container.remove())}}const Rt=new class{constructor(){this.onVideoAdded=new Pt,this.onVideoRemoved=new Pt,this.handleVideoAddedBound=this.handleVideoAdded.bind(this),this.handleVideoRemovedBound=this.handleVideoRemoved.bind(this),this.observer=new MutationObserver((t=>{window.requestIdleCallback((()=>{t.forEach((t=>{"childList"===t.type&&(Et(t.addedNodes).forEach(this.handleVideoAddedBound),Et(t.removedNodes).forEach(this.handleVideoRemovedBound))}))}),{timeout:1e3})}))}enable(){this.observer.observe(document,{childList:!0,subtree:!0}),document.querySelectorAll("video").forEach(this.handleVideoAddedBound)}disable(){this.observer.disconnect()}handleVideoAdded(t){this.onVideoAdded.dispatch(t)}handleVideoRemoved(t){document.contains(t)||this.onVideoRemoved.dispatch(t)}},Dt=new WeakMap;(async function(){b.Z.log("Loading extension..."),await v.V.update(),b.Z.log(`Selected menu language: ${v.V.lang}`),b.Z.log("Extension compatibility passed..."),Rt.onVideoAdded.addListener((t=>{for(const e of Ct.filter((t=>{const e=t=>t instanceof RegExp&&t.test(window.location.hostname)||"string"==typeof t&&window.location.hostname.includes(t)||"function"==typeof t&&t(new URL(window.location));return!!(e(t.match)||t.match instanceof Array&&t.match.some((t=>e(t))))&&t.host&&t.url}))){if(!e)continue;let o;if(e.shadowRoot)o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.shadowRoot.contains(t))):t.parentElement,o=o&&o.shadowRoot?o.parentElement:o;else{const n=At.browser.version.split(".")?.[0];if(e.selector?.includes(":not")&&e.selector?.includes("*")&&n&&("Chrome"===At.browser.name&&Number(n)<88||"Firefox"===At.browser.name&&Number(n)<84)){const n=e.selector?.split(" *")?.[0];o=n?Object.values(document.querySelectorAll(n)).find((e=>e.contains(t))):t.parentElement}else o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.contains(t))):t.parentElement}if(o&&!("rumble"===e.host&&o.querySelector("vot-block")||("peertube"===e.host&&(e.url=window.location.origin),Dt.has(t)))){Dt.set(t,new zt(t,o,e));break}}})),Rt.onVideoRemoved.addListener((async t=>{Dt.has(t)&&(await Dt.get(t).release(),Dt.delete(t))})),Rt.enable()})().catch((t=>{console.error("[VOT]",t)}))})()})(); \ No newline at end of file +(()=>{var t={"./node_modules/bowser/es5.js":function(t){t.exports=function(t){var e={};function o(n){if(e[n])return e[n].exports;var a=e[n]={i:n,l:!1,exports:{}};return t[n].call(a.exports,a,a.exports,o),a.l=!0,a.exports}return o.m=t,o.c=e,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)o.d(n,a,function(e){return t[e]}.bind(null,a));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=90)}({17:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n=o(18),a=function(){function t(){}return t.getFirstMatch=function(t,e){var o=e.match(t);return o&&o.length>0&&o[1]||""},t.getSecondMatch=function(t,e){var o=e.match(t);return o&&o.length>1&&o[2]||""},t.matchAndReturnConst=function(t,e,o){if(t.test(e))return o},t.getWindowsVersionName=function(t){switch(t){case"NT":return"NT";case"XP":case"NT 5.1":return"XP";case"NT 5.0":return"2000";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return}},t.getMacOSVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),10===e[0])switch(e[1]){case 5:return"Leopard";case 6:return"Snow Leopard";case 7:return"Lion";case 8:return"Mountain Lion";case 9:return"Mavericks";case 10:return"Yosemite";case 11:return"El Capitan";case 12:return"Sierra";case 13:return"High Sierra";case 14:return"Mojave";case 15:return"Catalina";default:return}},t.getAndroidVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),!(1===e[0]&&e[1]<5))return 1===e[0]&&e[1]<6?"Cupcake":1===e[0]&&e[1]>=6?"Donut":2===e[0]&&e[1]<2?"Eclair":2===e[0]&&2===e[1]?"Froyo":2===e[0]&&e[1]>2?"Gingerbread":3===e[0]?"Honeycomb":4===e[0]&&e[1]<1?"Ice Cream Sandwich":4===e[0]&&e[1]<4?"Jelly Bean":4===e[0]&&e[1]>=4?"KitKat":5===e[0]?"Lollipop":6===e[0]?"Marshmallow":7===e[0]?"Nougat":8===e[0]?"Oreo":9===e[0]?"Pie":void 0},t.getVersionPrecision=function(t){return t.split(".").length},t.compareVersions=function(e,o,n){void 0===n&&(n=!1);var a=t.getVersionPrecision(e),i=t.getVersionPrecision(o),r=Math.max(a,i),s=0,l=t.map([e,o],(function(e){var o=r-t.getVersionPrecision(e),n=e+new Array(o+1).join(".0");return t.map(n.split("."),(function(t){return new Array(20-t.length).join("0")+t})).reverse()}));for(n&&(s=r-Math.min(a,i)),r-=1;r>=s;){if(l[0][r]>l[1][r])return 1;if(l[0][r]===l[1][r]){if(r===s)return 0;r-=1}else if(l[0][r]1?a-1:0),r=1;r0){var r=Object.keys(o),l=s.default.find(r,(function(t){return e.isOS(t)}));if(l){var d=this.satisfies(o[l]);if(void 0!==d)return d}var c=s.default.find(r,(function(t){return e.isPlatform(t)}));if(c){var u=this.satisfies(o[c]);if(void 0!==u)return u}}if(i>0){var h=Object.keys(a),p=s.default.find(h,(function(t){return e.isBrowser(t,!0)}));if(void 0!==p)return this.compareVersion(a[p])}},e.isBrowser=function(t,e){void 0===e&&(e=!1);var o=this.getBrowserName().toLowerCase(),n=t.toLowerCase(),a=s.default.getBrowserTypeByAlias(n);return e&&a&&(n=a.toLowerCase()),n===o},e.compareVersion=function(t){var e=[0],o=t,n=!1,a=this.getBrowserVersion();if("string"==typeof a)return">"===t[0]||"<"===t[0]?(o=t.substr(1),"="===t[1]?(n=!0,o=t.substr(2)):e=[],">"===t[0]?e.push(1):e.push(-1)):"="===t[0]?o=t.substr(1):"~"===t[0]&&(n=!0,o=t.substr(1)),e.indexOf(s.default.compareVersions(a,o,n))>-1},e.isOS=function(t){return this.getOSName(!0)===String(t).toLowerCase()},e.isPlatform=function(t){return this.getPlatformType(!0)===String(t).toLowerCase()},e.isEngine=function(t){return this.getEngineName(!0)===String(t).toLowerCase()},e.is=function(t,e){return void 0===e&&(e=!1),this.isBrowser(t,e)||this.isOS(t)||this.isPlatform(t)},e.some=function(t){var e=this;return void 0===t&&(t=[]),t.some((function(t){return e.is(t)}))},t}();e.default=d,t.exports=e.default},92:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=/version\/(\d+(\.?_?\d+)+)/i,r=[{test:[/googlebot/i],describe:function(t){var e={name:"Googlebot"},o=a.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/opera/i],describe:function(t){var e={name:"Opera"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opr\/|opios/i],describe:function(t){var e={name:"Opera"},o=a.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/SamsungBrowser/i],describe:function(t){var e={name:"Samsung Internet for Android"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Whale/i],describe:function(t){var e={name:"NAVER Whale Browser"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MZBrowser/i],describe:function(t){var e={name:"MZ Browser"},o=a.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/focus/i],describe:function(t){var e={name:"Focus"},o=a.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/swing/i],describe:function(t){var e={name:"Swing"},o=a.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/coast/i],describe:function(t){var e={name:"Opera Coast"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(t){var e={name:"Opera Touch"},o=a.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/yabrowser/i],describe:function(t){var e={name:"Yandex Browser"},o=a.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/ucbrowser/i],describe:function(t){var e={name:"UC Browser"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Maxthon|mxios/i],describe:function(t){var e={name:"Maxthon"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/epiphany/i],describe:function(t){var e={name:"Epiphany"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/puffin/i],describe:function(t){var e={name:"Puffin"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sleipnir/i],describe:function(t){var e={name:"Sleipnir"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/k-meleon/i],describe:function(t){var e={name:"K-Meleon"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/micromessenger/i],describe:function(t){var e={name:"WeChat"},o=a.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/qqbrowser/i],describe:function(t){var e={name:/qqbrowserlite/i.test(t)?"QQ Browser Lite":"QQ Browser"},o=a.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/msie|trident/i],describe:function(t){var e={name:"Internet Explorer"},o=a.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/\sedg\//i],describe:function(t){var e={name:"Microsoft Edge"},o=a.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/edg([ea]|ios)/i],describe:function(t){var e={name:"Microsoft Edge"},o=a.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/vivaldi/i],describe:function(t){var e={name:"Vivaldi"},o=a.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/seamonkey/i],describe:function(t){var e={name:"SeaMonkey"},o=a.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sailfish/i],describe:function(t){var e={name:"Sailfish"},o=a.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,t);return o&&(e.version=o),e}},{test:[/silk/i],describe:function(t){var e={name:"Amazon Silk"},o=a.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/phantom/i],describe:function(t){var e={name:"PhantomJS"},o=a.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/slimerjs/i],describe:function(t){var e={name:"SlimerJS"},o=a.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e={name:"BlackBerry"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e={name:"WebOS Browser"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/bada/i],describe:function(t){var e={name:"Bada"},o=a.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/tizen/i],describe:function(t){var e={name:"Tizen"},o=a.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/qupzilla/i],describe:function(t){var e={name:"QupZilla"},o=a.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/firefox|iceweasel|fxios/i],describe:function(t){var e={name:"Firefox"},o=a.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/electron/i],describe:function(t){var e={name:"Electron"},o=a.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MiuiBrowser/i],describe:function(t){var e={name:"Miui"},o=a.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/chromium/i],describe:function(t){var e={name:"Chromium"},o=a.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/chrome|crios|crmo/i],describe:function(t){var e={name:"Chrome"},o=a.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/GSA/i],describe:function(t){var e={name:"Google Search"},o=a.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e={name:"Android Browser"},o=a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/playstation 4/i],describe:function(t){var e={name:"PlayStation 4"},o=a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/safari|applewebkit/i],describe:function(t){var e={name:"Safari"},o=a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/.*/i],describe:function(t){var e=-1!==t.search("\\(")?/^(.*)\/(.*)[ \t]\((.*)/:/^(.*)\/(.*) /;return{name:a.default.getFirstMatch(e,t),version:a.default.getSecondMatch(e,t)}}}];e.default=r,t.exports=e.default},93:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=o(18),r=[{test:[/Roku\/DVP/],describe:function(t){var e=a.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,t);return{name:i.OS_MAP.Roku,version:e}}},{test:[/windows phone/i],describe:function(t){var e=a.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.WindowsPhone,version:e}}},{test:[/windows /i],describe:function(t){var e=a.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,t),o=a.default.getWindowsVersionName(e);return{name:i.OS_MAP.Windows,version:e,versionName:o}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(t){var e={name:i.OS_MAP.iOS},o=a.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,t);return o&&(e.version=o),e}},{test:[/macintosh/i],describe:function(t){var e=a.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,t).replace(/[_\s]/g,"."),o=a.default.getMacOSVersionName(e),n={name:i.OS_MAP.MacOS,version:e};return o&&(n.versionName=o),n}},{test:[/(ipod|iphone|ipad)/i],describe:function(t){var e=a.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,t).replace(/[_\s]/g,".");return{name:i.OS_MAP.iOS,version:e}}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e=a.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,t),o=a.default.getAndroidVersionName(e),n={name:i.OS_MAP.Android,version:e};return o&&(n.versionName=o),n}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e=a.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,t),o={name:i.OS_MAP.WebOS};return e&&e.length&&(o.version=e),o}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e=a.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,t)||a.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,t)||a.default.getFirstMatch(/\bbb(\d+)/i,t);return{name:i.OS_MAP.BlackBerry,version:e}}},{test:[/bada/i],describe:function(t){var e=a.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.Bada,version:e}}},{test:[/tizen/i],describe:function(t){var e=a.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.Tizen,version:e}}},{test:[/linux/i],describe:function(){return{name:i.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:i.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(t){var e=a.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.PlayStation4,version:e}}}];e.default=r,t.exports=e.default},94:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=o(18),r=[{test:[/googlebot/i],describe:function(){return{type:"bot",vendor:"Google"}}},{test:[/huawei/i],describe:function(t){var e=a.default.getFirstMatch(/(can-l01)/i,t)&&"Nova",o={type:i.PLATFORMS_MAP.mobile,vendor:"Huawei"};return e&&(o.model=e),o}},{test:[/nexus\s*(?:7|8|9|10).*/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Nexus"}}},{test:[/ipad/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/kftt build/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Amazon",model:"Kindle Fire HD 7"}}},{test:[/silk/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Amazon"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet}}},{test:function(t){var e=t.test(/ipod|iphone/i),o=t.test(/like (ipod|iphone)/i);return e&&!o},describe:function(t){var e=a.default.getFirstMatch(/(ipod|iphone)/i,t);return{type:i.PLATFORMS_MAP.mobile,vendor:"Apple",model:e}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:i.PLATFORMS_MAP.mobile,vendor:"Nexus"}}},{test:[/[^-]mobi/i],describe:function(){return{type:i.PLATFORMS_MAP.mobile}}},{test:function(t){return"blackberry"===t.getBrowserName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.mobile,vendor:"BlackBerry"}}},{test:function(t){return"bada"===t.getBrowserName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.mobile}}},{test:function(t){return"windows phone"===t.getBrowserName()},describe:function(){return{type:i.PLATFORMS_MAP.mobile,vendor:"Microsoft"}}},{test:function(t){var e=Number(String(t.getOSVersion()).split(".")[0]);return"android"===t.getOSName(!0)&&e>=3},describe:function(){return{type:i.PLATFORMS_MAP.tablet}}},{test:function(t){return"android"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.mobile}}},{test:function(t){return"macos"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.desktop,vendor:"Apple"}}},{test:function(t){return"windows"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.desktop}}},{test:function(t){return"linux"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.desktop}}},{test:function(t){return"playstation 4"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.tv}}},{test:function(t){return"roku"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.tv}}}];e.default=r,t.exports=e.default},95:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=o(18),r=[{test:function(t){return"microsoft edge"===t.getBrowserName(!0)},describe:function(t){if(/\sedg\//i.test(t))return{name:i.ENGINE_MAP.Blink};var e=a.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,t);return{name:i.ENGINE_MAP.EdgeHTML,version:e}}},{test:[/trident/i],describe:function(t){var e={name:i.ENGINE_MAP.Trident},o=a.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){return t.test(/presto/i)},describe:function(t){var e={name:i.ENGINE_MAP.Presto},o=a.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=t.test(/gecko/i),o=t.test(/like gecko/i);return e&&!o},describe:function(t){var e={name:i.ENGINE_MAP.Gecko},o=a.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:i.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(t){var e={name:i.ENGINE_MAP.WebKit},o=a.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}}];e.default=r,t.exports=e.default}})},"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss":(t,e,o)=>{"use strict";o.d(e,{A:()=>s});var n=o("./node_modules/css-loader/dist/runtime/noSourceMaps.js"),a=o.n(n),i=o("./node_modules/css-loader/dist/runtime/api.js"),r=o.n(i)()(a());r.push([t.id,'.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}',""]);const s=r},"./node_modules/css-loader/dist/runtime/api.js":t=>{"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var o="",n=void 0!==e[5];return e[4]&&(o+="@supports (".concat(e[4],") {")),e[2]&&(o+="@media ".concat(e[2]," {")),n&&(o+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),o+=t(e),n&&(o+="}"),e[2]&&(o+="}"),e[4]&&(o+="}"),o})).join("")},e.i=function(t,o,n,a,i){"string"==typeof t&&(t=[[null,t,void 0]]);var r={};if(n)for(var s=0;s0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=i),o&&(c[2]?(c[1]="@media ".concat(c[2]," {").concat(c[1],"}"),c[2]=o):c[2]=o),a&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=a):c[4]="".concat(a)),e.push(c))}},e}},"./node_modules/css-loader/dist/runtime/noSourceMaps.js":t=>{"use strict";t.exports=function(t){return t[1]}},"./node_modules/requestidlecallback-polyfill/index.js":()=>{window.requestIdleCallback=window.requestIdleCallback||function(t){var e=Date.now();return setTimeout((function(){t({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-e))}})}),1)},window.cancelIdleCallback=window.cancelIdleCallback||function(t){clearTimeout(t)}},"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":t=>{"use strict";var e=[];function o(t){for(var o=-1,n=0;n{"use strict";var e={};t.exports=function(t,o){var n=function(t){if(void 0===e[t]){var o=document.querySelector(t);if(window.HTMLIFrameElement&&o instanceof window.HTMLIFrameElement)try{o=o.contentDocument.head}catch(t){o=null}e[t]=o}return e[t]}(t);if(!n)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");n.appendChild(o)}},"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js":(t,e,o)=>{"use strict";t.exports=function(t){var e=o.nc;e&&t.setAttribute("nonce",e)}},"./node_modules/style-loader/dist/runtime/styleDomAPI.js":t=>{"use strict";t.exports=function(t){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=t.insertStyleElement(t);return{update:function(o){!function(t,e,o){var n="";o.supports&&(n+="@supports (".concat(o.supports,") {")),o.media&&(n+="@media ".concat(o.media," {"));var a=void 0!==o.layer;a&&(n+="@layer".concat(o.layer.length>0?" ".concat(o.layer):""," {")),n+=o.css,a&&(n+="}"),o.media&&(n+="}"),o.supports&&(n+="}");var i=o.sourceMap;i&&"undefined"!=typeof btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleTagTransform(n,t,e.options)}(e,t,o)},remove:function(){!function(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t)}(e)}}}},"./node_modules/style-loader/dist/runtime/styleTagTransform.js":t=>{"use strict";t.exports=function(t,e){if(e.styleSheet)e.styleSheet.cssText=t;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(t))}}},"./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js":t=>{t.exports=function(){return function(t){return t.styleTagTransform=function(t,e){e?.remove(),GM_addStyle(t)},document.createElement("style")}.apply(null,arguments)}},"./src/config/config.js":(t,e,o)=>{"use strict";o.d(e,{Cc:()=>r,JD:()=>s,K2:()=>d,Pm:()=>a,QL:()=>c,S7:()=>i,mE:()=>l,rw:()=>u,se:()=>n});const n="m3u8-proxy.toil.cc",a="vot.toil.cc",i="xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm",r="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36",s=.15,l="yandex",d="yandex",c={yandex:"https://translate.toil.cc/detect",rustServer:"https://rust-server-531j.onrender.com/detect"},u={yandex:"https://translate.toil.cc/translate"}},"./src/utils/debug.js":(t,e,o)=>{"use strict";o.d(e,{A:()=>a});const n={log:(...t)=>{}},a=n},"./src/utils/storage.js":(t,e,o)=>{"use strict";o.d(e,{d:()=>a});var n=o("./src/utils/debug.js");const a=new class{constructor(){this.gmSupport="function"==typeof GM_getValue,n.A.log(`GM Storage Status: ${this.gmSupport}`)}syncGet(t,e=void 0,o=!1){if(this.gmSupport)return GM_getValue(t,e);let n=window.localStorage.getItem(t);if("udemyData"===t&&"string"==typeof n)try{n=JSON.parse(n)}catch{n=e}return o?Number(n)??Number(e):n??e}async get(t,e=void 0,o=!1){return this.gmSupport?await GM_getValue(t,e):Promise.resolve(this.syncGet(t,e,o))}syncSet(t,e){return this.gmSupport?GM_setValue(t,e):("udemyData"===t&&(e=JSON.stringify(e)),window.localStorage.setItem(t,e))}async set(t,e){return this.gmSupport?await GM_setValue(t,e):Promise.resolve(this.syncSet(t,e))}syncDelete(t){return this.gmSupport?GM_deleteValue(t):window.localStorage.removeItem(t)}async delete(t){return this.gmSupport?await GM_deleteValue(t):Promise.resolve(this.syncDelete(t))}syncList(){return this.gmSupport?GM_listValues():["autoTranslate","dontTranslateLanguage","dontTranslateYourLang","autoSetVolumeYandexStyle","showVideoSlider","syncVolume","subtitlesMaxLength","highlightWords","responseLanguage","defaultVolume","udemyData","audioProxy","showPiPButton","locale-version","locale-lang","locale-phrases"]}async list(){return this.gmSupport?await GM_listValues():Promise.resolve(this.syncList())}}},"./src/yandexRequest-cloudflare.js":(t,e,o)=>{"use strict";o.r(e),o.d(e,{default:()=>r});var n=o("./src/config/config.js"),a=o("./src/utils/debug.js"),i=o("./src/utils/storage.js");const r=async function(t,e,o,r){let s,l;try{a.A.log("yandexRequest:",t);const r={method:"POST",mode:"cors",cache:"no-cache",headers:{"Content-Type":"application/json"},redirect:"follow",referrerPolicy:"no-referrer",body:JSON.stringify({headers:{Accept:"application/x-protobuf","Accept-Language":"en","Content-Type":"application/x-protobuf","User-Agent":n.Cc,Pragma:"no-cache","Cache-Control":"no-cache","Sec-Fetch-Mode":"no-cors",...o},body:Array.from(e)})},d=await i.d.get("proxyWorkerHost",n.Pm);s=await fetch(`https://${d}${t}`,r),a.A.log("yandexRequest:",s.status,s),l=await s.arrayBuffer()}catch(t){console.error("[VOT]",t),s={status:-1},l=t}r(200==s.status,l)}}},e={};function o(n){var a=e[n];if(void 0!==a)return a.exports;var i=e[n]={id:n,exports:{}};return t[n].call(i.exports,i,i.exports,o),i.exports}o.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return o.d(e,{a:e}),e},o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.nc=void 0,(()=>{"use strict";const t=["invidious.snopyta.org","yewtu.be","invidious.kavin.rocks","vid.puffyan.us","invidious.namazso.eu","inv.riverside.rocks","yt.artemislena.eu","invidious.flokinet.to","invidious.esmailelbob.xyz","y.com.sb","invidious.nerdvpn.de","inv.vern.cc","invidious.slipfox.xyz","invidio.xamh.de","invidious.dhusch.de"],e=["piped.video","piped.tokhmi.xyz","piped.moomoo.me","piped.syncpundit.io","piped.mha.fi","watch.whatever.social","piped.garudalinux.org","efy.piped.pages.dev","watch.leptons.xyz","piped.lunar.icu","yt.dc09.ru","piped.mint.lgbt","il.ax","piped.privacy.com.de","piped.esmailelbob.xyz","piped.projectsegfau.lt","piped.in.projectsegfau.lt","piped.us.projectsegfau.lt","piped.privacydev.net","piped.palveluntarjoaja.eu","piped.smnz.de","piped.adminforge.de","piped.qdi.fi","piped.hostux.net","piped.chauvet.pro","piped.jotoma.de","piped.pfcd.me","piped.frontendfriendly.xyz"],n=["proxitok.pabloferreiro.es","proxitok.pussthecat.org","tok.habedieeh.re","proxitok.esmailelbob.xyz","proxitok.privacydev.net","tok.artemislena.eu","tok.adminforge.de","tik.hostux.net","tt.vern.cc","cringe.whatever.social","proxitok.lunar.icu","proxitok.privacy.com.de"],a=["peertube.1312.media","tube.shanti.cafe","bee-tube.fr","video.sadmin.io","dalek.zone","review.peertube.biz","peervideo.club","tube.la-dina.net","peertube.tmp.rcp.tf"];var i=o("./src/config/config.js");const r=["ru","en","zh","ko","lt","lv","ar","fr","it","es","de","ja"],s=["kk","bn","pt","cs","hi","mr","te","tr","ms","vi","ta","jv","ur","fa","gu","id","uk","da","fi","uz","pl","sv","az","sq","am","hy","af","eu","my","bg","bs","cy","hu","gl","el","zu","kn","ca","km","lo","mk","ml","mt","mn","ne","nl","pa","ro","sr","si","sk","sl","sw","su","hr","et"],l=["ru","en","kk"],d=JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}');var c=o("./src/utils/debug.js"),u=o("./src/utils/storage.js");const h=["auto","en","ru","af","am","ar","az","bg","bn","bs","ca","cs","cy","da","de","el","es","et","eu","fa","fi","fr","gl","hi","hr","hu","hy","id","it","ja","jv","kk","km","kn","ko","lo","mk","ml","mn","ms","mt","my","ne","nl","pa","pl","pt","ro","si","sk","sl","sq","sr","su","sv","sw","tr","uk","ur","uz","vi","zh","zu"],p=new class{lang="en";locale={};gmValues=["locale-phrases","locale-lang","locale-version","locale-lang-override"];constructor(){const t=u.d.syncGet("locale-lang-override","auto");this.lang=t&&"auto"!==t?t:(navigator.language||navigator.userLanguage)?.substr(0,2)?.toLowerCase()??"en",this.setLocaleFromJsonString(u.d.syncGet("locale-phrases",""))}reset(){this.gmValues.forEach((t=>u.d.syncDelete(t)))}async update(t=!1){(t||2!==await u.d.get("locale-version",0,!0)||await u.d.get("locale-lang")!==this.lang)&&(c.A.log("Updating locale..."),await fetch(`https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/src/localization/locales/${this.lang}.json`).then((t=>{if(200===t.status)return t.text();throw t.status})).then((async t=>{await u.d.set("locale-phrases",t),this.setLocaleFromJsonString(t);const e=this.getFromLocale(this.locale,"__version__");"number"==typeof e&&await u.d.set("locale-version",e),await u.d.set("locale-lang",this.lang)})).catch((async t=>{console.error("[VOT] [localizationProvider] failed get locale, cause:",t),this.setLocaleFromJsonString(await u.d.get("locale-phrases",""))})))}setLocaleFromJsonString(t){try{this.locale=JSON.parse(t)??{}}catch(t){console.error("[VOT] [localizationProvider]",t),this.locale={}}}getFromLocale(t,e){const o=e.split(".").reduce(((t,e)=>{if("object"==typeof t&&t)return t[e]}),t);return void 0===o&&console.warn("[VOT] [localizationProvider] locale",t,"doesn't contain key",e),o}getDefault(t){return this.getFromLocale(d,t)??t}get(t){return this.getFromLocale(this.locale,t)??this.getFromLocale(d,t)??t}};var g=o("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"),v=o.n(g),m=o("./node_modules/style-loader/dist/runtime/styleDomAPI.js"),b=o.n(m),f=o("./node_modules/style-loader/dist/runtime/insertBySelector.js"),y=o.n(f),w=o("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"),x=o.n(w),S=o("./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js"),k=o.n(S),T=o("./node_modules/style-loader/dist/runtime/styleTagTransform.js"),V=o.n(T),M=o("./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss"),L={};L.styleTagTransform=V(),L.setAttributes=x(),L.insert=y().bind(null,"head"),L.domAPI=b(),L.insertStyleElement=k();v()(M.A,L);M.A&&M.A.locals&&M.A.locals;function A(t){const e=document.createElement("vot-block");return e.classList.add("vot-icon-button"),e.innerHTML=t,e}function P(t){const e=parseFloat(t.value),o=""===t.min?0:parseFloat(t.min),n=(e-o)/((""===t.max?100:parseFloat(t.max))-o);t.parentElement.setAttribute("style",`--vot-progress: ${n}`)}function O(t,e="",o=" ",n=!1){const a=document.createElement("vot-block");a.classList.add("vot-textfield");const i=document.createElement(n?"textarea":"input");i.placeholder=o,i.value=e;const r=document.createElement("span");return r.innerHTML=t,a.appendChild(i),a.appendChild(r),{container:a,input:i,label:r}}function E(t){const e=document.createElement("vot-block");e.classList.add("vot-dialog-container"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-dialog-backdrop");const n=document.createElement("vot-block");n.classList.add("vot-dialog");const a=document.createElement("vot-block");a.classList.add("vot-dialog-content-wrapper");const i=document.createElement("vot-block");i.classList.add("vot-dialog-header-container");const r=document.createElement("vot-block");r.classList.add("vot-dialog-body-container");const s=document.createElement("vot-block");s.classList.add("vot-dialog-footer-container");const l=document.createElement("vot-block");l.classList.add("vot-dialog-title-container");const d=A('');d.classList.add("vot-dialog-close-button"),o.onclick=d.onclick=()=>{e.hidden=!0};const c=document.createElement("vot-block");return c.classList.add("vot-dialog-title"),c.innerHTML=t,e.appendChild(o),e.appendChild(n),n.appendChild(a),a.appendChild(i),a.appendChild(r),a.appendChild(s),i.appendChild(l),i.appendChild(d),l.appendChild(c),{container:e,backdrop:o,dialog:n,contentWrapper:a,headerContainer:i,bodyContainer:r,footerContainer:s,titleContainer:l,closeButton:d,title:c}}function C(t,e,o,n={}){const a=n.onSelectCb||function(){},i=n.labelElement||"";let r=[];const s=document.createElement("vot-block");s.classList.add("vot-select"),i&&s.appendChild(i);const l=document.createElement("vot-block");l.classList.add("vot-select-outer");const d=document.createElement("span");d.classList.add("vot-select-title"),d.innerText=t,void 0===t&&(d.innerText=o.find((t=>!0===t.selected))?.label);const c=document.createElement("vot-block");c.classList.add("vot-select-arrow-icon"),c.innerHTML='',l.append(d,c),l.onclick=()=>{const t=E(e);t.container.classList.add("vot-dialog-temp"),t.container.hidden=!1,document.documentElement.appendChild(t.container);const n=document.createElement("vot-block");n.classList.add("vot-select-content-list");for(const t of o){const e=document.createElement("vot-block");e.classList.add("vot-select-content-item"),e.innerText=t.label,e.dataset.votSelected=t.selected,e.dataset.votValue=t.value,t.disabled&&(e.inert=!0),e.onclick=async i=>{if(i.target.inert)return;n.childNodes.forEach((t=>t.dataset.votSelected=!1)),o.forEach((e=>e.selected=e.value===t.value)),e.dataset.votSelected=!0,d.innerText=t.label,await a(i)},n.appendChild(e)}const i=O(p.get("searchField"));i.input.oninput=t=>{const e=t.target.value.toLowerCase();Array.from(r).forEach((t=>t.hidden=!t.innerText.toLowerCase().includes(e)))},t.bodyContainer.append(i.container,n),r=n.childNodes,t.backdrop.onclick=t.closeButton.onclick=()=>{t.container.remove(),r=[]}},s.append(l);return{container:s,title:d,arrowIcon:c,labelElement:i,setTitle:t=>{d.innerText=t},setSelected:t=>{Array.from(r).filter((t=>!t.inert)).forEach((e=>e.dataset.votSelected=e.dataset.votValue===t)),o.forEach((e=>e.selected=String(e.value)===t))},updateItems:t=>{o=t}}}const B={createHeader:function(t,e=4){const o=document.createElement("vot-block");return o.classList.add("vot-header"),o.classList.add(`vot-header-level-${e}`),o.innerHTML=t,o},createInformation:function(t,e){const o=document.createElement("vot-block");o.classList.add("vot-info");const n=document.createElement("vot-block");n.innerHTML=t;const a=document.createElement("vot-block");return a.innerHTML=e,o.appendChild(n),o.appendChild(a),{container:o,header:n,value:a}},createButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-button"),e.innerHTML=t,e},createTextButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-text-button"),e.innerHTML=t,e},createOutlinedButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-outlined-button"),e.innerHTML=t,e},createIconButton:A,createCheckbox:function(t,e=!1){const o=document.createElement("label");o.classList.add("vot-checkbox");const n=document.createElement("input");n.type="checkbox",n.checked=Boolean(e);const a=document.createElement("span");return a.innerHTML=t,o.appendChild(n),o.appendChild(a),{container:o,input:n,label:a}},createSlider:function(t,e=50,o=0,n=100){const a=document.createElement("vot-block");a.classList.add("vot-slider");const i=document.createElement("input");i.type="range",i.min=o,i.max=n,i.value=e;const r=document.createElement("span");return r.innerHTML=t,a.appendChild(i),a.appendChild(r),i.addEventListener("input",(t=>P(t.target))),P(i),{container:a,input:i,label:r}},createTextfield:O,createDialog:E,createVOTButton:function(t){const e=document.createElement("vot-block");e.classList.add("vot-segmented-button");const o=document.createElement("vot-block");o.classList.add("vot-segment"),o.classList.add("vot-translate-button"),o.innerHTML='';const n=document.createElement("vot-block");n.classList.add("vot-separator");const a=document.createElement("vot-block");a.classList.add("vot-segment-only-icon"),a.innerHTML='';const i=document.createElement("vot-block");i.classList.add("vot-separator");const r=document.createElement("vot-block");r.classList.add("vot-segment-only-icon"),r.innerHTML='';const s=document.createElement("span");return s.classList.add("vot-segment-label"),s.innerHTML=t,e.appendChild(o),e.appendChild(n),e.appendChild(a),e.appendChild(i),e.appendChild(r),o.appendChild(s),{container:e,translateButton:o,separator:n,pipButton:a,separator2:i,menuButton:r,label:s}},createVOTMenu:function(t){const e=document.createElement("vot-block");e.classList.add("vot-menu"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-menu-content-wrapper");const n=document.createElement("vot-block");n.classList.add("vot-menu-header-container");const a=document.createElement("vot-block");a.classList.add("vot-menu-body-container");const i=document.createElement("vot-block");i.classList.add("vot-menu-footer-container");const r=document.createElement("vot-block");r.classList.add("vot-menu-title-container");const s=document.createElement("vot-block");return s.classList.add("vot-menu-title"),s.innerHTML=t,e.appendChild(o),o.appendChild(n),o.appendChild(a),o.appendChild(i),n.appendChild(r),r.appendChild(s),{container:e,contentWrapper:o,headerContainer:n,bodyContainer:a,footerContainer:i,titleContainer:r,title:s}},createVOTSelectLabel:function(t){const e=document.createElement("span");return e.classList.add("vot-select-label"),e.innerText=t,e},createVOTSelect:C,createVOTLanguageSelect:function(t){const e=t.fromTitle||"#UNDEFINED",o=t.fromDialogTitle||"#UNDEFINED",n=t.fromItems||[],a=t.fromOnSelectCB||function(){},i=t.toTitle||"#UNDEFINED",r=t.toDialogTitle||"#UNDEFINED",s=t.toItems||[],l=t.toOnSelectCB||function(){},d=document.createElement("vot-block");d.classList.add("vot-lang-select");const c=C(e,o,n,{onSelectCb:a}),u=document.createElement("vot-block");u.classList.add("vot-lang-select-icon"),u.innerHTML='';const h=C(i,r,s,{onSelectCb:l});return d.append(c.container,u,h.container),{container:d,fromSelect:c,icon:u,toSelect:h}},updateSlider:P};class F extends Error{constructor(t){super(p.getDefault(t)),this.name="VOTLocalizedError",this.unlocalizedMessage=t,this.localizedMessage=p.get(t)}}async function _(t,e){const o=new AbortController,n=setTimeout((()=>o.abort()),3e3);try{return await fetch(t,{...e,signal:o.signal})}catch(t){return console.error("Fetch timed-out. Error:",t),t}finally{clearTimeout(n)}}const R={async translate(t,e){try{const o=await _(i.rw.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.text[0]}catch(e){return console.error("Error translating text:",e),t}},async detect(t,e){try{const o=await _(i.QL.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.lang??"en"}catch(t){return console.error("Error translating text:",t),"en"}}},q={async detect(t){try{const e=await fetch(i.QL.rustServer,{method:"POST",body:t});if(e instanceof Error)throw e;return await e.text()}catch(t){return console.error("Error getting lang from text:",t),"en"}}};const D=["yandex"],z=["yandex","rust-server"];async function I(t,e,o,n){if(!window.location.hostname.includes("m.youtube.com")&&t?.getAudioTrack){const e=t.getAudioTrack(),o=e?.getLanguageInfo();if("und"!==o?.id)return Z(o.id.split(".")[0])}const a=e?.captions?.playerCaptionsTracklistRenderer?.captionTracks;if(a?.length){const t=a.find((t=>"asr"===t.kind));if(t&&t.languageCode)return Z(t.languageCode)}const r=[/(?:https?|ftp):\/\/[\S]+/g,/https?:\/\/\S+|www\.\S+/gm,/\b\S+\.\S+/gm,/#[^\s#]+/g,/Auto-generated by YouTube/g,/Provided to YouTube by/g,/Released on/g,/Bitcoin/g,/USDT/g,/Paypal/g],s=[o,n.split("\n\n").filter((t=>!r.some((e=>e.test(t))))).join("\n\n")].join(" ").replace(/[^\p{L}\s]/gu," ").trim().replace(/\s+/g," ").slice(0,1e3);return await async function(t){switch(await u.d.get("detectService",i.K2)){case"yandex":return await R.detect(t);case"rust-server":return await q.detect(t);default:return"en"}}(s)}function $(){return/^m\.youtube\.com$/.test(window.location.hostname)}function N(){return window.location.pathname.startsWith("/shorts/")?$()?document.querySelector("#movie_player"):document.querySelector("#shorts-player"):document.querySelector("#movie_player")}function H(){const t=N();return t?.getPlayerResponse?t?.getPlayerResponse?.call()??null:t?.data?.playerResponse??null}function j(){const t=N();return t?.getVideoData?t?.getVideoData?.call()??null:t?.data?.playerResponse?.videoDetails??null}const U={isMobile:$,getPlayer:N,getPlayerResponse:H,getPlayerData:j,getVideoVolume:function(){const t=N();return t?.getVolume?t.getVolume.call()/100:1},getSubtitles:function(){const t=H();let e=t?.captions?.playerCaptionsTracklistRenderer?.captionTracks??[];return e=e.reduce(((t,e)=>{if("languageCode"in e){const o=e?.languageCode?Z(e?.languageCode):void 0,n=e?.url||e?.baseUrl;o&&n&&t.push({source:"youtube",language:o,isAutoGenerated:"asr"===e?.kind,url:`${n.startsWith("http")?n:`${window.location.origin}/${n}`}&fmt=json3`})}return t}),[]),c.A.log("youtube subtitles:",e),e},getVideoData:async function(){const t=N(),e=H(),o=j(),{title:n}=o??{},{shortDescription:a,isLive:i,isLiveContent:s,isUpcoming:l}=e?.videoDetails??{},d=!(!i&&!l||s);let u=await I(t,e,n,a);r.includes(u)||(u="en");const h={isLive:!!i,isPremiere:d,title:n,description:a,detectedLanguage:u};return c.A.log("youtube video data:",h),console.log("[VOT] Detected language: ",h.detectedLanguage),h},setVideoVolume:function(t){const e=N();if(e?.setVolume)return e.setVolume(Math.round(100*t)),!0},videoSeek:function(t,e){c.A.log("videoSeek",e);const o=(N()?.getProgressState()?.seekableEnd||t.currentTime)-e;t.currentTime=o}},W=navigator.language||navigator.userLanguage,G=W?.substr(0,2)?.toLowerCase()??"en",Y=(t,e)=>{let o=new URL(window.location.href);switch(t){case"piped":case"invidious":case"youtube":if(o.searchParams.has("enablejsapi")){const t=U.getPlayer().getVideoUrl();o=new URL(t)}return o.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1]||o.searchParams.get("v");case"vk":return o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)?o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1):o.searchParams.get("z")?o.searchParams.get("z").split("/")[0]:!(!o.searchParams.get("oid")||!o.searchParams.get("id"))&&`video-${Math.abs(o.searchParams.get("oid"))}_${o.searchParams.get("id")}`;case"nine_gag":case"9gag":case"gag":return o.pathname.match(/gag\/([^/]+)/)?.[1];case"twitch":if(/^m\.twitch\.tv$/.test(window.location.hostname)){const t=document.head.querySelector('link[rel="canonical"]');return t?.href.match(/videos\/([^/]+)/)?.[0]||o.pathname.slice(1)}if(/^player\.twitch\.tv$/.test(window.location.hostname))return`videos/${o.searchParams.get("video")}`;if(/^clips\.twitch\.tv$/.test(window.location.hostname)){const t=document.querySelector(".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']");if(!t)return!1;return`${t.href.replace("https://www.twitch.tv/","")}/clip/${o.searchParams.get("clip")}`}return o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)?o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]:o.pathname.match(/(?:videos)\/([^/]+)/)?.[0];case"proxytok":return o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];case"tiktok":{let t=o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];if(!t){const o=e.closest(".xgplayer-playing, .tiktok-web-player"),n=o?.closest('div[data-e2e="recommend-list-item-container"]'),a=n?.querySelector('a[data-e2e="video-author-avatar"]');if(o&&a){const e=o.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1),n=a.href?.match(/.*(@.*)$/)?.at(1);e&&n&&(t=`${n}/video/${e}`)}}return t}case"vimeo":{const t=o.searchParams.get("app_id"),e=o.pathname.match(/[^/]+\/[^/]+$/)?.[0]||o.pathname.match(/[^/]+$/)?.[0];return t?`${e}?app_id=${t}`:e}case"xvideos":return o.pathname.match(/[^/]+\/[^/]+$/)?.[0];case"pornhub":return o.searchParams.get("viewkey")||o.pathname.match(/embed\/([^/]+)/)?.[1];case"twitter":return o.pathname.match(/status\/([^/]+)/)?.[1];case"udemy":case"rumble":case"facebook":return o.pathname;case"rutube":return o.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1];case"coub":return o.pathname.includes("/view")?o.pathname.match(/view\/([^/]+)/)?.[1]:o.pathname.includes("/embed")?o.pathname.match(/embed\/([^/]+)/)?.[1]:document.querySelector(".coub.active")?.dataset?.permalink;case"bilibili":{const t=o.searchParams.get("bvid");if(t)return t;{let t=o.pathname.match(/video\/([^/]+)/)?.[1];return t&&o.search&&null!==o.searchParams.get("p")&&(t+=`/?p=${o.searchParams.get("p")}`),t}}case"mail_ru":if(o.pathname.startsWith("/v/")||o.pathname.startsWith("/mail/"))return o.pathname;if(o.pathname.match(/video\/embed\/([^/]+)/)){const t=document.querySelector(".b-video-controls__mymail-link");return!!t&&t?.href.split("my.mail.ru")?.[1]}return!1;case"bitchute":return o.pathname.match(/video\/([^/]+)/)?.[1];case"coursera":return o.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0];case"eporner":return o.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0];case"peertube":return o.pathname.match(/\/w\/([^/]+)/)?.[0];case"dailymotion":{const t=Array.from(document.querySelectorAll("*")).filter((t=>t.innerHTML.trim().includes(".m3u8")));try{let e=t[1].lastChild.src;return e.match(/\/video\/(\w+)\.m3u8/)?.[1]}catch(t){return console.error("[VOT]",t),!1}}case"trovo":{if(!o.pathname.startsWith("/s/"))return!1;const t=o.searchParams.get("vid");if(!t)return!1;const e=o.pathname.match(/([^/]+)\/([\d]+)/)?.[0];return!!e&&`${e}?vid=${t}`}case"yandexdisk":return o.pathname.match(/\/i\/([^/]+)/)?.[1];case"coursehunter":{const t=o.pathname.match(/\/course\/([^/]+)/)?.[1];return!!t&&t+o.search}case"ok.ru":return o.pathname.match(/\/video\/(\d+)/)?.[0];case"googledrive":return o.searchParams.get("docid");case"bannedvideo":return o.searchParams.get("id");case"weverse":return o.pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[0];case"newgrounds":return o.pathname.match(/([^/]+)\/(view)\/([^/]+)/)?.[0];case"egghead":return o.pathname;case"youku":return o.pathname.match(/v_show\/id_[\w=]+/)?.[0];default:return!1}};function Z(t){return t.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]}function K(){return"pictureInPictureEnabled"in document&&document.pictureInPictureEnabled}function J(){return"undefined"!=typeof Hls&&Hls?.isSupported()?new Hls({debug:!1,lowLatencyMode:!0,backBufferLength:90}):void 0}function Q(t,e,o,n){let a=e;return e>n?(a=o+(e-n),a=a>100?100:Math.max(a,0),t.volume=a/100):e100?100:Math.max(a,0),t.volume=a/100),a}const X=new protobuf.Type("VideoTranslationHelpObject").add(new protobuf.Field("target",1,"string")).add(new protobuf.Field("targetUrl",2,"string")),tt=new protobuf.Type("VideoTranslationRequest").add(new protobuf.Field("url",3,"string")).add(new protobuf.Field("deviceId",4,"string")).add(new protobuf.Field("firstRequest",5,"bool")).add(new protobuf.Field("duration",6,"double")).add(new protobuf.Field("unknown2",7,"int32")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("unknown3",9,"int32")).add(new protobuf.Field("unknown4",10,"int32")).add(new protobuf.Field("translationHelp",11,"VideoTranslationHelpObject","repeated")).add(new protobuf.Field("responseLanguage",14,"string")).add(new protobuf.Field("unknown5",15,"int32")).add(new protobuf.Field("unknown6",16,"int32")).add(new protobuf.Field("unknown7",17,"int32")),et=new protobuf.Type("VideoSubtitlesRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")),ot=new protobuf.Type("VideoStreamRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")).add(new protobuf.Field("responseLanguage",3,"string")),nt=new protobuf.Type("VideoStreamPingRequest").add(new protobuf.Field("pingId",1,"int32")),at=new protobuf.Type("VideoTranslationResponse").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("duration",2,"double")).add(new protobuf.Field("status",4,"int32")).add(new protobuf.Field("remainingTime",5,"int32")).add(new protobuf.Field("unknown0",6,"int32")).add(new protobuf.Field("unknown1",7,"string")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("message",9,"string")),it=new protobuf.Type("VideoSubtitlesObject").add(new protobuf.Field("language",1,"string")).add(new protobuf.Field("url",2,"string")).add(new protobuf.Field("unknown2",3,"int32")).add(new protobuf.Field("translatedLanguage",4,"string")).add(new protobuf.Field("translatedUrl",5,"string")).add(new protobuf.Field("unknown5",6,"int32")).add(new protobuf.Field("unknown6",7,"int32")),rt=new protobuf.Type("VideoSubtitlesResponse").add(new protobuf.Field("unknown0",1,"int32")).add(new protobuf.Field("subtitles",2,"VideoSubtitlesObject","repeated")),st=new protobuf.Type("VideoStreamObject").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("timestamp",2,"int64")),lt=new protobuf.Type("VideoStreamResponse").add(new protobuf.Field("interval",1,"int32")).add(new protobuf.Field("translatedInfo",2,"VideoStreamObject")).add(new protobuf.Field("pingId",3,"int32")),dt=(new protobuf.Root).define("yandex").add(X).add(tt).add(at).add(et).add(it).add(rt).add(nt).add(ot).add(st).add(lt),ct={encodeTranslationRequest:(t,e,o,n,a)=>dt.VideoTranslationRequest.encode({url:t,firstRequest:!0,duration:e,unknown2:1,language:o,unknown3:0,unknown4:0,translationHelp:a,responseLanguage:n,unknown5:0,unknown6:1,unknown7:0}).finish(),decodeTranslationResponse:t=>dt.VideoTranslationResponse.decode(new Uint8Array(t)),encodeSubtitlesRequest:(t,e)=>dt.VideoSubtitlesRequest.encode({url:t,language:e}).finish(),decodeSubtitlesResponse:t=>dt.VideoSubtitlesResponse.decode(new Uint8Array(t)),encodeStreamPingRequest:t=>dt.VideoStreamPingRequest.encode({pingId:t}).finish(),encodeStreamRequest:(t,e,o)=>dt.VideoStreamRequest.encode({url:t,language:e,responseLanguage:o}).finish(),decodeStreamResponse:t=>dt.VideoStreamResponse.decode(new Uint8Array(t))};var ut=o("./node_modules/bowser/es5.js");function ht(t){const e=([1e7]+1e3+4e3+8e3+1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)));return t?e:e.toUpperCase()}async function pt(t){const e=new TextEncoder("utf-8"),o=await window.crypto.subtle.importKey("raw",e.encode(i.S7),{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign","verify"]),n=await window.crypto.subtle.sign("HMAC",o,t);return Array.from(new Uint8Array(n),(t=>t.toString(16).padStart(2,"0"))).join("")}const gt=async function(t,e){try{c.A.log("requestStreamPing");const n=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;c.A.log("Inited yandexRequest...");const a=ct.encodeStreamPingRequest(t);await n("/stream-translation/ping-stream",a,{"Vtrans-Signature":await pt(a),"Sec-Vtrans-Token":ht(!1)},e)}catch(t){console.error("[VOT]",t),e(!1)}};const vt=async function(t,e,n,a){try{c.A.log("requestStreamTranslation");const i=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;c.A.log("Inited yandexRequest...");const r=ct.encodeStreamRequest(t,e,n);await i("/stream-translation/translate-stream",r,{"Vtrans-Signature":await pt(r),"Sec-Vtrans-Token":ht(!1)},a)}catch(t){console.error("[VOT]",t),a(!1)}};const mt=async function(t,e,n,a,i,r){try{c.A.log("requestVideoTranslation");const s=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;c.A.log("Inited yandexRequest...");const l=ct.encodeTranslationRequest(t,e,n,a,i);await s("/video-translation/translate",l,{"Vtrans-Signature":await pt(l),"Sec-Vtrans-Token":ht(!1)},r)}catch(t){console.error("[VOT]",t),r(!1)}};const bt=async function(t,e,n){try{c.A.log("requestVideoSubtitles");const a=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest-cloudflare.js"))).default;c.A.log("Inited yandexRequest...");const i=ct.encodeSubtitlesRequest(t,e);await a("/video-subtitles/get-subtitles",i,{"Vsubs-Signature":await pt(i),"Sec-Vsubs-Token":ht(!1)},n)}catch(t){console.error("[VOT]",t),n(!1)}};function ft(t){const e=t.startMs+t.durationMs;return t.tokens.reduce(((o,n,a)=>{const i=t.tokens[a+1];let r;o.length>0&&(r=o[o.length-1]);const s=r?.alignRange?.end??0,l=s+n.text.length;if(n.alignRange={start:s,end:l},o.push(n),i){const t=n.startMs+n.durationMs,a=i.startMs?i.startMs-t:e-t;o.push({text:" ",startMs:t,durationMs:a,alignRange:{start:l,end:l+1}})}return o}),[])}function yt(t,e){const o=t.text.split(/([\n \t])/).reduce(((t,o)=>{if(o.length){const n=t[t.length-1]??e,a=n?.alignRange?.end??0,i=a+o.length;t.push({text:o,alignRange:{start:a,end:i}})}return t}),[]),n=Math.floor(t.durationMs/o.length),a=t.startMs+t.durationMs;return o.map(((e,i)=>{const r=i===o.length-1,s=t.startMs+n*i;return{...e,startMs:s,durationMs:r?a-s:n}}))}async function wt(t){let e=!1,o=await Promise.race([new Promise((t=>{setTimeout((()=>{e||(console.error("[VOT] Failed to fetch subtitles. Reason: timeout"),t([]))}),5e3)})),new Promise((o=>{c.A.log("Fetching subtitles:",t),fetch(t.url).then((t=>t.json())).then((t=>{e=!0,o(t)})).catch((t=>{console.error("[VOT] Failed to fetch subtitles. Reason:",t),e=!0,o({containsTokens:!1,subtitles:[]})}))}))]);return"youtube"===t.source&&(o=function(t){const e={containsTokens:!1,subtitles:[]};if("object"!=typeof t||!("events"in t)||!Array.isArray(t.events))return console.error("[VOT] Failed to format youtube subtitles",t),e;for(let o=0;ot.utf8.replace(/^ +| +$/g,""))).join(" ");let a=t.events[o].dDurationMs;t.events[o+1]&&t.events[o].tStartMs+t.events[o].dDurationMs>t.events[o+1].tStartMs&&(a=t.events[o+1].tStartMs-t.events[o].tStartMs),"\n"!==n&&e.subtitles.push({text:n,startMs:t.events[o].tStartMs,durationMs:a})}return e}(o)),o.subtitles=function(t,e){const o=[];let n;for(const a of t.subtitles){let i;if(a?.tokens?.length){if("yandex"!==e)return console.warn("[VOT] Unsupported subtitles tokens type: ",e),t.containsTokens=!1,null;i=ft(a)}else i=yt(a,n);n=i[i.length-1],o.push({...a,tokens:i})}return t.containsTokens=!0,o}(o,t.source),console.log("[VOT] subtitles:",o),o}class xt{dragging=!1;subtitlesContainerRect=null;containerRect=null;offsetX=null;offsetY=null;lastContent=null;highlightWords=!1;subtitles=null;maxLength=300;maxLengthRegexp=/.{1,300}(?:\s|$)/g;constructor(t,e,o){this.site=o,this.video=t,"youtube"===this.site.host&&"mobile"!==this.site.additionalData?this.container=e.parentElement:this.container=e,this.votSubtitlesContainer=document.createElement("vot-block"),this.votSubtitlesContainer.classList.add("vot-subtitles-widget"),this.container.appendChild(this.votSubtitlesContainer),this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onMouseMoveBound=this.onMouseMove.bind(this),this.onTimeUpdateBound=this.onTimeUpdate.bind(this),document.addEventListener("mousedown",this.onMouseDownBound),document.addEventListener("mouseup",this.onMouseUpBound),document.addEventListener("mousemove",this.onMouseMoveBound),this.video?.addEventListener("timeupdate",this.onTimeUpdateBound)}release(){this.video?.removeEventListener("timeupdate",this.onTimeUpdateBound),document.removeEventListener("mousedown",this.onMouseDownBound),document.removeEventListener("mouseup",this.onMouseUpBound),document.removeEventListener("mousemove",this.onMouseMoveBound),this.votSubtitlesContainer.remove()}onMouseDown(t){this.votSubtitlesContainer.contains(t.target)&&(this.subtitlesContainerRect=this.votSubtitlesContainer.getBoundingClientRect(),this.containerRect=this.container.getBoundingClientRect(),this.offsetX=t.clientX-this.subtitlesContainerRect.x,this.offsetY=t.clientY-this.subtitlesContainerRect.y,this.dragging=!0)}onMouseUp(){this.dragging=!1}onMouseMove(t){if(this.dragging){t.preventDefault();const e=t.clientX-this.offsetX,o=t.clientY-this.offsetY,n=o>=this.containerRect.top,a=o+this.subtitlesContainerRect.height<=this.containerRect.bottom,i=e>=this.containerRect.left,r=e+this.subtitlesContainerRect.width<=this.containerRect.right;this.votSubtitlesContainer.style.top=n&&a?o-this.containerRect.y+"px":n?this.containerRect.height-this.subtitlesContainerRect.height+"px":"0px",this.votSubtitlesContainer.style.left=i&&r?e-this.containerRect.x+"px":i?this.containerRect.width-this.subtitlesContainerRect.width+"px":"0px"}}onTimeUpdate(){this.update()}setContent(t){t&&this.video?(this.subtitles=t,this.update()):(this.subtitles=null,this.votSubtitlesContainer.innerHTML="")}setMaxLength(t){"number"==typeof t&&t&&(this.maxLength=t,this.maxLengthRegexp=new RegExp(`.{1,${t}}(?:\\s|$)`,"g"),this.update())}setHighlightWords(t){this.highlightWords!==!!t&&(this.highlightWords=!!t,this.update())}update(){if(!this.video)return;let t="",e=this.highlightWords&&this.subtitles?.containsTokens;const o=1e3*this.video.currentTime,n=this.subtitles?.subtitles?.findLast((t=>t.startMsthis.maxLength){let t=[],n=0,a=0,i=0;for(let o=0;othis.maxLength){let r=e.slice(n,a+1);r.at(0)&&" "===r.at(0).text&&(r=r.slice(1)),r.at(-1)&&" "===r.at(-1).text&&(r=r.slice(0,r.length-1)),t.push({startMs:e[n].startMs,durationMs:e[a].startMs+e[a].durationMs-e[n].startMs,tokens:r}),n=o,i=0}a=o}for(const n of t)if(n.startMse||o>n.startMs-100&&e-o<275?'class="passed"':""}>${n.text}`}}else if(n.text.length>this.maxLength){let e=n.text.match(this.maxLengthRegexp),a=n.durationMs/e.length;for(let i=0;i${t.replace("\\n","
")}`:"")}}const St={getVideoData:async function(){const t=window.course_id??document.querySelector('input[name="course_id"]')?.value,e=window.lessons??await async function(t){const e=await fetch(`https://coursehunter.net/api/v1/course/${t}/lessons`);return await e.json()}(t),o=parseInt(document.querySelector(".lessons-item_active")?.dataset?.index??1),n=e?.[o-1],{file:a,duration:i}=n;return c.A.log("coursehunter course data:",e),{url:a,duration:i}}};function kt(){return Tt()?.player}function Tt(){return document.querySelector(".vjs-v6")}const Vt={getPlayer:Tt,getPlayerData:kt,getVideoData:async function(t="en"){let e=null;const o=kt(),{duration:n}=o?.cache_||{},{courseId:a,tracks:i,sources:s}=o?.options_||{},l=function(t){const e=t?.find((t=>"video/mp4"===t.type));return e?.src}(s),d=await async function(t){const e=await fetch(`https://www.coursera.org/api/onDemandCourses.v1/${t}`),o=await e.json();return o?.elements?.[0]}(a);let u=d?.primaryLanguageCodes?.[0];u=u?Z(u):"en",r.includes(u)||(u="en");const h=function(t,e,o){let n=t?.find((t=>Z(t.srclang)===e));return n||(n=t?.find((t=>Z(t.srclang)===o))||t?.[0]),n?.src}(i,u,t);console.log(`videoURL: ${l}, subtitlesURL: ${h}`),h&&l?e=[{target:"video_file_url",targetUrl:l},{target:"subtitles_file_url",targetUrl:`https://www.coursera.org${h}`}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${l}, subtitlesURL: ${h}`);const p={duration:n,detectedLanguage:u,translationHelp:e};return c.A.log("coursera video data:",p),console.log("[VOT] Detected language: ",p.detectedLanguage),p}},Mt="https://www.udemy.com/api-2.0",Lt=2592e6;async function At(t){const e=await fetch(`${Mt}/courses/${t}/?`+new URLSearchParams({"fields[course]":"locale",use_remote_version:"true",caching_intent:"true"}));return await e.json()}async function Pt(t,e,o){if(!(n=t.expires,n+Lt>(new Date).getTime()&&t.accessToken))return void console.error(p.get("udemyAccessTokenExpired"));var n;const a=`Bearer ${t.accessToken}`,i=await fetch(`${Mt}/users/me/subscribed-courses/${e}/lectures/${o}/?`+new URLSearchParams({"fields[lecture]":"asset","fields[asset]":"length,media_sources,captions"}),{headers:{"x-udemy-authorization":a,authorization:a}});return await i.json()}function Ot(){return Ct()?.player}function Et(){const t=document.querySelector(".ud-app-loader[data-module-id='course-taking']")?.dataset?.moduleArgs;return t?JSON.parse(t):(console.error(p.get("udemyModuleArgsNotFound")),{})}function Ct(){return document.querySelector(".vjs-v7")}const Bt={getPlayer:Ct,getPlayerData:Ot,getVideoData:async function(t,e="en"){let o=null;const n=Ot();c.A.log("udemyData",t);const a=Et();c.A.log("moduleData: ",a);const i=a.courseId,s=window.location.pathname.match(/learn\/lecture\/([^/]+)/)?.[1];c.A.log(`CourseId: ${i}, lectureId: ${s}`);const l=await At(i);c.A.log("courseLang Data:",l);const d=await Pt(t,i,s);console.log("lecture Data:",d);let u=l?.locale?.locale;u=u?Z(u):"en",r.includes(u)||(u="en");const h=d?.asset?.length||n?.cache_?.duration,p=function(t){const e=t?.find((t=>"video/webm"===t.type||"video/mp4"===t.type));return e?.src}(d?.asset?.media_sources)||function(){const t=Ct()?.querySelector("video")?.src;return!t?.startsWith("blob:")&&t}(),g=function(t,e,o){let n=t?.find((t=>Z(t.locale_id)===e));return n||(n=t?.find((t=>Z(t.locale_id)===o))||t?.[0]),n?.url}(d?.asset?.captions,u,e);console.log(`videoURL: ${p}, subtitlesURL: ${g}`),g&&p?o=[{target:"video_file_url",targetUrl:p},{target:"subtitles_file_url",targetUrl:g}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${p}, subtitlesURL: ${g}`);const v={duration:h,detectedLanguage:u,translationHelp:o};return c.A.log("udemy video data:",v),console.log("[VOT] Detected language: ",v.detectedLanguage),v},getModuleData:Et,getCourseLang:At,getLectureData:Pt};const Ft={getVideoData:async function(t){const e=await async function(t){return await fetch("https://api.banned.video/graphql",{method:"POST",body:JSON.stringify({operationName:"GetVideo",query:"query GetVideo($id: String!) {\n getVideo(id: $id) {\n ...DisplayVideoFields\n videoUrl: directUrl\n live\n }\n }\n\n fragment DisplayVideoFields on Video {\n title\n description: summary\n duration: videoDuration\n }",variables:{id:t}}),headers:{"User-Agent":"bannedVideoFrontEnd","apollographql-client-name":"banned-web","apollographql-client-version":"1.3","content-type":"application/json"}}).then((t=>t.json())).catch((t=>(console.error(t),{data:{getVideo:{}}})))}(t);c.A.log("banned.video video data:",e);const{videoUrl:o,duration:n,live:a,description:i,title:r}=e.data.getVideo;return{url:o,duration:n,live:a,title:r,description:i}}};const _t="https://global.apis.naver.com/weverse/wevweb",Rt="be4d79eb8fc7bd008ee82c8ec4ff6fd4",qt="1b9cb6378d959b45714bec49971ade22e6e24e42";async function Dt(t){const e=Date.now();let o=t.substring(0,Math.min(255,t.length))+e;const n=await async function(t,e){const o=new TextEncoder("utf-8");return e=o.encode(e),window.crypto.subtle.importKey("raw",o.encode(t),{name:"HMAC",hash:{name:"SHA-1"}},!1,["sign","verify"]).then((t=>window.crypto.subtle.sign("HMAC",t,e))).then((t=>btoa(String.fromCharCode(...new Uint8Array(t))))).catch((t=>(console.error(t),!1)))}(qt,o);return{wmsgpad:e,wmd:n}}function zt(){return{appId:Rt,language:"en",os:"WEB",platform:"WEB",wpf:"pc"}}const It={getVideoData:async function(){const t=new URL(window.location).pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[3],e=await async function(t){const e=`/post/v1.0/post-${t}/preview?`+new URLSearchParams({fieldSet:"postForPreview",...zt()}),o=await Dt(e);return await fetch(_t+e+"&"+new URLSearchParams(o)).then((t=>t.json())).catch((t=>(console.error(t),{extension:{video:{}}})))}(t);c.A.log("weverse video preview data:",e);const{videoId:o,serviceId:n,infraVideoId:a}=e.extension.video;if(!(o&&n&&a))return!1;const{inKey:i}=await async function(t){const e=`/video/v1.1/vod/${t}/inKey?`+new URLSearchParams({gcc:"RU",...zt()}),o=await Dt(e);return await fetch(_t+e+"&"+new URLSearchParams(o),{method:"POST"}).then((t=>t.json())).catch((t=>(console.error(t),{})))}(o);if(c.A.log("weverse video inKey data:",e),!i)return!1;const r=await async function(t,e,o){const n=Date.now();return await fetch(`https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${t}?`+new URLSearchParams({key:e,sid:o,nonce:n,devt:"html5_pc",prv:"N",aup:"N",stpb:"N",cpl:"en",env:"prod",lc:"en",adi:[{adSystem:null}],adu:"/"})).then((t=>t.json())).catch((t=>(console.error(t),{videos:{list:[]}})))}(a,i,n);c.A.log("weverse video data:",r);const s=r.videos.list.find((t=>!1===t.useP2P&&t.source.includes(".mp4")));if(!s)return!1;const{source:l,duration:d}=s;return{url:l,duration:d}}},$t=[{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:"shorts-video #player"},{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:".player-container"},{host:"youtube",url:"https://youtu.be/",match:/^(www.)?youtube(-nocookie|kids)?.com$/,selector:".html5-video-container:not(#inline-player *)"},{host:"tiktok",url:"https://www.tiktok.com/",match:/^(www.)?tiktok.com$/,selector:null},{host:"proxytok",url:"https://www.tiktok.com/",match:n,selector:".column.has-text-centered"},{additionalData:"mobile",host:"twitch",url:"https://twitch.tv/",match:/^m.twitch.tv$/,selector:"main > div > section > div > div > div"},{host:"twitch",url:"https://twitch.tv/",match:t=>t.host.includes("clips.twitch.tv")||t.host.includes("player.twitch.tv")&&null===t.searchParams.get("channel")||t.host.includes("twitch.tv")&&(t.pathname.startsWith("/videos")||t.pathname.startsWith("/embed")||t.pathname.includes("/clip")),selector:".video-ref"},{host:"xvideos",url:"https://www.xvideos.com/",match:/^www.xvideos.com$/,selector:".video-bg-pic"},{host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:/^[a-z]+.pornhub.com$/,selector:".mainPlayerDiv > .video-element-wrapper-js > div"},{additionalData:"embed",host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:t=>t.host.includes("pornhub.com")&&t.pathname.startsWith("/embed/"),selector:"#player"},{additionalData:"mobile",host:"vk",url:"https://vk.com/video?z=",match:/^m.vk.(com|ru)$/,selector:"vk-video-player",shadowRoot:!0},{host:"vk",url:"https://vk.com/video?z=",match:/^(www.|m.)?vk.(com|ru)$/,selector:".videoplayer_media"},{host:"vimeo",url:"https://vimeo.com/",match:/^vimeo.com$/,selector:".player"},{additionalData:"embed",host:"vimeo",url:"https://player.vimeo.com/",match:/^player.vimeo.com$/,selector:".player"},{host:"ok.ru",url:"https://ok.ru/",match:/^ok.ru$/,selector:".html5-vpl_vid"},{host:"nine_gag",url:"https://9gag.com/gag/",match:/^9gag.com$/,selector:".video-post"},{host:"coub",url:"https://coub.com/view/",match:/^coub.com$/,selector:".viewer__player"},{host:"bitchute",url:"https://www.bitchute.com/video/",match:/^(www.)?bitchute.com$/,selector:"#player"},{host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:".video-player > div > div > div:nth-child(2)"},{additionalData:"embed",host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:"#app > div > div"},{host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m|player).bilibili.com$/,selector:".bpx-player-video-wrap"},{additionalData:"old",host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m).bilibili.com$/,selector:null},{host:"twitter",url:"https://twitter.com/i/status/",match:/^twitter.com$/,selector:'div[data-testid="videoComponent"] > div:nth-child(1) > div'},{host:"mail_ru",url:"https://my.mail.ru/",match:/^my.mail.ru$/,selector:"#b-video-wrapper"},{host:"coursera",url:"https://www.coursera.org/",match:/coursera.org$/,selector:".vjs-v6"},{host:"udemy",url:"https://www.udemy.com",match:/udemy.com$/,selector:'div[data-purpose="curriculum-item-viewer-content"] > section > div > div > div > div:nth-of-type(2)'},{host:"invidious",url:"https://youtu.be/",match:t,selector:"#player"},{host:"piped",url:"https://youtu.be/",match:e,selector:".shaka-video-container"},{host:"rumble",url:"https://rumble.com",match:/^rumble.com$/,selector:"#videoPlayer > .videoPlayer-Rumble-cls > div"},{host:"eporner",url:"https://www.eporner.com/",match:/^(www.)?eporner.com$/,selector:".vjs-v7"},{host:"peertube",url:"tube.shanti.cafe",match:a,selector:".vjs-v7"},{host:"dailymotion",url:"https://www.dailymotion.com/video/",match:/^geo.dailymotion.com$/,selector:".player"},{host:"trovo",url:"https://trovo.live/s/",match:/^trovo.live$/,selector:".player-video"},{host:"yandexdisk",url:"https://disk.yandex.ru/i/",match:/^disk.yandex.ru$/,selector:"yaplayertag > div:nth-of-type(1)"},{host:"coursehunter",url:"https://coursehunter.net/course/",match:/^coursehunter.net$/,selector:"#oframeplayer > pjsdiv:nth-of-type(1)"},{host:"googledrive",url:"https://drive.google.com/file/d/",match:/^youtube.googleapis.com$/,selector:".html5-video-container"},{host:"bannedvideo",url:"https://banned.video/watch?id=",match:/^(www.)?banned.video$/,selector:".vjs-v7"},{host:"facebook",url:"https://facebook.com",match:t=>t.host.includes("facebook.com")&&t.pathname.includes("/videos/"),selector:'div[data-pagelet="WatchPermalinkVideo"]'},{additionalData:"reels",host:"facebook",url:"https://facebook.com",match:t=>t.host.includes("facebook.com")&&t.pathname.includes("/reel/"),selector:'div[role="main"]'},{host:"weverse",url:"https://weverse.io/",match:/^weverse.io$/,selector:".webplayer-internal-source-wrapper"},{host:"newgrounds",url:"https://www.newgrounds.com/",match:/^www.newgrounds.com$/,selector:".ng-video-player"},{host:"egghead",url:"https://egghead.io",match:/^egghead.io$/,selector:".cueplayer-react-video-holder"},{host:"youku",url:"https://v.youku.com/",match:/^v.youku.com$/,selector:"#ykPlayer"}];o("./node_modules/requestidlecallback-polyfill/index.js");class Nt{constructor(){this.listeners=new Set}hasListener(t){return this.listeners.has(t)}dispatchToListener(t,...e){try{t(...e)}catch(t){console.error("[VOT]",t)}}addListener(t){if(this.hasListener(t))throw new Error("[VOT] The listener has already been added.");this.listeners.add(t)}removeListener(t){if(!this.hasListener(t))throw new Error("[VOT] The listener has not been added yet.");this.listeners.delete(t)}dispatch(...t){for(const e of Array.from(this.listeners))this.dispatchToListener(e,...t)}}function Ht(t){return Array.from(t).flatMap((t=>t instanceof HTMLVideoElement?[t]:t instanceof HTMLElement?Array.from(t.querySelectorAll("video")):t.shadowRoot?Array.from(t.shadowRoot.querySelectorAll("video")):[]))}const jt=ut.getParser(window.navigator.userAgent).getResult(),Ut=[...t,...e],Wt=["playing","ratechange","play","waiting","pause"];function Gt(t,e,o=!1){return t.map((t=>({label:`${o&&!l.includes(t)?"❌ ":""}${p.get("langs")[t]??t.toUpperCase()}`,value:t,selected:e===t})))}var Yt=!1;function Zt(t,e,o,n,a,i){c.A.log(`Translate video (url: ${t}, duration: ${e}, requestLang: ${o}, responseLang: ${n})`),c.A.log("translationHelp:",a),Yt?c.A.log("translationPanding return"):(Yt=!0,mt(t,e,o,n,a,((t,e)=>{if(Yt=!1,c.A.log("[exec callback] Requesting video translation"),!t)return void i(!1,p.get("requestTranslationFailed"));const o=ct.decodeTranslationResponse(e);switch(console.log("[VOT] Translation response: ",o),o.status){case 0:i(!1,o.message);break;case 1:i(!!o.url,o.url||p.get("audioNotReceived"));break;case 2:i(!1,o.remainingTime?function(t){const e=Math.floor(t/60),o=Math.floor(t%60);return e>=60?p.get("translationTakeMoreThanHour"):e>=10&&e%10?p.get("translationTakeApproximatelyMinutes").replace("{0}",e):1==e||0==e&&o>0?p.get("translationTakeAboutMinute"):p.get("translationTakeApproximatelyMinute").replace("{0}",e)}(o.remainingTime):p.get("translationTakeFewMinutes"));break;case 3:case 6:i(!1,p.get("videoBeingTranslated"))}})))}class Kt{translateFromLang="en";translateToLang=G;timer;ytData="";videoData="";firstPlay=!0;audio=new Audio;hls=J();videoTranslations=[];videoTranslationTTL=7200;downloadTranslationUrl=null;downloadSubtitlesUrl=null;autoRetry;streamPing;volumeOnStart;tempOriginalVolume;tempVolume;subtitlesList=[];subtitlesListVideoId=null;videoLastSrcObject=null;constructor(t,e,o){c.A.log("[VideoHandler] add video:",t,"container:",e,this),this.video=t,this.container=e,this.site=o,this.handleSrcChangedBound=this.handleSrcChanged.bind(this),this.video.addEventListener("loadedmetadata",this.handleSrcChangedBound),this.stopTranslationBound=this.stopTranslation.bind(this),this.handleVideoEventBound=this.handleVideoEvent.bind(this),this.changeOpacityOnEventBound=this.changeOpacityOnEvent.bind(this),this.resetTimerBound=this.resetTimer.bind(this),this.init()}async init(){if(this.initialized)return;const t="uk"===G?1:0,e={autoTranslate:u.d.get("autoTranslate",0,!0),dontTranslateLanguage:u.d.get("dontTranslateLanguage",G),dontTranslateYourLang:u.d.get("dontTranslateYourLang",1,!0),autoSetVolumeYandexStyle:u.d.get("autoSetVolumeYandexStyle",1,!0),autoVolume:u.d.get("autoVolume",i.JD,!0),showVideoSlider:u.d.get("showVideoSlider",1,!0),syncVolume:u.d.get("syncVolume",0,!0),subtitlesMaxLength:u.d.get("subtitlesMaxLength",300,!0),highlightWords:u.d.get("highlightWords",0,!0),responseLanguage:u.d.get("responseLanguage",G),defaultVolume:u.d.get("defaultVolume",100,!0),udemyData:u.d.get("udemyData",{accessToken:"",expires:0}),audioProxy:u.d.get("audioProxy",t,!0),showPiPButton:u.d.get("showPiPButton",0,!0),translateAPIErrors:u.d.get("translateAPIErrors",1,!0),translationService:u.d.get("translationService",i.mE),detectService:u.d.get("detectService",i.K2),m3u8ProxyHost:u.d.get("m3u8ProxyHost",i.se),proxyWorkerHost:u.d.get("proxyWorkerHost",i.Pm)},o=await Promise.all(Object.entries(e).map((async([t,e])=>[t,await e])));this.data=Object.fromEntries(o),this.videoData=await this.getVideoData(),console.log("[db] data from db: ",this.data),this.subtitlesWidget=new xt(this.video,this.container,this.site),this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength),this.subtitlesWidget.setHighlightWords(this.data.highlightWords),this.initUI(),this.initUIEvents();const n=!this.video.src&&!this.video.currentSrc&&!this.video.srcObject;this.votButton.container.hidden=n,n&&(this.votMenu.container.hidden=!0),await this.updateSubtitles(),await this.changeSubtitlesLang("disabled"),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage??"ru"),this.translateToLang=this.data.responseLanguage??"ru",this.initExtraEvents(),this.initialized=!0}transformBtn(t="none",e){this.votButton.container.dataset.status=t,this.votButton.label.innerHTML=e}initUI(){this.votButton=B.createVOTButton(p.get("translateVideo")),this.container.appendChild(this.votButton.container),this.votButton.pipButton.hidden=!K()||!this.data?.showPiPButton,this.votButton.separator2.hidden=!K()||!this.data?.showPiPButton,this.votButton.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votMenu=B.createVOTMenu(p.get("VOTSettings")),this.container.appendChild(this.votMenu.container),this.votDownloadButton=B.createIconButton(''),this.votDownloadButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadButton),this.votDownloadSubtitlesButton=B.createIconButton(''),this.votDownloadSubtitlesButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadSubtitlesButton),this.votSettingsButton=B.createIconButton(''),this.votMenu.headerContainer.appendChild(this.votSettingsButton),this.votTranslationLanguageSelect=B.createVOTLanguageSelect({fromTitle:p.get("langs")[this.video.detectedLanguage],fromDialogTitle:p.get("videoLanguage"),fromItems:[{label:p.get("langs").auto,value:"auto",selected:""},...Gt(r,this.videoData.detectedLanguage)],fromOnSelectCB:async t=>{c.A.log("[fromOnSelectCB] select from language",t.target.dataset.votValue),this.videoData=await this.getVideoData(),this.setSelectMenuValues(t.target.dataset.votValue,this.videoData.responseLanguage)},toTitle:p.get("langs")[this.video.responseLanguage],toDialogTitle:p.get("translationLanguage"),toItems:[...Gt(r,this.videoData.responseLanguage,!0),{label:"─────────",value:"separator",disabled:!0},...Gt(s,this.videoData.responseLanguage,!0)],toOnSelectCB:async t=>{const e=t.target.dataset.votValue;c.A.log("[toOnSelectCB] select to language",e),this.data.responseLanguage=this.translateToLang=e,await u.d.set("responseLanguage",this.data.responseLanguage),c.A.log("Response Language value changed. New value: ",this.data.responseLanguage),this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage)}}),this.votMenu.bodyContainer.appendChild(this.votTranslationLanguageSelect.container),this.votSubtitlesSelect=B.createVOTSelect(p.get("VOTSubtitlesDisabled"),p.get("VOTSubtitles"),[{label:p.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1}],{onSelectCb:async t=>{await this.changeSubtitlesLang(t.target.dataset.votValue)},labelElement:B.createVOTSelectLabel(p.get("VOTSubtitles"))}),this.votMenu.bodyContainer.appendChild(this.votSubtitlesSelect.container),this.votVideoVolumeSlider=B.createSlider(`${p.get("VOTVolume")}: ${100*this.getVideoVolume()}%`,100*this.getVideoVolume()),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoVolumeSlider.container),this.votVideoTranslationVolumeSlider=B.createSlider(`${p.get("VOTVolumeTranslation")}: ${this.data?.defaultVolume??100}%`,this.data?.defaultVolume??100),this.votVideoTranslationVolumeSlider.container.hidden="success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoTranslationVolumeSlider.container),this.votMenu.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votSettingsDialog=B.createDialog(p.get("VOTSettings")),document.documentElement.appendChild(this.votSettingsDialog.container),this.votTranslationHeader=B.createHeader(p.get("translationSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationHeader),this.votAutoTranslateCheckbox=B.createCheckbox(p.get("VOTAutoTranslate"),this.data?.autoTranslate??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoTranslateCheckbox.container),this.votDontTranslateYourLangSelect=B.createVOTSelect(p.get("langs")[u.d.syncGet("dontTranslateLanguage",G)],p.get("VOTDontTranslateYourLang"),Gt(r,u.d.syncGet("dontTranslateLanguage",G)),{onSelectCb:async t=>{this.data.dontTranslateLanguage=t.target.dataset.votValue,await u.d.set("dontTranslateLanguage",this.data.dontTranslateLanguage)},labelElement:B.createCheckbox(p.get("VOTDontTranslateYourLang"),this.data?.dontTranslateYourLang??!0).container}),this.votSettingsDialog.bodyContainer.appendChild(this.votDontTranslateYourLangSelect.container),this.votAutoSetVolumeCheckbox=B.createCheckbox(`${p.get("VOTAutoSetVolume")}`,this.data?.autoSetVolumeYandexStyle??!0),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeCheckbox.container),this.votAutoSetVolumeSlider=B.createSlider(`${100*(this.data?.autoVolume??i.JD)}%`,100*(this.data?.autoVolume??i.JD),0,100),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeSlider.container),this.votShowVideoSliderCheckbox=B.createCheckbox(p.get("VOTShowVideoSlider"),this.data?.showVideoSlider??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votShowVideoSliderCheckbox.container),this.votUdemyDataTextfield=B.createTextfield(p.get("VOTUdemyData"),this.data?.udemyData?.accessToken??""),this.votUdemyDataTextfield.container.hidden="udemy"!==this.site.host,this.votSettingsDialog.bodyContainer.appendChild(this.votUdemyDataTextfield.container),this.votSyncVolumeCheckbox=B.createCheckbox(p.get("VOTSyncVolume"),this.data?.syncVolume??!1),this.votSyncVolumeCheckbox.container.hidden=!["youtube","googledrive"].includes(this.site.host)||"mobile"===this.site.additionalData,this.votSettingsDialog.bodyContainer.appendChild(this.votSyncVolumeCheckbox.container),this.votTranslationServiceSelect=B.createVOTSelect(u.d.syncGet("translationService",i.mE),p.get("VOTTranslationService"),Gt(D,u.d.syncGet("translationService",i.mE)),{onSelectCb:async t=>{this.data.translationService=t.target.dataset.votValue,await u.d.set("translationService",this.data.translationService)},labelElement:B.createCheckbox(p.get("VOTTranslateAPIErrors"),this.data.translateAPIErrors??!0).container}),this.votTranslationServiceSelect.container.hidden="ru"===p.lang,this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationServiceSelect.container),this.votDetectServiceSelect=B.createVOTSelect(u.d.syncGet("detectService",i.K2),p.get("VOTDetectService"),Gt(z,u.d.syncGet("detectService",i.K2)),{onSelectCb:async t=>{this.data.detectService=t.target.dataset.votValue,await u.d.set("detectService",this.data.detectService)},labelElement:B.createVOTSelectLabel(p.get("VOTDetectService"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votDetectServiceSelect.container),this.votSubtitlesHeader=B.createHeader(p.get("subtitlesSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader),this.votSubtitlesMaxLengthSlider=B.createSlider(`${p.get("VOTSubtitlesMaxLength")}: ${this.data?.subtitlesMaxLength??300}`,this.data?.subtitlesMaxLength??300,50,300),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesMaxLengthSlider.container),this.votSubtitlesHighlightWordsCheckbox=B.createCheckbox(p.get("VOTHighlightWords"),this.data?.highlightWords??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHighlightWordsCheckbox.container),this.votProxyHeader=B.createHeader(p.get("proxySettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader),this.votM3u8ProxyHostTextfield=B.createTextfield(p.get("VOTM3u8ProxyHost"),this.data?.m3u8ProxyHost,i.se),this.votSettingsDialog.bodyContainer.appendChild(this.votM3u8ProxyHostTextfield.container),this.votProxyWorkerHostTextfield=B.createTextfield(p.get("VOTProxyWorkerHost"),this.data?.proxyWorkerHost,i.Pm),this.votProxyWorkerHostTextfield.container.hidden=!1,this.votSettingsDialog.bodyContainer.appendChild(this.votProxyWorkerHostTextfield.container),this.votAudioProxyCheckbox=B.createCheckbox(p.get("VOTAudioProxy"),this.data?.audioProxy??!1),this.votAudioProxyCheckbox.container.hidden=!1,this.votSettingsDialog.bodyContainer.appendChild(this.votAudioProxyCheckbox.container),this.votAboutHeader=B.createHeader(p.get("about")),this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader),this.votLanguageSelect=B.createVOTSelect(p.get("langs")[u.d.syncGet("locale-lang-override","auto")],p.get("VOTMenuLanguage"),Gt(h,u.d.syncGet("locale-lang-override","auto")),{onSelectCb:async t=>{await u.d.set("locale-lang-override",t.target.dataset.votValue)},labelElement:B.createVOTSelectLabel(p.get("VOTMenuLanguage"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votLanguageSelect.container),this.votShowPiPButtonCheckbox=B.createCheckbox(p.get("VOTShowPiPButton"),this.data?.showPiPButton??!1),this.votShowPiPButtonCheckbox.container.hidden=!K(),this.votSettingsDialog.bodyContainer.appendChild(this.votShowPiPButtonCheckbox.container),this.votVersionInfo=B.createInformation(`${p.get("VOTVersion")}:`,`cloudflare ${GM_info.script.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votVersionInfo.container),this.votAuthorsInfo=B.createInformation(`${p.get("VOTAuthors")}:`,GM_info.script.author),this.votSettingsDialog.bodyContainer.appendChild(this.votAuthorsInfo.container),this.votLoaderInfo=B.createInformation(`${p.get("VOTLoader")}:`,`${GM_info.scriptHandler} v${GM_info.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votLoaderInfo.container),this.votBrowserInfo=B.createInformation(`${p.get("VOTBrowser")}:`,`${jt.browser.name} ${jt.browser.version} (${jt.os.name} ${jt.os.version})`),this.votSettingsDialog.bodyContainer.appendChild(this.votBrowserInfo.container),this.votResetSettingsButton=B.createButton(p.get("resetSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votResetSettingsButton)}initUIEvents(){this.votButton.translateButton.addEventListener("click",(()=>{(async()=>{if(this.audio.src)return c.A.log("[click translationBtn] audio.src is not empty"),void this.stopTranslate();if(this.hls.url)return c.A.log("[click translationBtn] hls is not empty"),void this.stopTranslate();try{if(c.A.log("[click translationBtn] trying execute translation"),!this.videoData.videoId)throw new F("VOTNoVideoIDFound");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.votDownloadButton.addEventListener("click",(()=>{this.downloadTranslationUrl&&window.open(this.downloadTranslationUrl,"_blank").focus()})),this.votDownloadSubtitlesButton.addEventListener("click",(()=>{console.log(this.downloadSubtitlesUrl),this.downloadSubtitlesUrl&&window.open(this.downloadSubtitlesUrl,"_blank").focus()})),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);if(this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`,this.setVideoVolume(e/100),1===this.data.syncVolume){const t=Number(this.votVideoTranslationVolumeSlider.input.value),o=Q(this.audio,e,t,this.tempOriginalVolume);this.votVideoTranslationVolumeSlider.input.value=o,this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,B.updateSlider(this.votVideoTranslationVolumeSlider.input),this.tempVolume=o,this.tempOriginalVolume=e}})),this.votVideoTranslationVolumeSlider.input.addEventListener("input",(t=>{(async()=>{this.data.defaultVolume=Number(t.target.value),await u.d.set("defaultVolume",this.data.defaultVolume),this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${this.data.defaultVolume}%`,this.audio.volume=this.data.defaultVolume/100,1===this.data.syncVolume&&this.syncTranslationWithVideo(this.data.defaultVolume)})()})),this.votAutoTranslateCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.autoTranslate=Number(t.target.checked),await u.d.set("autoTranslate",this.data.autoTranslate),c.A.log("autoTranslate value changed. New value: ",this.data.autoTranslate)})()})),this.votDontTranslateYourLangSelect.labelElement.addEventListener("change",(t=>{(async()=>{this.data.dontTranslateYourLang=Number(t.target.checked),await u.d.set("dontTranslateYourLang",this.data.dontTranslateYourLang),c.A.log("dontTranslateYourLang value changed. New value: ",this.data.dontTranslateYourLang)})()})),this.votAutoSetVolumeCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.autoSetVolumeYandexStyle=Number(t.target.checked),await u.d.set("autoSetVolumeYandexStyle",this.data.autoSetVolumeYandexStyle),c.A.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 u.d.set("autoVolume",this.data.autoVolume),this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`})()})),this.votShowVideoSliderCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showVideoSlider=Number(t.target.checked),await u.d.set("showVideoSlider",this.data.showVideoSlider),c.A.log("showVideoSlider value changed. New value: ",this.data.showVideoSlider),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status})()})),this.votUdemyDataTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.udemyData={accessToken:t.target.value,expires:(new Date).getTime()},await u.d.set("udemyData",this.data.udemyData),c.A.log("udemyData value changed. New value: ",this.data.udemyData),window.location.reload()})()})),this.votSyncVolumeCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.syncVolume=Number(t.target.checked),await u.d.set("syncVolume",this.data.syncVolume),c.A.log("syncVolume value changed. New value: ",this.data.syncVolume)})()})),this.votTranslationServiceSelect.labelElement.addEventListener("change",(t=>{(async()=>{this.data.translateAPIErrors=Number(t.target.checked),await u.d.set("translateAPIErrors",this.data.translateAPIErrors),c.A.log("translateAPIErrors value changed. New value: ",this.data.translateAPIErrors)})()})),this.votSubtitlesMaxLengthSlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesMaxLength=Number(t.target.value),await u.d.set("subtitlesMaxLength",this.data.subtitlesMaxLength),this.votSubtitlesMaxLengthSlider.label.querySelector("strong").innerHTML=`${this.data.subtitlesMaxLength}`,this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength)})()})),this.votSubtitlesHighlightWordsCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.highlightWords=Number(t.target.checked),await u.d.set("highlightWords",this.data.highlightWords),c.A.log("highlightWords value changed. New value: ",this.data.highlightWords),this.subtitlesWidget.setHighlightWords(this.data.highlightWords)})()})),this.votShowPiPButtonCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showPiPButton=Number(t.target.checked),await u.d.set("showPiPButton",this.data.showPiPButton),c.A.log("showPiPButton value changed. New value: ",this.data.showPiPButton),this.votButton.pipButton.hidden=!K()||!this.data.showPiPButton,this.votButton.separator2.hidden=!K()||!this.data.showPiPButton})()})),this.votM3u8ProxyHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.m3u8ProxyHost=t.target.value||i.se,await u.d.set("m3u8ProxyHost",this.data.m3u8ProxyHost),c.A.log("m3u8ProxyHost value changed. New value: ",this.data.m3u8ProxyHost)})()})),this.votProxyWorkerHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.proxyWorkerHost=t.target.value||i.Pm,await u.d.set("proxyWorkerHost",this.data.proxyWorkerHost),c.A.log("proxyWorkerHost value changed. New value: ",this.data.proxyWorkerHost),window.location.reload()})()})),this.votAudioProxyCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.audioProxy=Number(t.target.checked),await u.d.set("audioProxy",this.data.audioProxy),c.A.log("audioProxy value changed. New value: ",this.data.audioProxy)})()})),this.votResetSettingsButton.addEventListener("click",(()=>{(async()=>{p.reset();(await u.d.list()).filter((t=>!p.gmValues.includes(t))).forEach((t=>u.d.syncDelete(t))),window.location.reload()})()}))}releaseExtraEvents(){clearInterval(this.resizeInterval),this.resizeObserver?.disconnect(),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData&&this.syncVolumeObserver?.disconnect(),this.extraEvents?.forEach((t=>{t.element.removeEventListener(t.event,t.handler)}))}initExtraEvents(){this.extraEvents=[];const t=(t,e,o)=>{this.extraEvents.push({element:t,event:e,handler:o}),t.addEventListener(e,o)},e=(e,o,n)=>{o.forEach((o=>{t(e,o,n)}))};if(this.resizeObserver=new ResizeObserver((t=>{t.forEach((t=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${t.contentRect.height}px`)}))})),this.resizeObserver.observe(this.video),this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`),this.resizeInterval=setInterval((()=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`)}),500),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData){this.syncVolumeObserver=new MutationObserver((t=>{t.forEach((t=>{"attributes"===t.type&&"aria-valuenow"===t.attributeName&&this.syncVideoVolumeSlider()}))}));const t=document.querySelector(".ytp-volume-panel");t&&this.syncVolumeObserver.observe(t,{attributes:!0,childList:!1,subtree:!0,attributeOldValue:!0})}let o;document.addEventListener("click",(t=>{const e=t.target,o=this.votButton.container,n=this.votMenu.container,a=this.container,i=this.votSettingsDialog.container,r=document.querySelector(".vot-dialog-temp"),s=o.contains(e),l=n.contains(e),d=a.contains(e),u=i.contains(e),h=r?.contains(e)??!1;c.A.log(`[document click] ${s} ${l} ${d} ${u} ${h}`),s||l||u||h||(d||this.logout(0),this.votMenu.container.hidden=!0)})),o="pornhub"===this.site.host?"embed"===this.site.additionalData?document.querySelector("#player"):this.container.querySelector(".video-element-wrapper-js > div"):"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),t(this.video,"emptied",(()=>{c.A.log("lipsync mode is emptied"),this.stopTranslation()})),t(this.video,"progress",(async()=>{if(this.firstPlay&&1===this.data.autoTranslate&&Y(this.site.host,this.video)===this.videoData.videoId){if(!this.videoData.videoId)throw new F("VOTNoVideoIDFound");try{this.firstPlay=!1,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.firstPlay=!1}}}))}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(c.A.log("[onchange] subtitles",t),this.votSubtitlesSelect.setSelected(t),"disabled"===t)this.votSubtitlesSelect.setTitle(p.get("VOTSubtitlesDisabled")),this.subtitlesWidget.setContent(null),this.votDownloadSubtitlesButton.hidden=!0,this.downloadSubtitlesUrl=null;else{const e=await wt(this.subtitlesList.at(parseInt(t)));this.subtitlesWidget.setContent(e),this.votDownloadSubtitlesButton.hidden=!1,this.downloadSubtitlesUrl=this.subtitlesList.at(parseInt(t))?.url}}async updateSubtitlesLangSelect(){const t=[{label:p.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1},...this.subtitlesList.map(((t,e)=>({label:(p.get("langs")[t.language]??t.language.toUpperCase())+(t.translatedFromLanguage?` ${p.get("VOTTranslatedFrom")} ${p.get("langs")[t.translatedFromLanguage]??t.translatedFromLanguage.toUpperCase()}`:"")+("yandex"!==t.source?` ${t.source}`:"")+(t.isAutoGenerated?` (${p.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] ${p.getDefault("VOTNoVideoIDFound")}`),this.subtitlesList=[],this.subtitlesListVideoId=null,void await this.updateSubtitlesLangSelect();this.subtitlesListVideoId!==this.videoData.videoId&&(this.subtitlesList=await async function(t,e,o){const n="youtube"===t.host?U.getSubtitles():[];let a=!1;const i=[...await Promise.race([new Promise((t=>{setTimeout((()=>{a||(console.error("[VOT] Failed get yandex subtitles. Reason: timeout"),t([]))}),5e3)})),new Promise((n=>{bt(`${t.url}${e}`,o,((t,e)=>{c.A.log("[exec callback] Requesting video subtitles"),t||(console.error("[VOT] Failed get yandex subtitles"),a=!0,n([]));const o=ct.decodeSubtitlesResponse(e);console.log("[VOT] Subtitles response: ",o);let i=o.subtitles??[];i=i.reduce(((t,e)=>(e.language&&!t.find((t=>{if("yandex"===t.source&&t.language===e.language&&!t.translatedFromLanguage)return t}))&&t.push({source:"yandex",language:e.language,url:e.url}),e.translatedLanguage&&t.push({source:"yandex",language:e.translatedLanguage,translatedFromLanguage:e.language,url:e.translatedUrl}),t)),[]),a=!0,n(i)}))}))]),...n].sort(((t,e)=>{if(t.source!==e.source)return"yandex"===t.source?-1:1;if(t.language!==e.language&&(t.language===G||e.language===G))return t.language===G?-1:1;if("yandex"===t.source){if(t.translatedFromLanguage!==e.translatedFromLanguage)return t.translatedFromLanguage&&e.translatedFromLanguage?t.translatedFromLanguage===o?-1:1:t.language===e.language?t.translatedFromLanguage?1:-1:t.translatedFromLanguage?-1:1;if(!t.translatedFromLanguage)return t.language===o?-1:1}return"youtube"===t.source&&t.isAutoGenerated!==e.isAutoGenerated?t.isAutoGenerated?1:-1:0}));return console.log("[VOT] subtitles list",i),i}(this.site,this.videoData.videoId,this.videoData.detectedLanguage),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=U.getVideoVolume()||t),t}setVideoVolume(t){if(["youtube","googledrive"].includes(this.site.host)){if(U.setVideoVolume(t))return}this.video.volume=t}syncVideoVolumeSlider(){const t=Math.round(100*this.getVideoVolume());this.votVideoVolumeSlider.input.value=t,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${t}%`,B.updateSlider(this.votVideoVolumeSlider.input),1===this.data.syncVolume&&(this.tempOriginalVolume=Number(t))}setSelectMenuValues(t,e){this.votTranslationLanguageSelect.fromSelect.setTitle(p.get("langs")[t]),this.votTranslationLanguageSelect.toSelect.setTitle(p.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}syncTranslationWithVideo(t){const e=Number(this.votVideoVolumeSlider.input.value),o=Q(this.video,t,e,this.tempVolume);this.votVideoVolumeSlider.input.value=o,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,B.updateSlider(this.votVideoVolumeSlider.input),this.tempOriginalVolume=o,this.tempVolume=t}async getVideoData(){const t={translationHelp:null,isStream:!1,duration:this.video?.duration||343,videoId:Y(this.site.host,this.video),detectedLanguage:this.translateFromLang,responseLanguage:this.translateToLang};if(!t.videoId)return this.ytData={},t;if(window.location.hostname.includes("youtube.com"))this.ytData=await U.getVideoData(),t.isStream=this.ytData.isLive,""!==this.ytData.author&&(t.detectedLanguage=this.ytData.detectedLanguage,t.responseLanguage=this.translateToLang);else if(window.location.hostname.includes("rutube")||window.location.hostname.includes("ok.ru")||window.location.hostname.includes("my.mail.ru"))t.detectedLanguage="ru";else if(["bilibili","youku"].includes(this.site.host))t.detectedLanguage="zh";else if(["vk"].includes(this.site.host)){const e=document.getElementsByTagName("track")?.[0]?.srclang;t.detectedLanguage=e||"auto"}else if(window.location.hostname.includes("coursera.org")){const e=await Vt.getVideoData(this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else if(window.location.hostname.includes("coursehunter.net")){const e=await St.getVideoData();t.translationHelp={url:e.url},t.duration=e.duration||t.duration}else if(window.location.hostname.includes("banned.video")){const e=await Ft.getVideoData(t.videoId);t.translationHelp={url:e.url},t.duration=e.duration||t.duration,t.isStream=e.live}else if(window.location.hostname.includes("weverse.io")){const e=await It.getVideoData();t.detectedLanguage="ko",e&&(t.translationHelp={url:e.url},t.duration=e.duration||t.duration)}else if(window.location.hostname.includes("udemy.com")){const e=await Bt.getVideoData(this.data.udemyData,this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else["piped","invidious","bitchute","rumble","peertube","dailymotion","trovo","yandexdisk","coursehunter"].includes(this.site.host)&&(t.detectedLanguage="auto");return t}videoValidator(){if(["youtube","ok.ru","vk"].includes(this.site.host)){if(c.A.log("VideoValidator videoData: ",this.videoData),1===this.data.dontTranslateYourLang&&this.videoData.detectedLanguage===this.data.dontTranslateLanguage&&this.videoData.responseLanguage===this.data.dontTranslateLanguage)throw new F("VOTDisableFromYourLang");if(!this.videoData.isStream&&this.videoData.duration>14400)throw new F("VOTVideoIsTooLong")}return!0}lipSync(t=!1){if(c.A.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)&&(c.A.log(`lipsync mode is ${t}`),this.audio.pause()),"playing"==t&&(c.A.log("lipsync mode is playing"),this.audio.play());else{c.A.log("lipsync mode is play");const t=this.audio.play();void 0!==t&&t.catch((t=>{if(console.error("[VOT]",t),"NotAllowedError"===t.name)throw this.transformBtn("error",p.get("grantPermissionToAutoPlay")),new F("grantPermissionToAutoPlay");if("NotSupportedError"===t.name)throw this.transformBtn("error",Ut.includes(window.location.hostname)?p.get("neededAdditionalExtension"):p.get("audioFormatNotSupported")),Ut.includes(window.location.hostname)?new F("neededAdditionalExtension"):new F("audioFormatNotSupported")}))}else c.A.log("lipsync mode is not set")}handleVideoEvent(t){c.A.log(`video ${t.type}`),this.lipSync(t.type)}stopTranslate(){Wt.forEach((t=>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",p.get("translateVideo")),c.A.log(`Volume on start: ${this.volumeOnStart}`),this.volumeOnStart&&this.setVideoVolume(this.volumeOnStart),this.volumeOnStart="",clearInterval(this.streamPing),this.hls?.destroy(),this.hls=J()}async translateExecutor(t){c.A.log("Run translateFunc"),this.translateFunc(t,this.videoData.isStream,this.videoData.detectedLanguage,this.videoData.responseLanguage,this.videoData.translationHelp)}async updateTranslationErrorMsg(t){const e=p.get("translationTake"),o=p.get("VOTTranslatingError"),n=p.lang;if("VOTLocalizedError"===t?.name)this.transformBtn("error",t.localizedMessage);else if(1!==this.data.translateAPIErrors||t.includes(e)||"ru"===n)this.transformBtn("error",t);else{const e=await async function(t,e="",o="ru"){if("yandex"===await u.d.get("translationService",i.mE)){const n=e&&o?`${e}-${o}`:o;return await R.translate(t,n)}return t}(t,"ru",n);this.transformBtn("error",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").innerHTML=100*this.data.autoVolume+"%",B.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=t}updateTranslation(t){if(this.audio.src=t,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/",""),o=`https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${e}`;console.log(`[VOT] Audio proxied via ${o}`),this.audio.src=o}if(this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),"twitter"===this.site.host)document.querySelector('div[data-testid="app-bar-back"][role="button"]').addEventListener("click",this.stopTranslationBound);this.video&&!this.video.paused&&this.lipSync("play"),Wt.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),this.transformBtn("success",p.get("disableTranslate")),this.afterUpdateTranslation(t)}translateFunc(t,e,o,n,a){console.log("[VOT] Video Data: ",this.videoData);const i=a?.url?a.url:`${this.site.url}${t}`;if(c.A.log("Run videoValidator"),this.videoValidator(),e)return c.A.log("Executed stream translation"),void function(t,e,o,n){c.A.log(`Translate stream (url: ${t}, requestLang: ${e}, responseLang: ${o})`),vt(t,e,o,((t,e)=>{if(c.A.log("[exec callback] Requesting stream translation"),!t)return void n(!1,p.get("requestTranslationFailed"));const o=ct.decodeStreamResponse(e);switch(console.log("[VOT] Stream Translation response: ",o),o.interval){case 10:n(!1,o.interval,p.get("translationTakeFewMinutes"));break;case 20:n(!0,o.interval,o||p.get("audioNotReceived"));break;case 0:n(!1,o.interval,p.get("streamNoConnectionToServer"))}}))}(i,o,n,(async(i,r,s)=>{if(c.A.log("[exec callback] translateStream callback"),Y(this.site.host,this.video)!==t)return;if(!i||!s.translatedInfo)return await this.updateTranslationErrorMsg(s),void(10===r&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,o,n,a)),1e3*r)));this.transformBtn("success",p.get("disableTranslate")),console.log(s);const l=s.pingId;c.A.log(`Stream pingId: ${l}`),this.streamPing=setInterval((async()=>await gt(l,(t=>c.A.log("Stream ping result: ",t)))),1e3*r),c.A.log(s.translatedInfo.url);const d=`https://${this.data.m3u8ProxyHost}/?all=yes&origin=${encodeURIComponent("https://strm.yandex.ru")}&referer=${encodeURIComponent("https://strm.yandex.ru")}&url=${encodeURIComponent(s.translatedInfo.url)}`;if(c.A.log(d),this.hls)this.hls.on(Hls.Events.MEDIA_ATTACHED,(function(){c.A.log("audio and hls.js are now bound together !")})),this.hls.on(Hls.Events.MANIFEST_PARSED,(function(t){c.A.log("manifest loaded, found "+t?.levels?.length+" quality level")})),this.hls.loadSource(d),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()}})),c.A.log(this.hls);else{if(!this.audio.canPlayType("application/vnd.apple.mpegurl"))throw new F("audioFormatNotSupported");this.audio.src=d}"youtube"===this.site.host&&U.videoSeek(this.video,10),this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),this.video.src||this.video.currentSrc||this.video.srcObject?(this.video&&!this.video.paused&&this.lipSync("play"),Wt.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),this.afterUpdateTranslation(d)):this.stopTranslation()}));if(["udemy","coursera"].includes(this.site.host)&&!a)throw new F("VOTTranslationHelpNull");const r=this.videoTranslations.find((e=>e.videoId===t&&e.expires>Date.now()/1e3&&e.from===o&&e.to===n));if(r)return this.updateTranslation(r.url),void c.A.log("[translateFunc] A cached translate was received");Zt(i,this.videoData.duration,o,n,a,(async(i,r)=>{if(c.A.log("[exec callback] translateVideo callback"),Y(this.site.host,this.video)===t){if(!i)return await this.updateTranslationErrorMsg(r),r.includes(p.get("translationTake"))&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,o,n,a)),6e4)),void console.error("[VOT]",r);this.updateTranslation(r),this.videoTranslations.push({videoId:t,from:o,to:n,url:r,expires:Date.now()/1e3+this.videoTranslationTTL})}}))}stopTranslation(){this.stopTranslate(),this.syncVideoVolumeSlider()}async handleSrcChanged(){c.A.log("[VideoHandler] src changed",this),this.stopTranslation(),this.firstPlay=!0,this.videoData=await this.getVideoData(),this.videoData.detectedLanguage&&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(){c.A.log("[VideoHandler] release"),this.initialized=!1,this.stopTranslation(),this.releaseExtraEvents(),this.subtitlesWidget.release(),this.votButton.container.remove(),this.votMenu.container.remove()}}const Jt=new class{constructor(){this.onVideoAdded=new Nt,this.onVideoRemoved=new Nt,this.handleVideoAddedBound=this.handleVideoAdded.bind(this),this.handleVideoRemovedBound=this.handleVideoRemoved.bind(this),this.observer=new MutationObserver((t=>{window.requestIdleCallback((()=>{t.forEach((t=>{"childList"===t.type&&(Ht(t.addedNodes).forEach(this.handleVideoAddedBound),Ht(t.removedNodes).forEach(this.handleVideoRemovedBound))}))}),{timeout:1e3})}))}enable(){this.observer.observe(document,{childList:!0,subtree:!0}),document.querySelectorAll("video").forEach(this.handleVideoAddedBound)}disable(){this.observer.disconnect()}handleVideoAdded(t){this.onVideoAdded.dispatch(t)}handleVideoRemoved(t){document.contains(t)||this.onVideoRemoved.dispatch(t)}},Qt=new WeakMap;(async function(){c.A.log("Loading extension..."),await p.update(),c.A.log(`Selected menu language: ${p.lang}`),c.A.log("Extension compatibility passed..."),Jt.onVideoAdded.addListener((t=>{for(const e of $t.filter((t=>{const e=t=>t instanceof RegExp&&t.test(window.location.hostname)||"string"==typeof t&&window.location.hostname.includes(t)||"function"==typeof t&&t(new URL(window.location));return!!(e(t.match)||t.match instanceof Array&&t.match.some((t=>e(t))))&&t.host&&t.url}))){if(!e)continue;let o;if(e.shadowRoot)o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.shadowRoot.contains(t))):t.parentElement,o=o&&o.shadowRoot?o.parentElement:o;else{const n=jt.browser.version.split(".")?.[0];if(e.selector?.includes(":not")&&e.selector?.includes("*")&&n&&("Chrome"===jt.browser.name&&Number(n)<88||"Firefox"===jt.browser.name&&Number(n)<84)){const n=e.selector?.split(" *")?.[0];o=n?Object.values(document.querySelectorAll(n)).find((e=>e.contains(t))):t.parentElement}else o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.contains(t))):t.parentElement}if(o&&!("rumble"===e.host&&o.querySelector("vot-block")||("peertube"===e.host&&(e.url=window.location.origin),Qt.has(t)))){Qt.set(t,new Kt(t,o,e));break}}})),Jt.onVideoRemoved.addListener((async t=>{Qt.has(t)&&(await Qt.get(t).release(),Qt.delete(t))})),Jt.enable()})().catch((t=>{console.error("[VOT]",t)}))})()})(); \ No newline at end of file diff --git a/dist/vot-cloudflare.user.js b/dist/vot-cloudflare.user.js index 64d1e1b7..ac51e544 100644 --- a/dist/vot-cloudflare.user.js +++ b/dist/vot-cloudflare.user.js @@ -1,124 +1,130 @@ // ==UserScript== -// @name [VOT Cloudflare] - Voice Over Translation -// @name:de [VOT Cloudflare] - Voice-Over-Video-Übersetzung -// @name:es [VOT Cloudflare] - Traducción de vídeo en off -// @name:fr [VOT Cloudflare] - Traduction vidéo voix-off -// @name:it [VOT Cloudflare] - Traduzione Video fuori campo -// @name:ru [VOT Cloudflare] - Закадровый перевод видео -// @name:zh [VOT Cloudflare] - 画外音视频翻译 -// @description A small extension that adds a Yandex Browser video translation to other browsers +// @name [VOT Cloudflare] - Voice Over Translation +// @name:de [VOT Cloudflare] - Voice-Over-Video-Übersetzung +// @name:es [VOT Cloudflare] - Traducción de vídeo en off +// @name:fr [VOT Cloudflare] - Traduction vidéo voix-off +// @name:it [VOT Cloudflare] - Traduzione Video fuori campo +// @name:ru [VOT Cloudflare] - Закадровый перевод видео +// @name:zh [VOT Cloudflare] - 画外音视频翻译 +// @description A small extension that adds a Yandex Browser video translation to other browsers // @description:de Eine kleine Erweiterung, die eine Voice-over-Übersetzung von Videos aus dem Yandex-Browser zu anderen Browsern hinzufügt // @description:es Una pequeña extensión que agrega una traducción de voz en off de un video de Yandex Browser a otros navegadores // @description:fr Une petite extension qui ajoute la traduction vocale de la vidéo du Navigateur Yandex à d'autres navigateurs // @description:it Una piccola estensione che aggiunge la traduzione vocale del video dal browser Yandex ad altri browser // @description:ru Небольшое расширение, которое добавляет закадровый перевод видео из Яндекс Браузера в другие браузеры // @description:zh 一个小扩展,它增加了视频从Yandex浏览器到其他浏览器的画外音翻译 -// @version 1.5.0.5 -// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD -// @supportURL https://github.com/ilyhalight/voice-over-translation/issues -// @match *://*.youtube.com/* -// @match *://*.youtube-nocookie.com/* -// @match *://*.youtubekids.com/* -// @match *://*.twitch.tv/* -// @match *://*.xvideos.com/* -// @match *://*.pornhub.com/* -// @match *://*.vk.com/* -// @match *://*.vk.ru/* -// @match *://invidious.snopyta.org/* -// @match *://invidious.kavin.rocks/* -// @match *://vid.puffyan.us/* -// @match *://invidious.namazso.eu/* -// @match *://inv.riverside.rocks/* -// @match *://yt.artemislena.eu/* -// @match *://invidious.flokinet.to/* -// @match *://invidious.esmailelbob.xyz/* -// @match *://invidious.nerdvpn.de/* -// @match *://invidious.slipfox.xyz/* -// @match *://invidio.xamh.de/* -// @match *://invidious.dhusch.de/* -// @match *://*.piped.video/* -// @match *://piped.tokhmi.xyz/* -// @match *://piped.moomoo.me/* -// @match *://piped.syncpundit.io/* -// @match *://piped.mha.fi/* -// @match *://watch.whatever.social/* -// @match *://piped.garudalinux.org/* -// @match *://efy.piped.pages.dev/* -// @match *://watch.leptons.xyz/* -// @match *://piped.lunar.icu/* -// @match *://yt.dc09.ru/* -// @match *://piped.mint.lgbt/* -// @match *://*.il.ax/* -// @match *://piped.privacy.com.de/* -// @match *://piped.esmailelbob.xyz/* -// @match *://piped.projectsegfau.lt/* -// @match *://piped.in.projectsegfau.lt/* -// @match *://piped.us.projectsegfau.lt/* -// @match *://piped.privacydev.net/* -// @match *://piped.palveluntarjoaja.eu/* -// @match *://piped.smnz.de/* -// @match *://piped.adminforge.de/* -// @match *://piped.qdi.fi/* -// @match *://piped.hostux.net/* -// @match *://piped.chauvet.pro/* -// @match *://piped.jotoma.de/* -// @match *://piped.pfcd.me/* -// @match *://piped.frontendfriendly.xyz/* -// @match *://*.yewtu.be/* -// @match *://inv.vern.cc/* -// @match *://*.vimeo.com/* -// @match *://*.9gag.com/* -// @match *://*.twitter.com/* -// @match *://*.facebook.com/* -// @match *://*.rutube.ru/* -// @match *://*.bilibili.com/* -// @match *://my.mail.ru/* -// @match *://*.bitchute.com/* -// @match *://*.coursera.org/learn/* -// @match *://*.udemy.com/course/* -// @match *://*.tiktok.com/* -// @match *://proxitok.pabloferreiro.es/* -// @match *://proxitok.pussthecat.org/* -// @match *://tok.habedieeh.re/* -// @match *://proxitok.esmailelbob.xyz/* -// @match *://proxitok.privacydev.net/* -// @match *://tok.artemislena.eu/* -// @match *://tok.adminforge.de/* -// @match *://tik.hostux.net/* -// @match *://tt.vern.cc/* -// @match *://cringe.whatever.social/* -// @match *://proxitok.lunar.icu/* -// @match *://proxitok.privacy.com.de/* -// @match *://rumble.com/* -// @match *://*.eporner.com/* -// @match *://peertube.1312.media/* -// @match *://tube.shanti.cafe/* -// @match *://bee-tube.fr/* -// @match *://video.sadmin.io/* -// @match *://dalek.zone/* -// @match *://review.peertube.biz/* -// @match *://peervideo.club/* -// @match *://tube.la-dina.net/* -// @match *://peertube.tmp.rcp.tf/* -// @match *://geo.dailymotion.com/* -// @match *://trovo.live/* -// @match *://disk.yandex.ru/i/* -// @match *://coursehunter.net/* -// @connect api.browser.yandex.ru -// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare.user.js -// @grant GM_xmlhttpRequest -// @grant GM_info -// @grant GM_setValue -// @grant GM_getValue -// @grant GM_deleteValue -// @grant GM_listValues -// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues -// @icon https://translate.yandex.ru/icons/favicon.ico -// @inject-into page -// @namespace vot-cloudflare -// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js -// @require https://cdn.jsdelivr.net/npm/hls.js@1 -// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare.user.js +// @grant GM_addStyle +// @grant GM_deleteValue +// @grant GM_listValues +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_info +// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js +// @require https://cdn.jsdelivr.net/npm/hls.js/dist/hls.light.min.js +// @match *://*.youtube.com/* +// @match *://*.youtube-nocookie.com/* +// @match *://*.youtubekids.com/* +// @match *://*.twitch.tv/* +// @match *://*.xvideos.com/* +// @match *://*.pornhub.com/* +// @match *://*.vk.com/* +// @match *://*.vk.ru/* +// @match *://invidious.snopyta.org/* +// @match *://invidious.kavin.rocks/* +// @match *://vid.puffyan.us/* +// @match *://invidious.namazso.eu/* +// @match *://inv.riverside.rocks/* +// @match *://yt.artemislena.eu/* +// @match *://invidious.flokinet.to/* +// @match *://invidious.esmailelbob.xyz/* +// @match *://invidious.nerdvpn.de/* +// @match *://invidious.slipfox.xyz/* +// @match *://invidio.xamh.de/* +// @match *://invidious.dhusch.de/* +// @match *://*.piped.video/* +// @match *://piped.tokhmi.xyz/* +// @match *://piped.moomoo.me/* +// @match *://piped.syncpundit.io/* +// @match *://piped.mha.fi/* +// @match *://watch.whatever.social/* +// @match *://piped.garudalinux.org/* +// @match *://efy.piped.pages.dev/* +// @match *://watch.leptons.xyz/* +// @match *://piped.lunar.icu/* +// @match *://yt.dc09.ru/* +// @match *://piped.mint.lgbt/* +// @match *://*.il.ax/* +// @match *://piped.privacy.com.de/* +// @match *://piped.esmailelbob.xyz/* +// @match *://piped.projectsegfau.lt/* +// @match *://piped.in.projectsegfau.lt/* +// @match *://piped.us.projectsegfau.lt/* +// @match *://piped.privacydev.net/* +// @match *://piped.palveluntarjoaja.eu/* +// @match *://piped.smnz.de/* +// @match *://piped.adminforge.de/* +// @match *://piped.qdi.fi/* +// @match *://piped.hostux.net/* +// @match *://piped.chauvet.pro/* +// @match *://piped.jotoma.de/* +// @match *://piped.pfcd.me/* +// @match *://piped.frontendfriendly.xyz/* +// @match *://*.yewtu.be/* +// @match *://inv.vern.cc/* +// @match *://*.vimeo.com/* +// @match *://*.9gag.com/* +// @match *://*.twitter.com/* +// @match *://*.facebook.com/* +// @match *://*.rutube.ru/* +// @match *://*.bilibili.com/* +// @match *://my.mail.ru/* +// @match *://*.bitchute.com/* +// @match *://*.coursera.org/learn/* +// @match *://*.udemy.com/course/* +// @match *://*.tiktok.com/* +// @match *://proxitok.pabloferreiro.es/* +// @match *://proxitok.pussthecat.org/* +// @match *://tok.habedieeh.re/* +// @match *://proxitok.esmailelbob.xyz/* +// @match *://proxitok.privacydev.net/* +// @match *://tok.artemislena.eu/* +// @match *://tok.adminforge.de/* +// @match *://tik.hostux.net/* +// @match *://tt.vern.cc/* +// @match *://cringe.whatever.social/* +// @match *://proxitok.lunar.icu/* +// @match *://proxitok.privacy.com.de/* +// @match *://rumble.com/* +// @match *://*.eporner.com/* +// @match *://peertube.1312.media/* +// @match *://tube.shanti.cafe/* +// @match *://bee-tube.fr/* +// @match *://video.sadmin.io/* +// @match *://dalek.zone/* +// @match *://review.peertube.biz/* +// @match *://peervideo.club/* +// @match *://tube.la-dina.net/* +// @match *://peertube.tmp.rcp.tf/* +// @match *://geo.dailymotion.com/* +// @match *://*.ok.ru/* +// @match *://trovo.live/* +// @match *://disk.yandex.ru/i/* +// @match *://coursehunter.net/* +// @match *://youtube.googleapis.com/embed/* +// @match *://*.banned.video/* +// @match *://*.weverse.io/* +// @match *://*.newgrounds.com/* +// @match *://*.egghead.io/* +// @match *://*.youku.com/* +// @connect api.browser.yandex.ru +// @namespace vot-cloudflare +// @version 1.5.1 +// @icon https://translate.yandex.ru/icons/favicon.ico +// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD +// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues +// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare.user.js +// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-cloudflare.user.js +// @supportURL https://github.com/ilyhalight/voice-over-translation/issues // ==/UserScript== /******/ (() => { // webpackBootstrap @@ -136,7 +142,7 @@ "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Z: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/css-loader/dist/runtime/noSourceMaps.js"); /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); @@ -147,7 +153,7 @@ var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); // Module -___CSS_LOADER_EXPORT___.push([module.id, `.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}`, ""]); +___CSS_LOADER_EXPORT___.push([module.id, `.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}`, ""]); // Exports /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); @@ -416,23 +422,6 @@ module.exports = insertBySelector; /***/ }), -/***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js": -/***/ ((module) => { - -"use strict"; - - -/* istanbul ignore next */ -function insertStyleElement(options) { - var element = document.createElement("style"); - options.setAttributes(element, options.attributes); - options.insert(element, options.options); - return element; -} -module.exports = insertStyleElement; - -/***/ }), - /***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js": /***/ ((module, __unused_webpack_exports, __webpack_require__) => { @@ -537,6 +526,22 @@ function styleTagTransform(css, styleElement) { } module.exports = styleTagTransform; +/***/ }), + +/***/ "./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js": +/***/ ((module) => { + +module.exports = function () { + return (function styleLoaderInsertStyleElement(options) { + options.styleTagTransform = function monkeyStyleTagTransform(css, styleElement) { + styleElement?.remove(); + GM_addStyle(css); + }; + return document.createElement("style"); +}).apply(null, arguments) +} + + /***/ }), /***/ "./src/config/config.js": @@ -544,25 +549,21 @@ module.exports = styleTagTransform; "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ EY: () => (/* binding */ defaultDetectService), -/* harmony export */ I1: () => (/* binding */ yandexHmacKey), -/* harmony export */ Rr: () => (/* binding */ yandexUserAgent), -/* harmony export */ e6: () => (/* binding */ m3u8ProxyHost), -/* harmony export */ ez: () => (/* binding */ proxyWorkerHost), -/* harmony export */ jm: () => (/* binding */ detectUrls), -/* harmony export */ kF: () => (/* binding */ defaultTranslationService), -/* harmony export */ rm: () => (/* binding */ translateUrls), -/* harmony export */ sN: () => (/* binding */ defaultAutoVolume) +/* harmony export */ Cc: () => (/* binding */ yandexUserAgent), +/* harmony export */ JD: () => (/* binding */ defaultAutoVolume), +/* harmony export */ K2: () => (/* binding */ defaultDetectService), +/* harmony export */ Pm: () => (/* binding */ proxyWorkerHost), +/* harmony export */ QL: () => (/* binding */ detectUrls), +/* harmony export */ S7: () => (/* binding */ yandexHmacKey), +/* harmony export */ mE: () => (/* binding */ defaultTranslationService), +/* harmony export */ rw: () => (/* binding */ translateUrls), +/* harmony export */ se: () => (/* binding */ m3u8ProxyHost) /* harmony export */ }); /* unused harmony export workerHost */ -/* harmony import */ var _utils_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils/utils.js"); - - // CONFIGURATION const workerHost = "api.browser.yandex.ru"; -const m3u8ProxyHost = "m3u8proxy.toil-dump.workers.dev"; -const proxyWorkerHost = - _utils_utils_js__WEBPACK_IMPORTED_MODULE_0__/* .lang */ .KQ === "uk" ? "vot-new.toil-dump.workers.dev" : "vot-worker.onrender.com"; // used for cloudflare version (vot-new.toil-dump.workers.dev || vot-worker.onrender.com) +const m3u8ProxyHost = "m3u8-proxy.toil.cc"; // used for striming +const proxyWorkerHost = "vot.toil.cc"; // used for cloudflare version (vot-new.toil-dump.workers.dev || vot-worker.onrender.com) const yandexHmacKey = "xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm"; const yandexUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36"; @@ -582,203 +583,6 @@ const translateUrls = { -/***/ }), - -/***/ "./src/localization/localizationProvider.js": -/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { - -"use strict"; - -// EXPORTS -__webpack_require__.d(__webpack_exports__, { - Z: () => (/* binding */ availableLocales), - V: () => (/* binding */ localizationProvider) -}); - -;// CONCATENATED MODULE: ./src/localization/locales/en.json -const en_namespaceObject = JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}'); -// EXTERNAL MODULE: ./src/utils/debug.js -var debug = __webpack_require__("./src/utils/debug.js"); -// EXTERNAL MODULE: ./src/utils/storage.js -var storage = __webpack_require__("./src/utils/storage.js"); -;// CONCATENATED MODULE: ./src/localization/localizationProvider.js - - - - -const localesVersion = 2; -const localesUrl = `https://raw.githubusercontent.com/ilyhalight/voice-over-translation/${ - false ? 0 : "master" -}/src/localization/locales`; - -const availableLocales = [ - "auto", - "en", - "ru", - - "af", - "am", - "ar", - "az", - "bg", - "bn", - "bs", - "ca", - "cs", - "cy", - "da", - "de", - "el", - "es", - "et", - "eu", - "fa", - "fi", - "fr", - "gl", - "hi", - "hr", - "hu", - "hy", - "id", - "it", - "ja", - "jv", - "kk", - "km", - "kn", - "ko", - "lo", - "mk", - "ml", - "mn", - "ms", - "mt", - "my", - "ne", - "nl", - "pa", - "pl", - "pt", - "ro", - "si", - "sk", - "sl", - "sq", - "sr", - "su", - "sv", - "sw", - "tr", - "uk", - "ur", - "uz", - "vi", - "zh", - "zu", -]; - -const localizationProvider = new (class { - lang = "en"; - locale = {}; - gmValues = [ - "locale-phrases", - "locale-lang", - "locale-version", - "locale-lang-override", - ]; - - constructor() { - const langOverride = storage/* votStorage */.i.syncGet("locale-lang-override", "auto"); - if (langOverride && langOverride !== "auto") { - this.lang = langOverride; - } else { - this.lang = - (navigator.language || navigator.userLanguage) - ?.substr(0, 2) - ?.toLowerCase() ?? "en"; - } - this.setLocaleFromJsonString(storage/* votStorage */.i.syncGet("locale-phrases", "")); - } - - reset() { - this.gmValues.forEach((v) => storage/* votStorage */.i.syncDelete(v)); - } - - async update(force = false) { - if ( - !force && - (await storage/* votStorage */.i.get("locale-version", 0, true)) === localesVersion && - (await storage/* votStorage */.i.get("locale-lang")) === this.lang - ) { - return; - } - - debug/* default */.Z.log("Updating locale..."); - - await fetch(`${localesUrl}/${this.lang}.json`) - .then((response) => { - if (response.status === 200) return response.text(); - throw response.status; - }) - .then(async (text) => { - await storage/* votStorage */.i.set("locale-phrases", text); - this.setLocaleFromJsonString(text); - const version = this.getFromLocale(this.locale, "__version__"); - if (typeof version === "number") - await storage/* votStorage */.i.set("locale-version", version); - await storage/* votStorage */.i.set("locale-lang", this.lang); - }) - .catch(async (error) => { - console.error( - "[VOT] [localizationProvider] failed get locale, cause:", - error, - ); - this.setLocaleFromJsonString( - await storage/* votStorage */.i.get("locale-phrases", ""), - ); - }); - } - - setLocaleFromJsonString(json) { - try { - this.locale = JSON.parse(json) ?? {}; - } catch (exception) { - console.error("[VOT] [localizationProvider]", exception); - this.locale = {}; - } - } - - getFromLocale(locale, key) { - const result = key.split(".").reduce((locale, key) => { - if (typeof locale === "object" && locale) return locale[key]; - return undefined; - }, locale); - if (result === undefined) { - console.warn( - "[VOT] [localizationProvider] locale", - locale, - "doesn't contain key", - key, - ); - } - return result; - } - - getDefault(key) { - return this.getFromLocale(en_namespaceObject, key) ?? key; - } - - get(key) { - return ( - this.getFromLocale(this.locale, key) ?? - this.getFromLocale(en_namespaceObject, key) ?? - key - ); - } -})(); - - /***/ }), /***/ "./src/utils/debug.js": @@ -786,7 +590,7 @@ const localizationProvider = new (class { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Z: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); const debug = {}; debug.log = (...text) => { @@ -810,7 +614,7 @@ debug.log = (...text) => { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ i: () => (/* binding */ votStorage) +/* harmony export */ d: () => (/* binding */ votStorage) /* harmony export */ }); /* harmony import */ var _debug_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils/debug.js"); @@ -818,7 +622,7 @@ debug.log = (...text) => { const votStorage = new (class { constructor() { this.gmSupport = typeof GM_getValue === "function"; - _debug_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z.log(`GM Storage Status: ${this.gmSupport}`); + _debug_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .A.log(`GM Storage Status: ${this.gmSupport}`); } syncGet(name, def = undefined, toNumber = false) { @@ -843,9 +647,7 @@ const votStorage = new (class { return await GM_getValue(name, def); } - return new Promise((resolve) => { - resolve(this.syncGet(name, def, toNumber)); - }); + return Promise.resolve(this.syncGet(name, def, toNumber)); } syncSet(name, value) { @@ -865,9 +667,7 @@ const votStorage = new (class { return await GM_setValue(name, value); } - return new Promise((resolve) => { - resolve(this.syncSet(name, value)); - }); + return Promise.resolve(this.syncSet(name, value)); } syncDelete(name) { @@ -883,9 +683,7 @@ const votStorage = new (class { return await GM_deleteValue(name); } - return new Promise((resolve) => { - resolve(this.syncDelete(name)); - }); + return Promise.resolve(this.syncDelete(name)); } syncList() { @@ -918,478 +716,515 @@ const votStorage = new (class { return await GM_listValues(); } - return new Promise((resolve) => { - resolve(this.syncList()); - }); + return Promise.resolve(this.syncList()); } })(); /***/ }), -/***/ "./src/utils/utils.js": +/***/ "./src/yandexRequest-cloudflare.js": /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; +__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ KQ: () => (/* binding */ lang), -/* harmony export */ PG: () => (/* binding */ secsToStrTime), -/* harmony export */ QZ: () => (/* binding */ initHls), -/* harmony export */ _v: () => (/* binding */ sleep), -/* harmony export */ eL: () => (/* binding */ langTo6391), -/* harmony export */ gJ: () => (/* binding */ getVideoId), -/* harmony export */ qq: () => (/* binding */ isPiPAvailable) +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); -/* unused harmony export waitForElm */ -/* harmony import */ var _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/localization/localizationProvider.js"); +/* harmony import */ var _config_config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/config/config.js"); +/* harmony import */ var _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/utils/debug.js"); +/* harmony import */ var _utils_storage_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./src/utils/storage.js"); -const userlang = navigator.language || navigator.userLanguage; -const lang = userlang?.substr(0, 2)?.toLowerCase() ?? "en"; -if (!String.prototype.format) { - // https://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format - // syntax example: "is {0} function".format("format") - String.prototype.format = function () { - // store arguments in an array - var args = arguments; - // use replace to iterate over the string - // select the match and check if the related argument is present - // if yes, replace the match with the argument - return this.replace(/{(\d+)}/g, function (match, index) { - // check if the argument is present - return typeof args[index] != "undefined" ? args[index] : match; - }); - }; -} -function waitForElm(selector) { - // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists - return new Promise((resolve) => { - const element = document.querySelector(selector); - if (element) { - return resolve(element); - } +async function yandexRequest(path, body, headers, callback) { + let response; + let responseBody; + try { + _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.log("yandexRequest:", path); + // Create a fetch options object with headers and body + const options = { + method: "POST", + mode: "cors", + cache: "no-cache", + headers: { + "Content-Type": "application/json", + }, + redirect: "follow", + referrerPolicy: "no-referrer", + body: JSON.stringify({ + headers: { + ...{ + Accept: "application/x-protobuf", + "Accept-Language": "en", + "Content-Type": "application/x-protobuf", + "User-Agent": _config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .yandexUserAgent */ .Cc, + Pragma: "no-cache", + "Cache-Control": "no-cache", + "Sec-Fetch-Mode": "no-cors", + }, + ...headers, + }, + body: Array.from(body), + }), + }; + const workerHost = await _utils_storage_js__WEBPACK_IMPORTED_MODULE_2__/* .votStorage */ .d.get("proxyWorkerHost", _config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .proxyWorkerHost */ .Pm); + // Fetch the translation from the worker host + response = await fetch(`https://${workerHost}${path}`, options); + _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.log("yandexRequest:", response.status, response); + // Get the response body as an array buffer + responseBody = await response.arrayBuffer(); + } catch (exception) { + console.error("[VOT]", exception); + // Handle errors + response = { status: -1 }; + responseBody = exception; + } - const observer = new MutationObserver(() => { - const element = document.querySelector(selector); - if (element) { - resolve(element); - observer.disconnect(); - } - }); - - observer.observe(document.body, { - childList: true, - subtree: true, - once: true, - }); - }); + // Call the callback function with the result + callback(response.status == 200, responseBody); } -const sleep = (m) => new Promise((r) => setTimeout(r, m)); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (yandexRequest); -const getVideoId = (service, video) => { - const url = new URL(window.location.href); - switch (service) { - case "piped": - case "invidious": - case "youtube": - return ( - url.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1] || - url.searchParams.get("v") - ); - case "vk": - if (url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)) { - return url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1); - } else if (url.searchParams.get("z")) { - return url.searchParams.get("z").split("/")[0]; - } else if (url.searchParams.get("oid") && url.searchParams.get("id")) { - return `video-${Math.abs( - url.searchParams.get("oid"), - )}_${url.searchParams.get("id")}`; - } else { - return false; - } - case "nine_gag": - case "9gag": - case "gag": - return url.pathname.match(/gag\/([^/]+)/)?.[1]; - case "twitch": - if (/^m\.twitch\.tv$/.test(window.location.hostname)) { - const linkUrl = document.head.querySelector('link[rel="canonical"]'); - return ( - linkUrl?.href.match(/videos\/([^/]+)/)?.[0] || url.pathname.slice(1) - ); - } else if (/^player\.twitch\.tv$/.test(window.location.hostname)) { - return `videos/${url.searchParams.get("video")}`; - } else if (/^clips\.twitch\.tv$/.test(window.location.hostname)) { - // get link to twitch channel (ex.: https://www.twitch.tv/xqc) - const channelLink = document.querySelector( - ".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']", - ); - if (!channelLink) { - return false; - } +/***/ }) - const channelName = channelLink.href.replace( - "https://www.twitch.tv/", - "", - ); - return `${channelName}/clip/${url.searchParams.get("clip")}`; - } else if (url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)) { - return url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]; - } else { - return url.pathname.match(/(?:videos)\/([^/]+)/)?.[0]; - } - case "proxytok": - return url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; - case "tiktok": { - let id = url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; - if (!id) { - const playerEl = video.closest(".xgplayer-playing, .tiktok-web-player"); - const itemEl = playerEl?.closest( - 'div[data-e2e="recommend-list-item-container"]', - ); - const authorEl = itemEl?.querySelector( - 'a[data-e2e="video-author-avatar"]', - ); - if (playerEl && authorEl) { - const videoId = playerEl.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1); - const author = authorEl.href?.match(/.*(@.*)$/)?.at(1); - if (videoId && author) { - id = `${author}/video/${videoId}`; - } - } - } - return id; - } - case "vimeo": - return ( - url.pathname.match(/[^/]+\/[^/]+$/)?.[0] || - url.pathname.match(/[^/]+$/)?.[0] - ); - case "xvideos": - return url.pathname.match(/[^/]+\/[^/]+$/)?.[0]; - case "pornhub": - return ( - url.searchParams.get("viewkey") || - url.pathname.match(/embed\/([^/]+)/)?.[1] - ); - case "twitter": - return url.pathname.match(/status\/([^/]+)/)?.[1]; - case "udemy": - return url.pathname; - case "rumble": - return url.pathname; - case "facebook": - // ...watch?v=XXX - // CHANNEL_ID/videos/VIDEO_ID/ - // returning "Видео недоступно для перевода" - - // fb.watch/YYY - // returning "Возникла ошибка, попробуйте позже" - if (url.searchParams.get("v")) { - return url.searchParams.get("v"); - } +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ id: moduleId, +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/nonce */ +/******/ (() => { +/******/ __webpack_require__.nc = undefined; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; - return false; - case "rutube": - return url.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1]; - case "coub": - if (url.pathname.includes("/view")) { - return url.pathname.match(/view\/([^/]+)/)?.[1]; - } else if (url.pathname.includes("/embed")) { - return url.pathname.match(/embed\/([^/]+)/)?.[1]; - } else { - return document.querySelector(".coub.active")?.dataset?.permalink; - } - case "bilibili": { - const bvid = url.searchParams.get("bvid"); - if (bvid) { - return bvid; - } else { - let vid = url.pathname.match(/video\/([^/]+)/)?.[1]; - if (vid && url.search && url.searchParams.get("p") !== null) { - vid += `/?p=${url.searchParams.get("p")}`; - } - return vid; - } - } - case "mail_ru": - if (url.pathname.startsWith("/v/") || url.pathname.startsWith("/mail/")) { - return url.pathname; - } else if (url.pathname.match(/video\/embed\/([^/]+)/)) { - const referer = document.querySelector( - ".b-video-controls__mymail-link", - ); - if (!referer) { - return false; - } +;// CONCATENATED MODULE: ./src/config/alternativeUrls.js +// Sites host Invidious. I tested the performance only on invidious.kevin.rocks, youtu.be and inv.vern.cc +const sitesInvidious = [ + "invidious.snopyta.org", + "yewtu.be", + "invidious.kavin.rocks", + "vid.puffyan.us", + "invidious.namazso.eu", + "inv.riverside.rocks", + "yt.artemislena.eu", + "invidious.flokinet.to", + "invidious.esmailelbob.xyz", + "y.com.sb", + "invidious.nerdvpn.de", + "inv.vern.cc", + "invidious.slipfox.xyz", + "invidio.xamh.de", + "invidious.dhusch.de", +]; - return referer?.href.split("my.mail.ru")?.[1]; - } - return false; - case "bitchute": - return url.pathname.match(/video\/([^/]+)/)?.[1]; - case "coursera": - // ! LINK SHOULD BE LIKE THIS https://www.coursera.org/learn/learning-how-to-learn/lecture/75EsZ - // return url.pathname.match(/lecture\/([^/]+)\/([^/]+)/)?.[1]; // <--- COURSE PREVIEW - return url.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0]; // <--- COURSE PASSING (IF YOU LOGINED TO COURSERA) - case "eporner": - // ! LINK SHOULD BE LIKE THIS eporner.com/video-XXXXXXXXX/isdfsd-dfjsdfjsdf-dsfsdf-dsfsda-dsad-ddsd - return url.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0]; - case "peertube": - return url.pathname.match(/\/w\/([^/]+)/)?.[0]; - case "dailymotion": { - // we work in the context of the player - // geo.dailymotion.com +// Sites host Piped. I tested the performance only on piped.video +const sitesPiped = [ + "piped.video", + "piped.tokhmi.xyz", + "piped.moomoo.me", + "piped.syncpundit.io", + "piped.mha.fi", + "watch.whatever.social", + "piped.garudalinux.org", + "efy.piped.pages.dev", + "watch.leptons.xyz", + "piped.lunar.icu", + "yt.dc09.ru", + "piped.mint.lgbt", + "il.ax", + "piped.privacy.com.de", + "piped.esmailelbob.xyz", + "piped.projectsegfau.lt", + "piped.in.projectsegfau.lt", + "piped.us.projectsegfau.lt", + "piped.privacydev.net", + "piped.palveluntarjoaja.eu", + "piped.smnz.de", + "piped.adminforge.de", + "piped.qdi.fi", + "piped.hostux.net", + "piped.chauvet.pro", + "piped.jotoma.de", + "piped.pfcd.me", + "piped.frontendfriendly.xyz", +]; - const plainPlayerConfig = Array.from(document.scripts).filter((s) => - s.innerText.trim().includes("window.__PLAYER_CONFIG__ = {"), - ); - if (!plainPlayerConfig.length) { - return false; - } +const sitesProxyTok = [ + "proxitok.pabloferreiro.es", + "proxitok.pussthecat.org", + "tok.habedieeh.re", + "proxitok.esmailelbob.xyz", + "proxitok.privacydev.net", + "tok.artemislena.eu", + "tok.adminforge.de", + "tik.hostux.net", // maybe instance doesn't working + "tt.vern.cc", + "cringe.whatever.social", + "proxitok.lunar.icu", + "proxitok.privacy.com.de", // maybe instance doesn't working +]; - try { - let clearPlainConfig = plainPlayerConfig[0].innerText - .trim() - .replace("window.__PLAYER_CONFIG__ = ", ""); - if (clearPlainConfig.endsWith("};")) { - clearPlainConfig = clearPlainConfig.substring( - 0, - clearPlainConfig.length - 1, - ); - } - const playerConfig = JSON.parse(clearPlainConfig); - const videoUrl = - playerConfig.context.embedder ?? playerConfig.context.http_referer; - console.log(videoUrl, playerConfig); - return videoUrl.match(/\/video\/([^/]+)/)?.[1]; - } catch (e) { - console.error("[VOT]", e); - return false; - } - } - case "trovo": { - if (!url.pathname.startsWith("/s/")) { - return false; - } +// Sites host Peertube. I tested the performance only on dalek.zone and tube.shanti.cafe +const sitesPeertube = [ + "peertube.1312.media", + "tube.shanti.cafe", + "bee-tube.fr", + "video.sadmin.io", + "dalek.zone", + "review.peertube.biz", + "peervideo.club", + "tube.la-dina.net", + "peertube.tmp.rcp.tf", +]; - const vid = url.searchParams.get("vid"); - if (!vid) { - return false; - } - const path = url.pathname.match(/([^/]+)\/([\d]+)/)?.[0]; - if (!path) { - return false; - } - return `${path}?vid=${vid}`; - } - case "yandexdisk": - return url.pathname.match(/\/[i|s|d]\/([^/]+)/)?.[1]; - case "coursehunter": { - const courseId = url.pathname.match(/\/course\/([^/]+)/)?.[1]; - return courseId ? courseId + url.search : false; +// EXTERNAL MODULE: ./src/config/config.js +var config = __webpack_require__("./src/config/config.js"); +;// CONCATENATED MODULE: ./src/config/constants.js +// available languages for translation +const availableLangs = [ + "ru", + "en", + "zh", + "ko", + "lt", + "lv", + "ar", + "fr", + "it", + "es", + "de", + "ja", +]; + +// Additional languages working with TTS +const additionalTTS = [ + "kk", + "bn", + "pt", + "cs", + "hi", + "mr", // TODO: Add menu translation (MAYBE) + "te", // TODO: Add menu translation (MAYBE) + "tr", + "ms", + "vi", + "ta", // TODO: Add menu translation (MAYBE) + "jv", + "ur", + "fa", + "gu", // TODO: Add menu translation (MAYBE) + "id", + "uk", + "da", + "fi", + "uz", + "pl", + "sv", + "az", + "sq", + "am", + "hy", + "af", + "eu", + "my", + "bg", + "bs", + "cy", + "hu", + "gl", + "el", + "zu", + "kn", + "ca", + "km", + "lo", + "mk", + "ml", + "mt", + "mn", + "ne", + "nl", + "pa", + "ro", + "sr", + "si", + "sk", + "sl", + "sw", + "su", + "hr", + "et", +]; + +// up-to-date list of TTS working languages +const actualTTS = ["ru", "en", "kk"]; + +const cfOnlyExtensions = (/* unused pure expression or super */ null && ([ + "Violentmonkey", + "FireMonkey", + "Greasemonkey", + "AdGuard", + "OrangeMonkey", +])); + + + +;// CONCATENATED MODULE: ./src/localization/locales/en.json +const en_namespaceObject = /*#__PURE__*/JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}'); +// EXTERNAL MODULE: ./src/utils/debug.js +var debug = __webpack_require__("./src/utils/debug.js"); +// EXTERNAL MODULE: ./src/utils/storage.js +var storage = __webpack_require__("./src/utils/storage.js"); +;// CONCATENATED MODULE: ./src/localization/localizationProvider.js + + + + +const localesVersion = 2; +const localesUrl = `https://raw.githubusercontent.com/ilyhalight/voice-over-translation/${ + false ? 0 : "master" +}/src/localization/locales`; + +const availableLocales = [ + "auto", + "en", + "ru", + + "af", + "am", + "ar", + "az", + "bg", + "bn", + "bs", + "ca", + "cs", + "cy", + "da", + "de", + "el", + "es", + "et", + "eu", + "fa", + "fi", + "fr", + "gl", + "hi", + "hr", + "hu", + "hy", + "id", + "it", + "ja", + "jv", + "kk", + "km", + "kn", + "ko", + "lo", + "mk", + "ml", + "mn", + "ms", + "mt", + "my", + "ne", + "nl", + "pa", + "pl", + "pt", + "ro", + "si", + "sk", + "sl", + "sq", + "sr", + "su", + "sv", + "sw", + "tr", + "uk", + "ur", + "uz", + "vi", + "zh", + "zu", +]; + +const localizationProvider = new (class { + lang = "en"; + locale = {}; + gmValues = [ + "locale-phrases", + "locale-lang", + "locale-version", + "locale-lang-override", + ]; + + constructor() { + const langOverride = storage/* votStorage */.d.syncGet("locale-lang-override", "auto"); + if (langOverride && langOverride !== "auto") { + this.lang = langOverride; + } else { + this.lang = + (navigator.language || navigator.userLanguage) + ?.substr(0, 2) + ?.toLowerCase() ?? "en"; } - default: - return false; + this.setLocaleFromJsonString(storage/* votStorage */.d.syncGet("locale-phrases", "")); } -}; -function secsToStrTime(secs) { - const minutes = Math.floor(secs / 60); - const seconds = Math.floor(secs % 60); - if (minutes >= 60) { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V.get("translationTakeMoreThanHour"); - } else if (minutes >= 10 && minutes % 10) { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V - .get("translationTakeApproximatelyMinutes") - .format(minutes); - } else if (minutes == 1 || (minutes == 0 && seconds > 0)) { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V.get("translationTakeAboutMinute"); - } else { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V - .get("translationTakeApproximatelyMinute") - .format(minutes); + reset() { + this.gmValues.forEach((v) => storage/* votStorage */.d.syncDelete(v)); } -} -function langTo6391(lang) { - // convert lang to ISO 639-1 - return lang.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]; -} + async update(force = false) { + if ( + !force && + (await storage/* votStorage */.d.get("locale-version", 0, true)) === localesVersion && + (await storage/* votStorage */.d.get("locale-lang")) === this.lang + ) { + return; + } -function isPiPAvailable() { - return ( - "pictureInPictureEnabled" in document && document.pictureInPictureEnabled - ); -} + debug/* default */.A.log("Updating locale..."); -function initHls() { - return typeof Hls != "undefined" && Hls?.isSupported() - ? new Hls({ - debug: false, // turn it on manually if necessary - lowLatencyMode: true, - backBufferLength: 90, + await fetch(`${localesUrl}/${this.lang}.json`) + .then((response) => { + if (response.status === 200) return response.text(); + throw response.status; }) - : undefined; -} - - - - -/***/ }), - -/***/ "./src/yandexRequest-cloudflare.js": -/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -/* harmony import */ var _config_config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/config/config.js"); -/* harmony import */ var _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/utils/debug.js"); -/* harmony import */ var _utils_storage_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./src/utils/storage.js"); - - - - -async function yandexRequest(path, body, headers, callback) { - let response; - let responseBody; - try { - _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .Z.log("yandexRequest:", path); - // Create a fetch options object with headers and body - const options = { - method: "POST", - mode: "cors", - cache: "no-cache", - headers: { - "Content-Type": "application/json", - }, - redirect: "follow", - referrerPolicy: "no-referrer", - body: JSON.stringify({ - headers: { - ...{ - Accept: "application/x-protobuf", - "Accept-Language": "en", - "Content-Type": "application/x-protobuf", - "User-Agent": _config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .yandexUserAgent */ .Rr, - Pragma: "no-cache", - "Cache-Control": "no-cache", - "Sec-Fetch-Mode": "no-cors", - }, - ...headers, - }, - body: Array.from(body), - }), - }; - const workerHost = await _utils_storage_js__WEBPACK_IMPORTED_MODULE_2__/* .votStorage */ .i.get("proxyWorkerHost", _config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .proxyWorkerHost */ .ez); - // Fetch the translation from the worker host - response = await fetch(`https://${workerHost}${path}`, options); - _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .Z.log("yandexRequest:", response.status, response); - // Get the response body as an array buffer - responseBody = await response.arrayBuffer(); - } catch (exception) { - console.error("[VOT]", exception); - // Handle errors - response = { status: -1 }; - responseBody = exception; + .then(async (text) => { + await storage/* votStorage */.d.set("locale-phrases", text); + this.setLocaleFromJsonString(text); + const version = this.getFromLocale(this.locale, "__version__"); + if (typeof version === "number") + await storage/* votStorage */.d.set("locale-version", version); + await storage/* votStorage */.d.set("locale-lang", this.lang); + }) + .catch(async (error) => { + console.error( + "[VOT] [localizationProvider] failed get locale, cause:", + error, + ); + this.setLocaleFromJsonString( + await storage/* votStorage */.d.get("locale-phrases", ""), + ); + }); } - // Call the callback function with the result - callback(response.status == 200, responseBody); -} - -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (yandexRequest); - - -/***/ }) + setLocaleFromJsonString(json) { + try { + this.locale = JSON.parse(json) ?? {}; + } catch (exception) { + console.error("[VOT] [localizationProvider]", exception); + this.locale = {}; + } + } -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ id: moduleId, -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/compat get default export */ -/******/ (() => { -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = (module) => { -/******/ var getter = module && module.__esModule ? -/******/ () => (module['default']) : -/******/ () => (module); -/******/ __webpack_require__.d(getter, { a: getter }); -/******/ return getter; -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __webpack_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ -/******/ /* webpack/runtime/make namespace object */ -/******/ (() => { -/******/ // define __esModule on exports -/******/ __webpack_require__.r = (exports) => { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/nonce */ -/******/ (() => { -/******/ __webpack_require__.nc = undefined; -/******/ })(); -/******/ -/************************************************************************/ -var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be in strict mode. -(() => { -"use strict"; + getFromLocale(locale, key) { + const result = key.split(".").reduce((locale, key) => { + if (typeof locale === "object" && locale) return locale[key]; + return undefined; + }, locale); + if (result === undefined) { + console.warn( + "[VOT] [localizationProvider] locale", + locale, + "doesn't contain key", + key, + ); + } + return result; + } + + getDefault(key) { + return this.getFromLocale(en_namespaceObject, key) ?? key; + } + + get(key) { + return ( + this.getFromLocale(this.locale, key) ?? + this.getFromLocale(en_namespaceObject, key) ?? + key + ); + } +})(); // EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js var injectStylesIntoStyleTag = __webpack_require__("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); @@ -1403,9 +1238,9 @@ var insertBySelector_default = /*#__PURE__*/__webpack_require__.n(insertBySelect // EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js var setAttributesWithoutAttributes = __webpack_require__("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"); var setAttributesWithoutAttributes_default = /*#__PURE__*/__webpack_require__.n(setAttributesWithoutAttributes); -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertStyleElement.js -var insertStyleElement = __webpack_require__("./node_modules/style-loader/dist/runtime/insertStyleElement.js"); -var insertStyleElement_default = /*#__PURE__*/__webpack_require__.n(insertStyleElement); +// EXTERNAL MODULE: ./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js +var style_loader_insertStyleElement = __webpack_require__("./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js"); +var style_loader_insertStyleElement_default = /*#__PURE__*/__webpack_require__.n(style_loader_insertStyleElement); // EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleTagTransform.js var styleTagTransform = __webpack_require__("./node_modules/style-loader/dist/runtime/styleTagTransform.js"); var styleTagTransform_default = /*#__PURE__*/__webpack_require__.n(styleTagTransform); @@ -1431,1164 +1266,1112 @@ options.setAttributes = (setAttributesWithoutAttributes_default()); options.insert = insertBySelector_default().bind(null, "head"); options.domAPI = (styleDomAPI_default()); -options.insertStyleElement = (insertStyleElement_default()); - -var update = injectStylesIntoStyleTag_default()(main/* default */.Z, options); - +options.insertStyleElement = (style_loader_insertStyleElement_default()); +var update = injectStylesIntoStyleTag_default()(main/* default */.A, options); - /* harmony default export */ const styles_main = (main/* default */.Z && main/* default */.Z.locals ? main/* default */.Z.locals : undefined); -// EXTERNAL MODULE: ./src/localization/localizationProvider.js + 1 modules -var localizationProvider = __webpack_require__("./src/localization/localizationProvider.js"); -;// CONCATENATED MODULE: ./src/utils/VOTLocalizedError.js + /* harmony default export */ const styles_main = (main/* default */.A && main/* default */.A.locals ? main/* default */.A.locals : undefined); -class VOTLocalizedError extends Error { - constructor(message) { - super(localizationProvider/* localizationProvider */.V.getDefault(message)); - this.name = "VOTLocalizedError"; - this.unlocalizedMessage = message; - this.localizedMessage = localizationProvider/* localizationProvider */.V.get(message); - } -} +;// CONCATENATED MODULE: ./src/ui.js -// EXTERNAL MODULE: ./src/utils/debug.js -var debug = __webpack_require__("./src/utils/debug.js"); -;// CONCATENATED MODULE: ./src/config/constants.js -// available languages for translation -const availableLangs = [ - "ru", - "en", - "zh", - "ko", - "lt", - "lv", - "ar", - "fr", - "it", - "es", - "de", - "ja", -]; -// Additional languages working with TTS -const additionalTTS = [ - "kk", - "bn", - "pt", - "cs", - "hi", - "mr", // TODO: Add menu translation (MAYBE) - "te", // TODO: Add menu translation (MAYBE) - "tr", - "ms", - "vi", - "ta", // TODO: Add menu translation (MAYBE) - "jv", - "ur", - "fa", - "gu", // TODO: Add menu translation (MAYBE) - "id", - "uk", - "da", - "fi", - "uz", - "pl", - "sv", - "az", - "sq", - "am", - "hy", - "af", - "eu", - "my", - "bg", - "bs", - "cy", - "hu", - "gl", - "el", - "zu", - "kn", - "ca", - "km", - "lo", - "mk", - "ml", - "mt", - "mn", - "ne", - "nl", - "pa", - "ro", - "sr", - "si", - "sk", - "sl", - "sw", - "su", - "hr", - "et", -]; +function createHeader(html, level = 4) { + const header = document.createElement("vot-block"); + header.classList.add("vot-header"); + header.classList.add(`vot-header-level-${level}`); + header.innerHTML = html; -// up-to-date list of TTS working languages -const actualTTS = ["ru", "en", "kk"]; + return header; +} -const cfOnlyExtensions = (/* unused pure expression or super */ null && ([ - "Violentmonkey", - "FireMonkey", - "Greasemonkey", - "AdGuard", - "OrangeMonkey", -])); +function createInformation(html, valueHtml) { + const container = document.createElement("vot-block"); + container.classList.add("vot-info"); + const header = document.createElement("vot-block"); + header.innerHTML = html; + const value = document.createElement("vot-block"); + value.innerHTML = valueHtml; -// EXTERNAL MODULE: ./src/utils/utils.js -var utils = __webpack_require__("./src/utils/utils.js"); -// EXTERNAL MODULE: ./src/config/config.js -var config = __webpack_require__("./src/config/config.js"); -// EXTERNAL MODULE: ./src/utils/storage.js -var storage = __webpack_require__("./src/utils/storage.js"); -;// CONCATENATED MODULE: ./src/utils/translateApis.js + container.appendChild(header); + container.appendChild(value); + return { + container, + header, + value, + }; +} +function createButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-button"); + button.innerHTML = html; -const HTTP_TIMEOUT = 3000; + return button; +} -async function fetchWithTimeout(url, options) { - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT); +function createTextButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-text-button"); + button.innerHTML = html; - try { - return await fetch(url, { - ...options, - signal: controller.signal, - }); - } catch (error) { - console.error("Fetch timed-out. Error:", error); - return error; - } finally { - clearTimeout(timeoutId); - } + return button; } -const YandexTranslateAPI = { - async translate(text, lang) { - // Limit: 10k symbols - // - // Lang examples: - // en-ru, uk-ru, ru-en... - // ru, en (instead of auto-ru, auto-en) +function createOutlinedButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-outlined-button"); + button.innerHTML = html; - try { - const response = await fetchWithTimeout(config/* translateUrls */.rm.yandex, { - method: "POST", - headers: { - "content-type": "application/json", - }, - body: JSON.stringify({ - text, - lang, - }), - }); + return button; +} - if (response instanceof Error) { - throw response; - } +function createIconButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-icon-button"); + button.innerHTML = html; - const content = await response.json(); + return button; +} - if (content.code !== 200) { - throw content.message; - } +function createCheckbox(html, value = false) { + const container = document.createElement("label"); + container.classList.add("vot-checkbox"); - return content.text[0]; - } catch (error) { - console.error("Error translating text:", error); - return text; - } - }, + const input = document.createElement("input"); + input.type = "checkbox"; + input.checked = Boolean(value); - async detect(text, lang) { - // Limit: 10k symbols - try { - const response = await fetchWithTimeout(config/* detectUrls */.jm.yandex, { - method: "POST", - headers: { - "content-type": "application/json", - }, - body: JSON.stringify({ - text, - lang, - }), - }); + const label = document.createElement("span"); + label.innerHTML = html; - if (response instanceof Error) { - throw response; - } + container.appendChild(input); + container.appendChild(label); - const content = await response.json(); - if (content.code !== 200) { - throw content.message; - } + return { container, input, label }; +} - return content.lang ?? "en"; - } catch (error) { - console.error("Error translating text:", error); - return "en"; - } - }, -}; +function updateSlider(input) { + const value = parseFloat(input.value); + const min = input.min === "" ? 0 : parseFloat(input.min); + const max = input.max === "" ? 100 : parseFloat(input.max); + const progress = (value - min) / (max - min); + input.parentElement.setAttribute("style", `--vot-progress: ${progress}`); +} -const RustServerAPI = { - async detect(text) { - try { - const response = await fetch(config/* detectUrls */.jm.rustServer, { - method: "POST", - body: text, - }); +function createSlider(html, value = 50, min = 0, max = 100) { + const container = document.createElement("vot-block"); + container.classList.add("vot-slider"); - if (response instanceof Error) { - throw response; - } + const input = document.createElement("input"); + input.type = "range"; + input.min = min; + input.max = max; + input.value = value; - return await response.text(); - } catch (error) { - console.error("Error getting lang from text:", error); - return "en"; - } - }, -}; + const label = document.createElement("span"); + label.innerHTML = html; -async function translate(text, fromLang = "", toLang = "ru") { - const service = await storage/* votStorage */.i.get( - "translationService", - config/* defaultTranslationService */.kF, - ); - switch (service) { - case "yandex": { - const langPair = fromLang && toLang ? `${fromLang}-${toLang}` : toLang; - return await YandexTranslateAPI.translate(text, langPair); - } - default: - return text; - } -} + container.appendChild(input); + container.appendChild(label); -async function detect(text) { - const service = await storage/* votStorage */.i.get("detectService", config/* defaultDetectService */.EY); - switch (service) { - case "yandex": - return await YandexTranslateAPI.detect(text); - case "rust-server": - return await RustServerAPI.detect(text); - default: - return "en"; - } -} + input.addEventListener("input", (e) => updateSlider(e.target)); + updateSlider(input); -const translateServices = ["yandex"]; -const detectServices = ["yandex", "rust-server"]; + return { + container, + input, + label, + }; +} +function createTextfield( + html, + value = "", + placeholder = " ", + multiline = false, +) { + const container = document.createElement("vot-block"); + container.classList.add("vot-textfield"); + const input = document.createElement(multiline ? "textarea" : "input"); + input.placeholder = placeholder; + input.value = value; -;// CONCATENATED MODULE: ./src/utils/youtubeUtils.js + const label = document.createElement("span"); + label.innerHTML = html; + container.appendChild(input); + container.appendChild(label); + return { + container, + input, + label, + }; +} +function createDialog(html) { + const container = document.createElement("vot-block"); + container.classList.add("vot-dialog-container"); + container.hidden = true; + const backdrop = document.createElement("vot-block"); + backdrop.classList.add("vot-dialog-backdrop"); -// Get the language code from the response or the text -async function getLanguage(player, response, title, description) { - if ( - !window.location.hostname.includes("m.youtube.com") && - player?.getAudioTrack - ) { - // ! Experimental ! get lang from selected audio track if availabled - const audioTracks = player.getAudioTrack(); - const trackInfo = audioTracks?.getLanguageInfo(); // get selected track info (id === "und" if tracks are not available) - if (trackInfo?.id !== "und") { - return (0,utils/* langTo6391 */.eL)(trackInfo.id.split(".")[0]); - } - } + const dialog = document.createElement("vot-block"); + dialog.classList.add("vot-dialog"); - // TODO: If the audio tracks will work fine, transfer the receipt of captions to the audioTracks variable - // Check if there is an automatic caption track in the response - const captionTracks = - response?.captions?.playerCaptionsTracklistRenderer?.captionTracks; - if (captionTracks?.length) { - const autoCaption = captionTracks.find((caption) => caption.kind === "asr"); - if (autoCaption && autoCaption.languageCode) { - return (0,utils/* langTo6391 */.eL)(autoCaption.languageCode); - } - } + const contentWrapper = document.createElement("vot-block"); + contentWrapper.classList.add("vot-dialog-content-wrapper"); - // the "delayed video upload" fix for YouTube (#387) - if (!(description && title)) { - return "en"; - } + const headerContainer = document.createElement("vot-block"); + headerContainer.classList.add("vot-dialog-header-container"); - // If there is no caption track, use detect to get the language code from the description + const bodyContainer = document.createElement("vot-block"); + bodyContainer.classList.add("vot-dialog-body-container"); - const deletefilter = [ - /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g, // remove links - /Auto-generated by YouTube/g, - /Provided to YouTube by/g, - /Released on/g, - /Bitcoin/g, - /USDT/g, - /Paypal/g, - ]; + const footerContainer = document.createElement("vot-block"); + footerContainer.classList.add("vot-dialog-footer-container"); - const cleanedDescription = description - .split("\n\n") - .filter((line) => !deletefilter.some((regex) => regex.test(line))) - .join("\n\n") - .replace(/[^\p{L}\s]/gu, " ") - .trim() - .replace(/\s+/g, " ") - .slice(0, 250); + const titleContainer = document.createElement("vot-block"); + titleContainer.classList.add("vot-dialog-title-container"); - const cleanText = [cleanedDescription, title].join(" "); + const closeButton = createIconButton( + ``, + ); + closeButton.classList.add("vot-dialog-close-button"); - return await detect(cleanText); -} + backdrop.onclick = closeButton.onclick = () => { + container.hidden = true; + }; -function isMobile() { - return /^m\.youtube\.com$/.test(window.location.hostname); -} + const title = document.createElement("vot-block"); + title.classList.add("vot-dialog-title"); + title.innerHTML = html; -function getPlayer() { - if (window.location.pathname.startsWith("/shorts/")) { - return isMobile() - ? document.querySelector("#movie_player") - : document.querySelector("#shorts-player"); - } + container.appendChild(backdrop); + container.appendChild(dialog); + dialog.appendChild(contentWrapper); + contentWrapper.appendChild(headerContainer); + contentWrapper.appendChild(bodyContainer); + contentWrapper.appendChild(footerContainer); + headerContainer.appendChild(titleContainer); + headerContainer.appendChild(closeButton); + titleContainer.appendChild(title); - return document.querySelector("#movie_player"); + return { + container, + backdrop, + dialog, + contentWrapper, + headerContainer, + bodyContainer, + footerContainer, + titleContainer, + closeButton, + title, + }; } -function getPlayerResponse() { - const player = getPlayer(); - if (player?.getPlayerResponse) - return player?.getPlayerResponse?.call() ?? null; - return player?.data?.playerResponse ?? null; -} +function createVOTButton(html) { + const container = document.createElement("vot-block"); + container.classList.add("vot-segmented-button"); -function getPlayerData() { - const player = getPlayer(); - if (player?.getVideoData) return player?.getVideoData?.call() ?? null; - return player?.data?.playerResponse?.videoDetails ?? null; -} + const translateButton = document.createElement("vot-block"); + translateButton.classList.add("vot-segment"); + translateButton.classList.add("vot-translate-button"); + translateButton.innerHTML = ``; -function getVideoVolume() { - const player = getPlayer(); - if (player?.getVolume) { - return player.getVolume.call() / 100; - } + const separator = document.createElement("vot-block"); + separator.classList.add("vot-separator"); - return 1; -} + const pipButton = document.createElement("vot-block"); + pipButton.classList.add("vot-segment-only-icon"); + pipButton.innerHTML = ``; -function setVideoVolume(volume) { - const player = getPlayer(); - if (player?.setVolume) { - player.setVolume(Math.round(volume * 100)); - return true; - } -} + const separator2 = document.createElement("vot-block"); + separator2.classList.add("vot-separator"); -function videoSeek(video, time) { - // * TIME IN MS - debug/* default */.Z.log("videoSeek", time); - const preTime = - getPlayer()?.getProgressState()?.seekableEnd || video.currentTime; - const finalTime = preTime - time; // we always throw it to the end of the stream - time - video.currentTime = finalTime; -} + const menuButton = document.createElement("vot-block"); + menuButton.classList.add("vot-segment-only-icon"); + menuButton.innerHTML = ``; -function getSubtitles() { - const response = getPlayerResponse(); - let captionTracks = - response?.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? []; - captionTracks = captionTracks.reduce((result, captionTrack) => { - if ("languageCode" in captionTrack) { - const language = captionTrack?.languageCode - ? (0,utils/* langTo6391 */.eL)(captionTrack?.languageCode) - : undefined; - const url = captionTrack?.url || captionTrack?.baseUrl; - language && - url && - result.push({ - source: "youtube", - language, - isAutoGenerated: captionTrack?.kind === "asr", - url: `${ - url.startsWith("http") ? url : `${window.location.origin}/${url}` - }&fmt=json3`, - }); - } - return result; - }, []); - debug/* default */.Z.log("youtube subtitles:", captionTracks); - return captionTracks; -} + const label = document.createElement("span"); + label.classList.add("vot-segment-label"); + label.innerHTML = html; -// Get the video data from the player -async function getVideoData() { - const player = getPlayer(); - const response = getPlayerResponse(); // null in /embed - const data = getPlayerData(); - const { author, title } = data ?? {}; - const { - shortDescription: description, - isLive, - isLiveContent, - isUpcoming, - } = response?.videoDetails ?? {}; - const isPremiere = (!!isLive || !!isUpcoming) && !isLiveContent; - let detectedLanguage = await getLanguage( - player, - response, - title, - description, - author, - ); - if (!availableLangs.includes(detectedLanguage)) { - detectedLanguage = "en"; - } - const videoData = { - isLive: !!isLive, - isPremiere, - title, - description, - author, - detectedLanguage, + container.appendChild(translateButton); + container.appendChild(separator); + container.appendChild(pipButton); + container.appendChild(separator2); + container.appendChild(menuButton); + translateButton.appendChild(label); + + return { + container, + translateButton, + separator, + pipButton, + separator2, + menuButton, + label, }; - debug/* default */.Z.log("youtube video data:", videoData); - console.log("[VOT] Detected language: ", videoData.detectedLanguage); - return videoData; } -const youtubeUtils = { - isMobile, - getPlayer, - getPlayerResponse, - getPlayerData, - getVideoVolume, - getSubtitles, - getVideoData, - setVideoVolume, - videoSeek, -}; +function createVOTMenu(html) { + const container = document.createElement("vot-block"); + container.classList.add("vot-menu"); + container.hidden = true; -;// CONCATENATED MODULE: ./src/yandexProtobuf.js -// coursera & udemy translation help object -const VideoTranslationHelpObject = new protobuf.Type( - "VideoTranslationHelpObject", -) - .add(new protobuf.Field("target", 1, "string")) // video_file_url or subtitles_file_url - .add(new protobuf.Field("targetUrl", 2, "string")); // url to video_file or url to subtitles + const contentWrapper = document.createElement("vot-block"); + contentWrapper.classList.add("vot-menu-content-wrapper"); -const VideoTranslationRequest = new protobuf.Type("VideoTranslationRequest") - .add(new protobuf.Field("url", 3, "string")) - .add(new protobuf.Field("deviceId", 4, "string")) // removed? - .add(new protobuf.Field("firstRequest", 5, "bool")) // true for the first request, false for subsequent ones - .add(new protobuf.Field("duration", 6, "double")) - .add(new protobuf.Field("unknown2", 7, "int32")) // 1 1 - .add(new protobuf.Field("language", 8, "string")) // source language code - .add(new protobuf.Field("unknown3", 9, "int32")) // 0 - without translationHelp | 1 - with translationHelp (??? But it works without it) - .add(new protobuf.Field("unknown4", 10, "int32")) // 0 0 - .add( - new protobuf.Field( - "translationHelp", - 11, - "VideoTranslationHelpObject", - "repeated", - ), - ) // array for translation assistance ([0] -> {2: link to video, 1: "video_file_url"}, [1] -> {2: link to subtitles, 1: "subtitles_file_url"}) - .add(new protobuf.Field("responseLanguage", 14, "string")) - .add(new protobuf.Field("unknown5", 15, "int32")) // 0 - .add(new protobuf.Field("unknown6", 16, "int32")) // 1 - .add(new protobuf.Field("unknown7", 17, "int32")); // 0 + const headerContainer = document.createElement("vot-block"); + headerContainer.classList.add("vot-menu-header-container"); -const VideoSubtitlesRequest = new protobuf.Type("VideoSubtitlesRequest") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("language", 2, "string")); // source language code + const bodyContainer = document.createElement("vot-block"); + bodyContainer.classList.add("vot-menu-body-container"); -const VideoStreamRequest = new protobuf.Type("VideoStreamRequest") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("language", 2, "string")) - .add(new protobuf.Field("responseLanguage", 3, "string")); + const footerContainer = document.createElement("vot-block"); + footerContainer.classList.add("vot-menu-footer-container"); -const VideoStreamPingRequest = new protobuf.Type("VideoStreamPingRequest").add( - new protobuf.Field("pingId", 1, "int32"), -); + const titleContainer = document.createElement("vot-block"); + titleContainer.classList.add("vot-menu-title-container"); -const VideoTranslationResponse = new protobuf.Type("VideoTranslationResponse") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("duration", 2, "double")) - .add(new protobuf.Field("status", 4, "int32")) - .add(new protobuf.Field("remainingTime", 5, "int32")) // secs before translation (used as interval before next request in yaBrowser) - .add(new protobuf.Field("unknown0", 6, "int32")) // unknown 0 (1st request) -> 10 (2nd, 3th and etc requests) - .add(new protobuf.Field("unknown1", 7, "string")) - .add(new protobuf.Field("language", 8, "string")) // detected language (if the wrong one is set) - .add(new protobuf.Field("message", 9, "string")); + const title = document.createElement("vot-block"); + title.classList.add("vot-menu-title"); + title.innerHTML = html; -const VideoSubtitlesObject = new protobuf.Type("VideoSubtitlesObject") - .add(new protobuf.Field("language", 1, "string")) - .add(new protobuf.Field("url", 2, "string")) - .add(new protobuf.Field("unknown2", 3, "int32")) - .add(new protobuf.Field("translatedLanguage", 4, "string")) - .add(new protobuf.Field("translatedUrl", 5, "string")) - .add(new protobuf.Field("unknown5", 6, "int32")) - .add(new protobuf.Field("unknown6", 7, "int32")); + container.appendChild(contentWrapper); + contentWrapper.appendChild(headerContainer); + contentWrapper.appendChild(bodyContainer); + contentWrapper.appendChild(footerContainer); + headerContainer.appendChild(titleContainer); + titleContainer.appendChild(title); -const VideoSubtitlesResponse = new protobuf.Type("VideoSubtitlesResponse") - .add(new protobuf.Field("unknown0", 1, "int32")) - .add(new protobuf.Field("subtitles", 2, "VideoSubtitlesObject", "repeated")); + return { + container, + contentWrapper, + headerContainer, + bodyContainer, + footerContainer, + titleContainer, + title, + }; +} -const VideoStreamObject = new protobuf.Type("VideoStreamObject") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("timestamp", 2, "int64")); // timestamp in ms (probably means the time of 1 request to translate the stream) +function createVOTSelectLabel(text) { + const label = document.createElement("span"); + label.classList.add("vot-select-label"); + label.innerText = text; + return label; +} -const VideoStreamResponse = new protobuf.Type("VideoStreamResponse") - .add(new protobuf.Field("interval", 1, "int32")) // 20s - streaming, 10s - translating, 0s - there is no connection with the server (the broadcast is finished or deleted) - .add(new protobuf.Field("translatedInfo", 2, "VideoStreamObject")) - .add(new protobuf.Field("pingId", 3, "int32")); +function createVOTSelect(selectTitle, dialogTitle, items, options = {}) { + const onSelectCb = options.onSelectCb || function () {}; + const labelElement = options.labelElement || ""; + let selectedItems = []; -// * Yandex has been skipping any translation streams for a long time (whitelist always return true) -// * Most likely, it is already outdated and will not be used -// const VideoWhitelistStreamRequest = new protobuf.Type("VideoWhitelistStreamRequest") -// .add(new protobuf.Field("url", 1, "string")) -// .add(new protobuf.Field("deviceId", 4, "string")) + const container = document.createElement("vot-block"); + container.classList.add("vot-select"); -// const VideoWhitelistStreamResponse = new protobuf.Type("VideoWhitelistStreamResponse") -// .add(new protobuf.Field("inWhitelist", 1, "bool")) + if (labelElement) { + container.appendChild(labelElement); + } -// Create a root namespace and add the types -const root = new protobuf.Root() - .define("yandex") - .add(VideoTranslationHelpObject) - .add(VideoTranslationRequest) - .add(VideoTranslationResponse) - .add(VideoSubtitlesRequest) - .add(VideoSubtitlesObject) - .add(VideoSubtitlesResponse) - .add(VideoStreamPingRequest) - .add(VideoStreamRequest) - .add(VideoStreamObject) - .add(VideoStreamResponse); + const outer = document.createElement("vot-block"); + outer.classList.add("vot-select-outer"); -// Export the encoding and decoding functions -const yandexProtobuf = { - encodeTranslationRequest( - url, - duration, - requestLang, - responseLang, - translationHelp, - ) { - return root.VideoTranslationRequest.encode({ - url, - firstRequest: true, - duration, - unknown2: 1, - language: requestLang, - unknown3: 0, - unknown4: 0, - translationHelp, - responseLanguage: responseLang, - unknown5: 0, - unknown6: 1, - unknown7: 0, - }).finish(); - }, - decodeTranslationResponse(response) { - return root.VideoTranslationResponse.decode(new Uint8Array(response)); - }, - encodeSubtitlesRequest(url, requestLang) { - return root.VideoSubtitlesRequest.encode({ - url, - language: requestLang, - }).finish(); - }, - decodeSubtitlesResponse(response) { - return root.VideoSubtitlesResponse.decode(new Uint8Array(response)); - }, - encodeStreamPingRequest(pingId) { - return root.VideoStreamPingRequest.encode({ - pingId, - }).finish(); - }, - encodeStreamRequest(url, requestLang, responseLang) { - return root.VideoStreamRequest.encode({ - url, - language: requestLang, - responseLanguage: responseLang, - }).finish(); - }, - decodeStreamResponse(response) { - return root.VideoStreamResponse.decode(new Uint8Array(response)); - }, -}; + const title = document.createElement("span"); + title.classList.add("vot-select-title"); + title.innerText = selectTitle; + + if (selectTitle === undefined) { + title.innerText = items.find((i) => i.selected === true)?.label; + } + + const arrowIcon = document.createElement("vot-block"); + arrowIcon.classList.add("vot-select-arrow-icon"); + arrowIcon.innerHTML = ``; + + outer.append(title, arrowIcon); + outer.onclick = () => { + const votSelectDialog = createDialog(dialogTitle); + votSelectDialog.container.classList.add("vot-dialog-temp"); + votSelectDialog.container.hidden = false; + document.documentElement.appendChild(votSelectDialog.container); -;// CONCATENATED MODULE: ./src/config/alternativeUrls.js -// Sites host Invidious. I tested the performance only on invidious.kevin.rocks, youtu.be and inv.vern.cc -const sitesInvidious = [ - "invidious.snopyta.org", - "yewtu.be", - "invidious.kavin.rocks", - "vid.puffyan.us", - "invidious.namazso.eu", - "inv.riverside.rocks", - "yt.artemislena.eu", - "invidious.flokinet.to", - "invidious.esmailelbob.xyz", - "y.com.sb", - "invidious.nerdvpn.de", - "inv.vern.cc", - "invidious.slipfox.xyz", - "invidio.xamh.de", - "invidious.dhusch.de", -]; + const contentList = document.createElement("vot-block"); + contentList.classList.add("vot-select-content-list"); -// Sites host Piped. I tested the performance only on piped.video -const sitesPiped = [ - "piped.video", - "piped.tokhmi.xyz", - "piped.moomoo.me", - "piped.syncpundit.io", - "piped.mha.fi", - "watch.whatever.social", - "piped.garudalinux.org", - "efy.piped.pages.dev", - "watch.leptons.xyz", - "piped.lunar.icu", - "yt.dc09.ru", - "piped.mint.lgbt", - "il.ax", - "piped.privacy.com.de", - "piped.esmailelbob.xyz", - "piped.projectsegfau.lt", - "piped.in.projectsegfau.lt", - "piped.us.projectsegfau.lt", - "piped.privacydev.net", - "piped.palveluntarjoaja.eu", - "piped.smnz.de", - "piped.adminforge.de", - "piped.qdi.fi", - "piped.hostux.net", - "piped.chauvet.pro", - "piped.jotoma.de", - "piped.pfcd.me", - "piped.frontendfriendly.xyz", -]; + for (const item of items) { + const contentItem = document.createElement("vot-block"); + contentItem.classList.add("vot-select-content-item"); + contentItem.innerText = item.label; + contentItem.dataset.votSelected = item.selected; + contentItem.dataset.votValue = item.value; + if (item.disabled) { + contentItem.inert = true; + } -const sitesProxyTok = [ - "proxitok.pabloferreiro.es", - "proxitok.pussthecat.org", - "tok.habedieeh.re", - "proxitok.esmailelbob.xyz", - "proxitok.privacydev.net", - "tok.artemislena.eu", - "tok.adminforge.de", - "tik.hostux.net", // maybe instance doesn't working - "tt.vern.cc", - "cringe.whatever.social", - "proxitok.lunar.icu", - "proxitok.privacy.com.de", // maybe instance doesn't working -]; + contentItem.onclick = async (e) => { + if (e.target.inert) return; -// Sites host Peertube. I tested the performance only on dalek.zone and tube.shanti.cafe -const sitesPeertube = [ - "peertube.1312.media", - "tube.shanti.cafe", - "bee-tube.fr", - "video.sadmin.io", - "dalek.zone", - "review.peertube.biz", - "peervideo.club", - "tube.la-dina.net", - "peertube.tmp.rcp.tf", -]; + // removing the selected value for updating + const contentItems = contentList.childNodes; + contentItems.forEach((ci) => (ci.dataset.votSelected = false)); + // fixed selection after closing the modal and opening again + items.forEach((i) => (i.selected = i.value === item.value)); + contentItem.dataset.votSelected = true; + title.innerText = item.label; + // !!! use e.target.dataset.votValue instead of e.target.value !!! + await onSelectCb(e); + }; + contentList.appendChild(contentItem); + } -;// CONCATENATED MODULE: ./src/ui.js + // search logic + const votSearchLangTextfield = createTextfield( + localizationProvider.get("searchField"), + ); + votSearchLangTextfield.input.oninput = (e) => { + const searchText = e.target.value.toLowerCase(); + // check if there are lovercase characters in the string. used for smarter search + Array.from(selectedItems).forEach( + (ci) => (ci.hidden = !ci.innerText.toLowerCase().includes(searchText)), + ); + }; -function createHeader(html, level = 4) { - const header = document.createElement("vot-block"); - header.classList.add("vot-header"); - header.classList.add(`vot-header-level-${level}`); - header.innerHTML = html; + votSelectDialog.bodyContainer.append( + votSearchLangTextfield.container, + contentList, + ); + selectedItems = contentList.childNodes; - return header; -} + // remove the modal so that they do not accumulate + votSelectDialog.backdrop.onclick = votSelectDialog.closeButton.onclick = + () => { + votSelectDialog.container.remove(); + selectedItems = []; + }; + }; -function createInformation(html, valueHtml) { - const container = document.createElement("vot-block"); - container.classList.add("vot-info"); + container.append(outer); - const header = document.createElement("vot-block"); - header.innerHTML = html; + const setTitle = (newTitle) => { + title.innerText = newTitle; + }; - const value = document.createElement("vot-block"); - value.innerHTML = valueHtml; + const setSelected = (val) => { + Array.from(selectedItems) + .filter((ci) => !ci.inert) + .forEach((ci) => (ci.dataset.votSelected = ci.dataset.votValue === val)); + items.forEach((i) => (i.selected = String(i.value) === val)); + }; - container.appendChild(header); - container.appendChild(value); + const updateItems = (newItems) => { + items = newItems; + }; return { container, - header, - value, + title, + arrowIcon, + labelElement, + setTitle, + setSelected, + updateItems, }; } -function createButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-button"); - button.innerHTML = html; - - return button; -} +function createVOTLanguageSelect(options) { + const fromTitle = options.fromTitle || "#UNDEFINED"; + const fromDialogTitle = options.fromDialogTitle || "#UNDEFINED"; + const fromItems = options.fromItems || []; + const fromOnSelectCB = options.fromOnSelectCB || function () {}; + const toTitle = options.toTitle || "#UNDEFINED"; + const toDialogTitle = options.toDialogTitle || "#UNDEFINED"; + const toItems = options.toItems || []; + const toOnSelectCB = options.toOnSelectCB || function () {}; -function createTextButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-text-button"); - button.innerHTML = html; + const container = document.createElement("vot-block"); + container.classList.add("vot-lang-select"); - return button; -} + const fromSelect = createVOTSelect(fromTitle, fromDialogTitle, fromItems, { + onSelectCb: fromOnSelectCB, + }); -function createOutlinedButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-outlined-button"); - button.innerHTML = html; + const icon = document.createElement("vot-block"); + icon.classList.add("vot-lang-select-icon"); + icon.innerHTML = ``; - return button; -} + const toSelect = createVOTSelect(toTitle, toDialogTitle, toItems, { + onSelectCb: toOnSelectCB, + }); -function createIconButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-icon-button"); - button.innerHTML = html; + container.append(fromSelect.container, icon, toSelect.container); - return button; + return { + container, + fromSelect, + icon, + toSelect, + }; } -function createCheckbox(html, value = false) { - const container = document.createElement("label"); - container.classList.add("vot-checkbox"); - - const input = document.createElement("input"); - input.type = "checkbox"; - input.checked = Boolean(value); - - const label = document.createElement("span"); - label.innerHTML = html; +/* harmony default export */ const ui = ({ + createHeader, + createInformation, + createButton, + createTextButton, + createOutlinedButton, + createIconButton, + createCheckbox, + createSlider, + createTextfield, + createDialog, + createVOTButton, + createVOTMenu, + createVOTSelectLabel, + createVOTSelect, + createVOTLanguageSelect, + updateSlider, +}); - container.appendChild(input); - container.appendChild(label); +;// CONCATENATED MODULE: ./src/utils/VOTLocalizedError.js - return { container, input, label }; -} -function updateSlider(input) { - const value = parseFloat(input.value); - const min = input.min === "" ? 0 : parseFloat(input.min); - const max = input.max === "" ? 100 : parseFloat(input.max); - const progress = (value - min) / (max - min); - input.parentElement.setAttribute("style", `--vot-progress: ${progress}`); +class VOTLocalizedError extends Error { + constructor(message) { + super(localizationProvider.getDefault(message)); + this.name = "VOTLocalizedError"; + this.unlocalizedMessage = message; + this.localizedMessage = localizationProvider.get(message); + } } -function createSlider(html, value = 50, min = 0, max = 100) { - const container = document.createElement("vot-block"); - container.classList.add("vot-slider"); +;// CONCATENATED MODULE: ./src/utils/translateApis.js - const input = document.createElement("input"); - input.type = "range"; - input.min = min; - input.max = max; - input.value = value; - const label = document.createElement("span"); - label.innerHTML = html; - container.appendChild(input); - container.appendChild(label); +const HTTP_TIMEOUT = 3000; - input.addEventListener("input", (e) => updateSlider(e.target)); - updateSlider(input); +async function fetchWithTimeout(url, options) { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT); - return { - container, - input, - label, - }; + try { + return await fetch(url, { + ...options, + signal: controller.signal, + }); + } catch (error) { + console.error("Fetch timed-out. Error:", error); + return error; + } finally { + clearTimeout(timeoutId); + } } -function createTextfield( - html, - value = "", - placeholder = " ", - multiline = false, -) { - const container = document.createElement("vot-block"); - container.classList.add("vot-textfield"); +const YandexTranslateAPI = { + async translate(text, lang) { + // Limit: 10k symbols + // + // Lang examples: + // en-ru, uk-ru, ru-en... + // ru, en (instead of auto-ru, auto-en) - const input = document.createElement(multiline ? "textarea" : "input"); - input.placeholder = placeholder; - input.value = value; + try { + const response = await fetchWithTimeout(config/* translateUrls */.rw.yandex, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + text, + lang, + }), + }); - const label = document.createElement("span"); - label.innerHTML = html; + if (response instanceof Error) { + throw response; + } - container.appendChild(input); - container.appendChild(label); + const content = await response.json(); - return { - container, - input, - label, - }; -} + if (content.code !== 200) { + throw content.message; + } -function createDialog(html) { - const container = document.createElement("vot-block"); - container.classList.add("vot-dialog-container"); - container.hidden = true; + return content.text[0]; + } catch (error) { + console.error("Error translating text:", error); + return text; + } + }, - const backdrop = document.createElement("vot-block"); - backdrop.classList.add("vot-dialog-backdrop"); + async detect(text, lang) { + // Limit: 10k symbols + try { + const response = await fetchWithTimeout(config/* detectUrls */.QL.yandex, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + text, + lang, + }), + }); - const dialog = document.createElement("vot-block"); - dialog.classList.add("vot-dialog"); + if (response instanceof Error) { + throw response; + } - const contentWrapper = document.createElement("vot-block"); - contentWrapper.classList.add("vot-dialog-content-wrapper"); + const content = await response.json(); + if (content.code !== 200) { + throw content.message; + } - const headerContainer = document.createElement("vot-block"); - headerContainer.classList.add("vot-dialog-header-container"); + return content.lang ?? "en"; + } catch (error) { + console.error("Error translating text:", error); + return "en"; + } + }, +}; - const bodyContainer = document.createElement("vot-block"); - bodyContainer.classList.add("vot-dialog-body-container"); +const RustServerAPI = { + async detect(text) { + try { + const response = await fetch(config/* detectUrls */.QL.rustServer, { + method: "POST", + body: text, + }); - const footerContainer = document.createElement("vot-block"); - footerContainer.classList.add("vot-dialog-footer-container"); + if (response instanceof Error) { + throw response; + } - const titleContainer = document.createElement("vot-block"); - titleContainer.classList.add("vot-dialog-title-container"); + return await response.text(); + } catch (error) { + console.error("Error getting lang from text:", error); + return "en"; + } + }, +}; - const closeButton = createIconButton( - ``, +async function translate(text, fromLang = "", toLang = "ru") { + const service = await storage/* votStorage */.d.get( + "translationService", + config/* defaultTranslationService */.mE, ); - closeButton.classList.add("vot-dialog-close-button"); - - backdrop.onclick = closeButton.onclick = () => { - container.hidden = true; - }; - - const title = document.createElement("vot-block"); - title.classList.add("vot-dialog-title"); - title.innerHTML = html; - - container.appendChild(backdrop); - container.appendChild(dialog); - dialog.appendChild(contentWrapper); - contentWrapper.appendChild(headerContainer); - contentWrapper.appendChild(bodyContainer); - contentWrapper.appendChild(footerContainer); - headerContainer.appendChild(titleContainer); - headerContainer.appendChild(closeButton); - titleContainer.appendChild(title); + switch (service) { + case "yandex": { + const langPair = fromLang && toLang ? `${fromLang}-${toLang}` : toLang; + return await YandexTranslateAPI.translate(text, langPair); + } + default: + return text; + } +} - return { - container, - backdrop, - dialog, - contentWrapper, - headerContainer, - bodyContainer, - footerContainer, - titleContainer, - closeButton, - title, - }; +async function detect(text) { + const service = await storage/* votStorage */.d.get("detectService", config/* defaultDetectService */.K2); + switch (service) { + case "yandex": + return await YandexTranslateAPI.detect(text); + case "rust-server": + return await RustServerAPI.detect(text); + default: + return "en"; + } } -function createVOTButton(html) { - const container = document.createElement("vot-block"); - container.classList.add("vot-segmented-button"); +const translateServices = ["yandex"]; +const detectServices = ["yandex", "rust-server"]; - const translateButton = document.createElement("vot-block"); - translateButton.classList.add("vot-segment"); - translateButton.classList.add("vot-translate-button"); - translateButton.innerHTML = ``; - const separator = document.createElement("vot-block"); - separator.classList.add("vot-separator"); - const pipButton = document.createElement("vot-block"); - pipButton.classList.add("vot-segment-only-icon"); - pipButton.innerHTML = ``; +;// CONCATENATED MODULE: ./src/utils/youtubeUtils.js - const separator2 = document.createElement("vot-block"); - separator2.classList.add("vot-separator"); - const menuButton = document.createElement("vot-block"); - menuButton.classList.add("vot-segment-only-icon"); - menuButton.innerHTML = ``; - const label = document.createElement("span"); - label.classList.add("vot-segment-label"); - label.innerHTML = html; - container.appendChild(translateButton); - container.appendChild(separator); - container.appendChild(pipButton); - container.appendChild(separator2); - container.appendChild(menuButton); - translateButton.appendChild(label); - return { - container, - translateButton, - separator, - pipButton, - separator2, - menuButton, - label, - }; -} +// Get the language code from the response or the text +async function getLanguage(player, response, title, description) { + if ( + !window.location.hostname.includes("m.youtube.com") && + player?.getAudioTrack + ) { + // ! Experimental ! get lang from selected audio track if availabled + const audioTracks = player.getAudioTrack(); + const trackInfo = audioTracks?.getLanguageInfo(); // get selected track info (id === "und" if tracks are not available) + if (trackInfo?.id !== "und") { + return langTo6391(trackInfo.id.split(".")[0]); + } + } + + // TODO: If the audio tracks will work fine, transfer the receipt of captions to the audioTracks variable + // Check if there is an automatic caption track in the response + const captionTracks = + response?.captions?.playerCaptionsTracklistRenderer?.captionTracks; + if (captionTracks?.length) { + const autoCaption = captionTracks.find((caption) => caption.kind === "asr"); + if (autoCaption && autoCaption.languageCode) { + return langTo6391(autoCaption.languageCode); + } + } -function createVOTMenu(html) { - const container = document.createElement("vot-block"); - container.classList.add("vot-menu"); - container.hidden = true; + // If there is no caption track, use detect to get the language code from the description - const contentWrapper = document.createElement("vot-block"); - contentWrapper.classList.add("vot-menu-content-wrapper"); + const deletefilter = [ + /(?:https?|ftp):\/\/[\S]+/g, //temp fix + /https?:\/\/\S+|www\.\S+/gm, + /\b\S+\.\S+/gm, + /#[^\s#]+/g, // hash tags + /Auto-generated by YouTube/g, + /Provided to YouTube by/g, + /Released on/g, + /Bitcoin/g, + /USDT/g, + /Paypal/g, + ]; - const headerContainer = document.createElement("vot-block"); - headerContainer.classList.add("vot-menu-header-container"); + const cleanedDescription = description + .split("\n\n") + .filter((line) => !deletefilter.some((regex) => regex.test(line))) + .join("\n\n"); - const bodyContainer = document.createElement("vot-block"); - bodyContainer.classList.add("vot-menu-body-container"); + const cleanText = [title, cleanedDescription] + .join(" ") + .replace(/[^\p{L}\s]/gu, " ") + .trim() + .replace(/\s+/g, " ") + .slice(0, 1000); - const footerContainer = document.createElement("vot-block"); - footerContainer.classList.add("vot-menu-footer-container"); + return await detect(cleanText); +} - const titleContainer = document.createElement("vot-block"); - titleContainer.classList.add("vot-menu-title-container"); +function isMobile() { + return /^m\.youtube\.com$/.test(window.location.hostname); +} - const title = document.createElement("vot-block"); - title.classList.add("vot-menu-title"); - title.innerHTML = html; +function getPlayer() { + if (window.location.pathname.startsWith("/shorts/")) { + return isMobile() + ? document.querySelector("#movie_player") + : document.querySelector("#shorts-player"); + } - container.appendChild(contentWrapper); - contentWrapper.appendChild(headerContainer); - contentWrapper.appendChild(bodyContainer); - contentWrapper.appendChild(footerContainer); - headerContainer.appendChild(titleContainer); - titleContainer.appendChild(title); + return document.querySelector("#movie_player"); +} - return { - container, - contentWrapper, - headerContainer, - bodyContainer, - footerContainer, - titleContainer, - title, - }; +function getPlayerResponse() { + const player = getPlayer(); + if (player?.getPlayerResponse) + return player?.getPlayerResponse?.call() ?? null; + return player?.data?.playerResponse ?? null; } -function createVOTSelectLabel(text) { - const label = document.createElement("span"); - label.classList.add("vot-select-label"); - label.innerText = text; - return label; +function getPlayerData() { + const player = getPlayer(); + if (player?.getVideoData) return player?.getVideoData?.call() ?? null; + return player?.data?.playerResponse?.videoDetails ?? null; } -function createVOTSelect(selectTitle, dialogTitle, items, options = {}) { - const onSelectCb = options.onSelectCb || function () {}; - const labelElement = options.labelElement || ""; - let selectedItems = []; +function getVideoVolume() { + const player = getPlayer(); + if (player?.getVolume) { + return player.getVolume.call() / 100; + } - const container = document.createElement("vot-block"); - container.classList.add("vot-select"); + return 1; +} - if (labelElement) { - container.appendChild(labelElement); +function setVideoVolume(volume) { + const player = getPlayer(); + if (player?.setVolume) { + player.setVolume(Math.round(volume * 100)); + return true; } +} - const outer = document.createElement("vot-block"); - outer.classList.add("vot-select-outer"); +function videoSeek(video, time) { + // * TIME IN MS + debug/* default */.A.log("videoSeek", time); + const preTime = + getPlayer()?.getProgressState()?.seekableEnd || video.currentTime; + const finalTime = preTime - time; // we always throw it to the end of the stream - time + video.currentTime = finalTime; +} - const title = document.createElement("span"); - title.classList.add("vot-select-title"); - title.innerText = selectTitle; +function getSubtitles() { + const response = getPlayerResponse(); + let captionTracks = + response?.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? []; + captionTracks = captionTracks.reduce((result, captionTrack) => { + if ("languageCode" in captionTrack) { + const language = captionTrack?.languageCode + ? langTo6391(captionTrack?.languageCode) + : undefined; + const url = captionTrack?.url || captionTrack?.baseUrl; + language && + url && + result.push({ + source: "youtube", + language, + isAutoGenerated: captionTrack?.kind === "asr", + url: `${ + url.startsWith("http") ? url : `${window.location.origin}/${url}` + }&fmt=json3`, + }); + } + return result; + }, []); + debug/* default */.A.log("youtube subtitles:", captionTracks); + return captionTracks; +} - if (selectTitle === undefined) { - title.innerText = items.find((i) => i.selected === true)?.label; +// Get the video data from the player +async function getVideoData() { + const player = getPlayer(); + const response = getPlayerResponse(); // null in /embed + const data = getPlayerData(); + const { title } = data ?? {}; + const { + shortDescription: description, + isLive, + isLiveContent, + isUpcoming, + } = response?.videoDetails ?? {}; + const isPremiere = (!!isLive || !!isUpcoming) && !isLiveContent; + let detectedLanguage = await getLanguage( + player, + response, + title, + description, + ); + if (!availableLangs.includes(detectedLanguage)) { + detectedLanguage = "en"; } + const videoData = { + isLive: !!isLive, + isPremiere, + title, + description, + detectedLanguage, + }; + debug/* default */.A.log("youtube video data:", videoData); + console.log("[VOT] Detected language: ", videoData.detectedLanguage); + return videoData; +} - const arrowIcon = document.createElement("vot-block"); - arrowIcon.classList.add("vot-select-arrow-icon"); - arrowIcon.innerHTML = ``; +/* harmony default export */ const youtubeUtils = ({ + isMobile, + getPlayer, + getPlayerResponse, + getPlayerData, + getVideoVolume, + getSubtitles, + getVideoData, + setVideoVolume, + videoSeek, +}); - outer.append(title, arrowIcon); - outer.onclick = () => { - const votSelectDialog = createDialog(dialogTitle); - votSelectDialog.container.classList.add("vot-dialog-temp"); - votSelectDialog.container.hidden = false; - document.documentElement.appendChild(votSelectDialog.container); +;// CONCATENATED MODULE: ./src/utils/utils.js - const contentList = document.createElement("vot-block"); - contentList.classList.add("vot-select-content-list"); - for (const item of items) { - const contentItem = document.createElement("vot-block"); - contentItem.classList.add("vot-select-content-item"); - contentItem.innerText = item.label; - contentItem.dataset.votSelected = item.selected; - contentItem.dataset.votValue = item.value; - if (item.disabled) { - contentItem.inert = true; - } - contentItem.onclick = async (e) => { - if (e.target.inert) return; +const userlang = navigator.language || navigator.userLanguage; +const lang = userlang?.substr(0, 2)?.toLowerCase() ?? "en"; - // removing the selected value for updating - const contentItems = contentList.childNodes; - contentItems.forEach((ci) => (ci.dataset.votSelected = false)); - // fixed selection after closing the modal and opening again - items.forEach((i) => (i.selected = i.value === item.value)); +// not used +// function waitForElm(selector) { +// // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists +// return new Promise((resolve) => { +// const element = document.querySelector(selector); +// if (element) { +// return resolve(element); +// } + +// const observer = new MutationObserver(() => { +// const element = document.querySelector(selector); +// if (element) { +// resolve(element); +// observer.disconnect(); +// } +// }); + +// observer.observe(document.body, { +// childList: true, +// subtree: true, +// once: true, +// }); +// }); +// } + +// not used +// const sleep = (m) => new Promise((r) => setTimeout(r, m)); - contentItem.dataset.votSelected = true; - title.innerText = item.label; +const getVideoId = (service, video) => { + let url = new URL(window.location.href); + + switch (service) { + case "piped": + case "invidious": + case "youtube": { + if (url.searchParams.has("enablejsapi")) { + const videoUrl = youtubeUtils.getPlayer().getVideoUrl(); + url = new URL(videoUrl); + } + + return ( + url.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1] || + url.searchParams.get("v") + ); + } + case "vk": + if (url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)) { + return url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1); + } else if (url.searchParams.get("z")) { + return url.searchParams.get("z").split("/")[0]; + } else if (url.searchParams.get("oid") && url.searchParams.get("id")) { + return `video-${Math.abs( + url.searchParams.get("oid"), + )}_${url.searchParams.get("id")}`; + } else { + return false; + } + case "nine_gag": + case "9gag": + case "gag": + return url.pathname.match(/gag\/([^/]+)/)?.[1]; + case "twitch": + if (/^m\.twitch\.tv$/.test(window.location.hostname)) { + const linkUrl = document.head.querySelector('link[rel="canonical"]'); + return ( + linkUrl?.href.match(/videos\/([^/]+)/)?.[0] || url.pathname.slice(1) + ); + } else if (/^player\.twitch\.tv$/.test(window.location.hostname)) { + return `videos/${url.searchParams.get("video")}`; + } else if (/^clips\.twitch\.tv$/.test(window.location.hostname)) { + // get link to twitch channel (ex.: https://www.twitch.tv/xqc) + const channelLink = document.querySelector( + ".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']", + ); + if (!channelLink) { + return false; + } - // !!! use e.target.dataset.votValue instead of e.target.value !!! - await onSelectCb(e); - }; - contentList.appendChild(contentItem); + const channelName = channelLink.href.replace( + "https://www.twitch.tv/", + "", + ); + return `${channelName}/clip/${url.searchParams.get("clip")}`; + } else if (url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)) { + return url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]; + } else { + return url.pathname.match(/(?:videos)\/([^/]+)/)?.[0]; + } + case "proxytok": + return url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; + case "tiktok": { + let id = url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; + if (!id) { + const playerEl = video.closest(".xgplayer-playing, .tiktok-web-player"); + const itemEl = playerEl?.closest( + 'div[data-e2e="recommend-list-item-container"]', + ); + const authorEl = itemEl?.querySelector( + 'a[data-e2e="video-author-avatar"]', + ); + if (playerEl && authorEl) { + const videoId = playerEl.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1); + const author = authorEl.href?.match(/.*(@.*)$/)?.at(1); + if (videoId && author) { + id = `${author}/video/${videoId}`; + } + } + } + return id; } + case "vimeo": { + const appId = url.searchParams.get("app_id"); + const videoId = + url.pathname.match(/[^/]+\/[^/]+$/)?.[0] || + url.pathname.match(/[^/]+$/)?.[0]; - // search logic - const votSearchLangTextfield = createTextfield( - localizationProvider/* localizationProvider */.V.get("searchField"), - ); - - votSearchLangTextfield.input.oninput = (e) => { - const searchText = e.target.value.toLowerCase(); - // check if there are lovercase characters in the string. used for smarter search - Array.from(selectedItems).forEach( - (ci) => (ci.hidden = !ci.innerText.toLowerCase().includes(searchText)), + return appId ? `${videoId}?app_id=${appId}` : videoId; + } + case "xvideos": + return url.pathname.match(/[^/]+\/[^/]+$/)?.[0]; + case "pornhub": + return ( + url.searchParams.get("viewkey") || + url.pathname.match(/embed\/([^/]+)/)?.[1] ); - }; - - votSelectDialog.bodyContainer.append( - votSearchLangTextfield.container, - contentList, - ); - selectedItems = contentList.childNodes; - - // remove the modal so that they do not accumulate - votSelectDialog.backdrop.onclick = votSelectDialog.closeButton.onclick = - () => { - votSelectDialog.container.remove(); - selectedItems = []; - }; - }; + case "twitter": + return url.pathname.match(/status\/([^/]+)/)?.[1]; + case "udemy": + return url.pathname; + case "rumble": + return url.pathname; + case "facebook": + return url.pathname; + case "rutube": + return url.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1]; + case "coub": + if (url.pathname.includes("/view")) { + return url.pathname.match(/view\/([^/]+)/)?.[1]; + } else if (url.pathname.includes("/embed")) { + return url.pathname.match(/embed\/([^/]+)/)?.[1]; + } else { + return document.querySelector(".coub.active")?.dataset?.permalink; + } + case "bilibili": { + const bvid = url.searchParams.get("bvid"); + if (bvid) { + return bvid; + } else { + let vid = url.pathname.match(/video\/([^/]+)/)?.[1]; + if (vid && url.search && url.searchParams.get("p") !== null) { + vid += `/?p=${url.searchParams.get("p")}`; + } + return vid; + } + } + case "mail_ru": + if (url.pathname.startsWith("/v/") || url.pathname.startsWith("/mail/")) { + return url.pathname; + } else if (url.pathname.match(/video\/embed\/([^/]+)/)) { + const referer = document.querySelector( + ".b-video-controls__mymail-link", + ); + if (!referer) { + return false; + } - container.append(outer); + return referer?.href.split("my.mail.ru")?.[1]; + } + return false; + case "bitchute": + return url.pathname.match(/video\/([^/]+)/)?.[1]; + case "coursera": + // ! LINK SHOULD BE LIKE THIS https://www.coursera.org/learn/learning-how-to-learn/lecture/75EsZ + // return url.pathname.match(/lecture\/([^/]+)\/([^/]+)/)?.[1]; // <--- COURSE PREVIEW + return url.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0]; // <--- COURSE PASSING (IF YOU LOGINED TO COURSERA) + case "eporner": + // ! LINK SHOULD BE LIKE THIS eporner.com/video-XXXXXXXXX/isdfsd-dfjsdfjsdf-dsfsdf-dsfsda-dsad-ddsd + return url.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0]; + case "peertube": + return url.pathname.match(/\/w\/([^/]+)/)?.[0]; + case "dailymotion": { + // we work in the context of the player + // geo.dailymotion.com + const plainPlayerConfig = Array.from( + document.querySelectorAll("*"), + ).filter((s) => s.innerHTML.trim().includes(".m3u8")); + try { + let videoUrl = plainPlayerConfig[1].lastChild.src; + return videoUrl.match(/\/video\/(\w+)\.m3u8/)?.[1]; + } catch (e) { + console.error("[VOT]", e); + return false; + } + } + case "trovo": { + if (!url.pathname.startsWith("/s/")) { + return false; + } - const setTitle = (newTitle) => { - title.innerText = newTitle; - }; + const vid = url.searchParams.get("vid"); + if (!vid) { + return false; + } - const setSelected = (val) => { - Array.from(selectedItems) - .filter((ci) => !ci.inert) - .forEach((ci) => (ci.dataset.votSelected = ci.dataset.votValue === val)); - items.forEach((i) => (i.selected = String(i.value) === val)); - }; + const path = url.pathname.match(/([^/]+)\/([\d]+)/)?.[0]; + if (!path) { + return false; + } - const updateItems = (newItems) => { - items = newItems; - }; + return `${path}?vid=${vid}`; + } + case "yandexdisk": + return url.pathname.match(/\/i\/([^/]+)/)?.[1]; + case "coursehunter": { + const courseId = url.pathname.match(/\/course\/([^/]+)/)?.[1]; + return courseId ? courseId + url.search : false; + } + case "ok.ru": { + return url.pathname.match(/\/video\/(\d+)/)?.[0]; + } + case "googledrive": + return url.searchParams.get("docid"); + case "bannedvideo": + return url.searchParams.get("id"); + case "weverse": + return url.pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[0]; + case "newgrounds": + return url.pathname.match(/([^/]+)\/(view)\/([^/]+)/)?.[0]; + case "egghead": + return url.pathname; + case "youku": + return url.pathname.match(/v_show\/id_[\w=]+/)?.[0]; + default: + return false; + } +}; - return { - container, - title, - arrowIcon, - labelElement, - setTitle, - setSelected, - updateItems, - }; +function secsToStrTime(secs) { + const minutes = Math.floor(secs / 60); + const seconds = Math.floor(secs % 60); + if (minutes >= 60) { + return localizationProvider.get("translationTakeMoreThanHour"); + } else if (minutes >= 10 && minutes % 10) { + return localizationProvider + .get("translationTakeApproximatelyMinutes") + .replace("{0}", minutes); + } else if (minutes == 1 || (minutes == 0 && seconds > 0)) { + return localizationProvider.get("translationTakeAboutMinute"); + } else { + return localizationProvider + .get("translationTakeApproximatelyMinute") + .replace("{0}", minutes); + } +} +function langTo6391(lang) { + // convert lang to ISO 639-1 + return lang.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]; } -function createVOTLanguageSelect(options) { - const fromTitle = options.fromTitle || "#UNDEFINED"; - const fromDialogTitle = options.fromDialogTitle || "#UNDEFINED"; - const fromItems = options.fromItems || []; - const fromOnSelectCB = options.fromOnSelectCB || function () {}; - const toTitle = options.toTitle || "#UNDEFINED"; - const toDialogTitle = options.toDialogTitle || "#UNDEFINED"; - const toItems = options.toItems || []; - const toOnSelectCB = options.toOnSelectCB || function () {}; - - const container = document.createElement("vot-block"); - container.classList.add("vot-lang-select"); - - const fromSelect = createVOTSelect(fromTitle, fromDialogTitle, fromItems, { - onSelectCb: fromOnSelectCB, - }); - - const icon = document.createElement("vot-block"); - icon.classList.add("vot-lang-select-icon"); - icon.innerHTML = ``; - - const toSelect = createVOTSelect(toTitle, toDialogTitle, toItems, { - onSelectCb: toOnSelectCB, - }); - - container.append(fromSelect.container, icon, toSelect.container); - - return { - container, - fromSelect, - icon, - toSelect, - }; +function isPiPAvailable() { + return ( + "pictureInPictureEnabled" in document && document.pictureInPictureEnabled + ); } -/* harmony default export */ const ui = ({ - createHeader, - createInformation, - createButton, - createTextButton, - createOutlinedButton, - createIconButton, - createCheckbox, - createSlider, - createTextfield, - createDialog, - createVOTButton, - createVOTMenu, - createVOTSelectLabel, - createVOTSelect, - createVOTLanguageSelect, - updateSlider, -}); +function initHls() { + return typeof Hls != "undefined" && Hls?.isSupported() + ? new Hls({ + debug: false, // turn it on manually if necessary + lowLatencyMode: true, + backBufferLength: 90, + }) + : undefined; +} + + ;// CONCATENATED MODULE: ./src/utils/volume.js // element - audio / video element @@ -2621,6 +2404,157 @@ function syncVolume(element, sliderVolume, otherSliderVolume, tempVolume) { +;// CONCATENATED MODULE: ./src/yandexProtobuf.js +// coursera & udemy translation help object +const VideoTranslationHelpObject = new protobuf.Type( + "VideoTranslationHelpObject", +) + .add(new protobuf.Field("target", 1, "string")) // video_file_url or subtitles_file_url + .add(new protobuf.Field("targetUrl", 2, "string")); // url to video_file or url to subtitles + +const VideoTranslationRequest = new protobuf.Type("VideoTranslationRequest") + .add(new protobuf.Field("url", 3, "string")) + .add(new protobuf.Field("deviceId", 4, "string")) // removed? + .add(new protobuf.Field("firstRequest", 5, "bool")) // true for the first request, false for subsequent ones + .add(new protobuf.Field("duration", 6, "double")) + .add(new protobuf.Field("unknown2", 7, "int32")) // 1 1 + .add(new protobuf.Field("language", 8, "string")) // source language code + .add(new protobuf.Field("unknown3", 9, "int32")) // 0 - without translationHelp | 1 - with translationHelp (??? But it works without it) + .add(new protobuf.Field("unknown4", 10, "int32")) // 0 0 + .add( + new protobuf.Field( + "translationHelp", + 11, + "VideoTranslationHelpObject", + "repeated", + ), + ) // array for translation assistance ([0] -> {2: link to video, 1: "video_file_url"}, [1] -> {2: link to subtitles, 1: "subtitles_file_url"}) + .add(new protobuf.Field("responseLanguage", 14, "string")) + .add(new protobuf.Field("unknown5", 15, "int32")) // 0 + .add(new protobuf.Field("unknown6", 16, "int32")) // 1 + .add(new protobuf.Field("unknown7", 17, "int32")); // 0 + +const VideoSubtitlesRequest = new protobuf.Type("VideoSubtitlesRequest") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("language", 2, "string")); // source language code + +const VideoStreamRequest = new protobuf.Type("VideoStreamRequest") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("language", 2, "string")) + .add(new protobuf.Field("responseLanguage", 3, "string")); + +const VideoStreamPingRequest = new protobuf.Type("VideoStreamPingRequest").add( + new protobuf.Field("pingId", 1, "int32"), +); + +const VideoTranslationResponse = new protobuf.Type("VideoTranslationResponse") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("duration", 2, "double")) + .add(new protobuf.Field("status", 4, "int32")) + .add(new protobuf.Field("remainingTime", 5, "int32")) // secs before translation (used as interval before next request in yaBrowser) + .add(new protobuf.Field("unknown0", 6, "int32")) // unknown 0 (1st request) -> 10 (2nd, 3th and etc requests) + .add(new protobuf.Field("unknown1", 7, "string")) + .add(new protobuf.Field("language", 8, "string")) // detected language (if the wrong one is set) + .add(new protobuf.Field("message", 9, "string")); + +const VideoSubtitlesObject = new protobuf.Type("VideoSubtitlesObject") + .add(new protobuf.Field("language", 1, "string")) + .add(new protobuf.Field("url", 2, "string")) + .add(new protobuf.Field("unknown2", 3, "int32")) + .add(new protobuf.Field("translatedLanguage", 4, "string")) + .add(new protobuf.Field("translatedUrl", 5, "string")) + .add(new protobuf.Field("unknown5", 6, "int32")) + .add(new protobuf.Field("unknown6", 7, "int32")); + +const VideoSubtitlesResponse = new protobuf.Type("VideoSubtitlesResponse") + .add(new protobuf.Field("unknown0", 1, "int32")) + .add(new protobuf.Field("subtitles", 2, "VideoSubtitlesObject", "repeated")); + +const VideoStreamObject = new protobuf.Type("VideoStreamObject") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("timestamp", 2, "int64")); // timestamp in ms (probably means the time of 1 request to translate the stream) + +const VideoStreamResponse = new protobuf.Type("VideoStreamResponse") + .add(new protobuf.Field("interval", 1, "int32")) // 20s - streaming, 10s - translating, 0s - there is no connection with the server (the broadcast is finished or deleted) + .add(new protobuf.Field("translatedInfo", 2, "VideoStreamObject")) + .add(new protobuf.Field("pingId", 3, "int32")); + +// * Yandex has been skipping any translation streams for a long time (whitelist always return true) +// * Most likely, it is already outdated and will not be used +// const VideoWhitelistStreamRequest = new protobuf.Type("VideoWhitelistStreamRequest") +// .add(new protobuf.Field("url", 1, "string")) +// .add(new protobuf.Field("deviceId", 4, "string")) + +// const VideoWhitelistStreamResponse = new protobuf.Type("VideoWhitelistStreamResponse") +// .add(new protobuf.Field("inWhitelist", 1, "bool")) + +// Create a root namespace and add the types +const root = new protobuf.Root() + .define("yandex") + .add(VideoTranslationHelpObject) + .add(VideoTranslationRequest) + .add(VideoTranslationResponse) + .add(VideoSubtitlesRequest) + .add(VideoSubtitlesObject) + .add(VideoSubtitlesResponse) + .add(VideoStreamPingRequest) + .add(VideoStreamRequest) + .add(VideoStreamObject) + .add(VideoStreamResponse); + +// Export the encoding and decoding functions +const yandexProtobuf = { + encodeTranslationRequest( + url, + duration, + requestLang, + responseLang, + translationHelp, + ) { + return root.VideoTranslationRequest.encode({ + url, + firstRequest: true, + duration, + unknown2: 1, + language: requestLang, + unknown3: 0, + unknown4: 0, + translationHelp, + responseLanguage: responseLang, + unknown5: 0, + unknown6: 1, + unknown7: 0, + }).finish(); + }, + decodeTranslationResponse(response) { + return root.VideoTranslationResponse.decode(new Uint8Array(response)); + }, + encodeSubtitlesRequest(url, requestLang) { + return root.VideoSubtitlesRequest.encode({ + url, + language: requestLang, + }).finish(); + }, + decodeSubtitlesResponse(response) { + return root.VideoSubtitlesResponse.decode(new Uint8Array(response)); + }, + encodeStreamPingRequest(pingId) { + return root.VideoStreamPingRequest.encode({ + pingId, + }).finish(); + }, + encodeStreamRequest(url, requestLang, responseLang) { + return root.VideoStreamRequest.encode({ + url, + language: requestLang, + responseLanguage: responseLang, + }).finish(); + }, + decodeStreamResponse(response) { + return root.VideoStreamResponse.decode(new Uint8Array(response)); + }, +}; + // EXTERNAL MODULE: ./node_modules/bowser/es5.js var es5 = __webpack_require__("./node_modules/bowser/es5.js"); ;// CONCATENATED MODULE: ./src/getUUID.js @@ -2644,7 +2578,7 @@ async function getSignature(body) { const utf8Encoder = new TextEncoder("utf-8"); const key = await window.crypto.subtle.importKey( "raw", - utf8Encoder.encode(config/* yandexHmacKey */.I1), + utf8Encoder.encode(config/* yandexHmacKey */.S7), { name: "HMAC", hash: { name: "SHA-256" } }, false, ["sign", "verify"], @@ -2659,39 +2593,25 @@ async function getSignature(body) { -;// CONCATENATED MODULE: ./src/rvt.js +;// CONCATENATED MODULE: ./src/rsp.js -// Request video translation from Yandex API -async function requestVideoTranslation( - url, - duration, - requestLang, - responseLang, - translationHelp, - callback, -) { +// Request stream ping from Yandex API +async function requestStreamPing(pingId, callback) { try { - debug/* default */.Z.log("requestVideoTranslation"); + debug/* default */.A.log("requestStreamPing"); + // ! CURRENT CLOUDFLARE WORKER DOESN'T SUPPORT STREAM TRANSLATIONS const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest-cloudflare.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables - const body = yandexProtobuf.encodeTranslationRequest( - url, - duration, - requestLang, - responseLang, - translationHelp, - ); + const body = yandexProtobuf.encodeStreamPingRequest(pingId); // Send the request await yandexRequest( - // "/stream-translation/whitelist-stream", - // "/stream-translation/translate-stream", - "/video-translation/translate", + "/stream-translation/ping-stream", body, { "Vtrans-Signature": await getSignature(body), @@ -2706,7 +2626,7 @@ async function requestVideoTranslation( } } -/* harmony default export */ const rvt = (requestVideoTranslation); +/* harmony default export */ const rsp = (requestStreamPing); ;// CONCATENATED MODULE: ./src/rst.js @@ -2722,11 +2642,11 @@ async function requestStreamTranslation( callback, ) { try { - debug/* default */.Z.log("requestStreamTranslation"); + debug/* default */.A.log("requestStreamTranslation"); // ! CURRENT CLOUDFLARE WORKER DOESN'T SUPPORT STREAM TRANSLATIONS const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest-cloudflare.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables const body = yandexProtobuf.encodeStreamRequest( url, @@ -2752,25 +2672,39 @@ async function requestStreamTranslation( /* harmony default export */ const rst = (requestStreamTranslation); -;// CONCATENATED MODULE: ./src/rsp.js +;// CONCATENATED MODULE: ./src/rvt.js -// Request stream ping from Yandex API -async function requestStreamPing(pingId, callback) { +// Request video translation from Yandex API +async function requestVideoTranslation( + url, + duration, + requestLang, + responseLang, + translationHelp, + callback, +) { try { - debug/* default */.Z.log("requestStreamPing"); - // ! CURRENT CLOUDFLARE WORKER DOESN'T SUPPORT STREAM TRANSLATIONS + debug/* default */.A.log("requestVideoTranslation"); const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest-cloudflare.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables - const body = yandexProtobuf.encodeStreamPingRequest(pingId); + const body = yandexProtobuf.encodeTranslationRequest( + url, + duration, + requestLang, + responseLang, + translationHelp, + ); // Send the request await yandexRequest( - "/stream-translation/ping-stream", + // "/stream-translation/whitelist-stream", + // "/stream-translation/translate-stream", + "/video-translation/translate", body, { "Vtrans-Signature": await getSignature(body), @@ -2785,7 +2719,7 @@ async function requestStreamPing(pingId, callback) { } } -/* harmony default export */ const rsp = (requestStreamPing); +/* harmony default export */ const rvt = (requestVideoTranslation); ;// CONCATENATED MODULE: ./src/rvs.js @@ -2796,10 +2730,10 @@ async function requestStreamPing(pingId, callback) { // Request video subtitles from Yandex API async function requestVideoSubtitles(url, requestLang, callback) { try { - debug/* default */.Z.log("requestVideoSubtitles"); + debug/* default */.A.log("requestVideoSubtitles"); const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest-cloudflare.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables const body = yandexProtobuf.encodeSubtitlesRequest(url, requestLang); // Send the request @@ -2832,17 +2766,17 @@ function formatYandexSubtitlesTokens(line) { const lineEndMs = line.startMs + line.durationMs; return line.tokens.reduce((result, token, index) => { const nextToken = line.tokens[index + 1]; - const lastToken = result[result.length - 1]; + let lastToken; + if (result.length > 0) { + lastToken = result[result.length - 1]; + } const alignRangeEnd = lastToken?.alignRange?.end ?? 0; const newAlignRangeEnd = alignRangeEnd + token.text.length; - result.push( - Object.assign(Object.assign({}, token), { - alignRange: { - start: alignRangeEnd, - end: newAlignRangeEnd, - }, - }), - ); + token.alignRange = { + start: alignRangeEnd, + end: newAlignRangeEnd, + }; + result.push(token); if (nextToken) { const endMs = token.startMs + token.durationMs; const durationMs = nextToken.startMs @@ -2863,33 +2797,32 @@ function formatYandexSubtitlesTokens(line) { } function createSubtitlesTokens(line, previousLineLastToken) { - const tokens = line.text - .split(new RegExp("([\n \t])")) - .reduce((result, tokenText) => { - if (tokenText.length) { - const lastToken = result[result.length - 1] ?? previousLineLastToken; - const alignRangeStart = lastToken?.alignRange?.end ?? 0; - const alignRangeEnd = alignRangeStart + tokenText.length; - result.push({ - text: tokenText, - alignRange: { - start: alignRangeStart, - end: alignRangeEnd, - }, - }); - } - return result; - }, []); + const tokens = line.text.split(/([\n \t])/).reduce((result, tokenText) => { + if (tokenText.length) { + const lastToken = result[result.length - 1] ?? previousLineLastToken; + const alignRangeStart = lastToken?.alignRange?.end ?? 0; + const alignRangeEnd = alignRangeStart + tokenText.length; + result.push({ + text: tokenText, + alignRange: { + start: alignRangeStart, + end: alignRangeEnd, + }, + }); + } + return result; + }, []); const tokenDurationMs = Math.floor(line.durationMs / tokens.length); const lineEndMs = line.startMs + line.durationMs; return tokens.map((token, index) => { const isLastToken = index === tokens.length - 1; const startMs = line.startMs + tokenDurationMs * index; const durationMs = isLastToken ? lineEndMs - startMs : tokenDurationMs; - return Object.assign(Object.assign({}, token), { + return { + ...token, startMs, durationMs, - }); + }; }); } @@ -2910,11 +2843,10 @@ function getSubtitlesTokens(subtitles, source) { tokens = createSubtitlesTokens(line, lastToken); } lastToken = tokens[tokens.length - 1]; - result.push( - Object.assign(Object.assign({}, line), { - tokens, - }), - ); + result.push({ + ...line, + tokens, + }); } subtitles.containsTokens = true; return result; @@ -2961,17 +2893,17 @@ function formatYoutubeSubtitles(subtitles) { async function fetchSubtitles(subtitlesObject) { let resolved = false; let subtitles = await Promise.race([ - new Promise(async (resolve) => { - await (0,utils/* sleep */._v)(5000); - if (!resolved) { - console.error("[VOT] Failed to fetch subtitles. Reason: timeout"); - } - resolved = true; - resolve([]); + new Promise((resolve) => { + setTimeout(() => { + if (!resolved) { + console.error("[VOT] Failed to fetch subtitles. Reason: timeout"); + resolve([]); + } + }, 5000); }), - new Promise(async (resolve) => { - debug/* default */.Z.log("Fetching subtitles:", subtitlesObject); - await fetch(subtitlesObject.url) + new Promise((resolve) => { + debug/* default */.A.log("Fetching subtitles:", subtitlesObject); + fetch(subtitlesObject.url) .then((response) => response.json()) .then((json) => { resolved = true; @@ -3000,20 +2932,20 @@ async function subtitles_getSubtitles(site, videoId, requestLang) { site.host === "youtube" ? youtubeUtils.getSubtitles() : []; let resolved = false; const yaSubtitles = await Promise.race([ - new Promise(async (resolve) => { - await (0,utils/* sleep */._v)(5000); - if (!resolved) { - console.error("[VOT] Failed get yandex subtitles. Reason: timeout"); - } - resolved = true; - resolve([]); + new Promise((resolve) => { + setTimeout(() => { + if (!resolved) { + console.error("[VOT] Failed get yandex subtitles. Reason: timeout"); + resolve([]); + } + }, 5000); }), new Promise((resolve) => { rvs( `${site.url}${videoId}`, requestLang, (success, response) => { - debug/* default */.Z.log("[exec callback] Requesting video subtitles"); + debug/* default */.A.log("[exec callback] Requesting video subtitles"); if (!success) { console.error("[VOT] Failed get yandex subtitles"); @@ -3068,10 +3000,10 @@ async function subtitles_getSubtitles(site, videoId, requestLang) { } if ( a.language !== b.language && - (a.language === utils/* lang */.KQ || b.language === utils/* lang */.KQ) + (a.language === lang || b.language === lang) ) { // sort by user language - return a.language === utils/* lang */.KQ ? -1 : 1; + return a.language === lang ? -1 : 1; } if (a.source === "yandex") { // sort by translation @@ -3178,25 +3110,22 @@ class SubtitlesWidget { if (top && bottom) { this.votSubtitlesContainer.style.top = `${y - this.containerRect.y}px`; + } else if (!top) { + this.votSubtitlesContainer.style.top = `${0}px`; } else { - if (!top) { - this.votSubtitlesContainer.style.top = `${0}px`; - } else { - this.votSubtitlesContainer.style.top = `${ - this.containerRect.height - this.subtitlesContainerRect.height - }px`; - } + this.votSubtitlesContainer.style.top = `${ + this.containerRect.height - this.subtitlesContainerRect.height + }px`; } + if (left && right) { this.votSubtitlesContainer.style.left = `${x - this.containerRect.x}px`; + } else if (!left) { + this.votSubtitlesContainer.style.left = `${0}px`; } else { - if (!left) { - this.votSubtitlesContainer.style.left = `${0}px`; - } else { - this.votSubtitlesContainer.style.left = `${ - this.containerRect.width - this.subtitlesContainerRect.width - }px`; - } + this.votSubtitlesContainer.style.left = `${ + this.containerRect.width - this.subtitlesContainerRect.width + }px`; } } } @@ -3241,7 +3170,7 @@ class SubtitlesWidget { }); if (line) { if (highlightWords) { - let tokens = line.tokens; + let { tokens } = line; if (tokens.at(-1).alignRange.end > this.maxLength) { let chunks = []; let chunkStartIndex = 0; @@ -3267,12 +3196,12 @@ class SubtitlesWidget { } chunkEndIndex = i; } - for (let i = 0; i < chunks.length; i++) { + for (const chunk of chunks) { if ( - chunks[i].startMs < time && - time < chunks[i].startMs + chunks[i].durationMs + chunk.startMs < time && + time < chunk.startMs + chunk.durationMs ) { - tokens = chunks[i].tokens; + tokens = chunk.tokens; break; } } @@ -3286,22 +3215,20 @@ class SubtitlesWidget { : "" }>${token.text}`; } - } else { - if (line.text.length > this.maxLength) { - let chunks = line.text.match(this.maxLengthRegexp); - let chunkDurationMs = line.durationMs / chunks.length; - for (let i = 0; i < chunks.length; i++) { - if ( - line.startMs + chunkDurationMs * i < time && - time < line.startMs + chunkDurationMs * (i + 1) - ) { - content = chunks[i].trim(); - break; - } + } else if (line.text.length > this.maxLength) { + let chunks = line.text.match(this.maxLengthRegexp); + let chunkDurationMs = line.durationMs / chunks.length; + for (let i = 0; i < chunks.length; i++) { + if ( + line.startMs + chunkDurationMs * i < time && + time < line.startMs + chunkDurationMs * (i + 1) + ) { + content = chunks[i].trim(); + break; } - } else { - content = line.text; } + } else { + content = line.text; } } if (content !== this.lastContent) { @@ -3341,16 +3268,16 @@ async function coursehunterUtils_getVideoData() { const { file: videoUrl, duration } = lessonData; - debug/* default */.Z.log("coursehunter course data:", courseData); + debug/* default */.A.log("coursehunter course data:", courseData); return { url: videoUrl, duration, }; } -const coursehunterUtils = { +/* harmony default export */ const coursehunterUtils = ({ getVideoData: coursehunterUtils_getVideoData, -}; +}); ;// CONCATENATED MODULE: ./src/utils/courseraUtils.js @@ -3367,13 +3294,13 @@ async function courseraUtils_getCourseData(courseId) { function getSubtitlesFileURL(captions, detectedLanguage, responseLang) { let subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.srclang) === detectedLanguage, + (caption) => langTo6391(caption.srclang) === detectedLanguage, ); if (!subtitle) { subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.srclang) === responseLang, + (caption) => langTo6391(caption.srclang) === responseLang, ) || captions?.[0]; } @@ -3407,7 +3334,7 @@ async function courseraUtils_getVideoData(responseLang = "en") { const courseData = await courseraUtils_getCourseData(courseId); let detectedLanguage = courseData?.primaryLanguageCodes?.[0]; - detectedLanguage = detectedLanguage ? (0,utils/* langTo6391 */.eL)(detectedLanguage) : "en"; + detectedLanguage = detectedLanguage ? langTo6391(detectedLanguage) : "en"; if (!availableLangs.includes(detectedLanguage)) { detectedLanguage = "en"; @@ -3443,16 +3370,16 @@ async function courseraUtils_getVideoData(responseLang = "en") { translationHelp, }; - debug/* default */.Z.log("coursera video data:", videoData); + debug/* default */.A.log("coursera video data:", videoData); console.log("[VOT] Detected language: ", videoData.detectedLanguage); return videoData; } -const courseraUtils = { +/* harmony default export */ const courseraUtils = ({ getPlayer: courseraUtils_getPlayer, getPlayerData: courseraUtils_getPlayerData, getVideoData: courseraUtils_getVideoData, -}; +}); ;// CONCATENATED MODULE: ./src/utils/udemyUtils.js @@ -3482,7 +3409,7 @@ function checkUdemyTokenExpire(expires) { async function getLectureData(udemyData, courseId, lectureId) { // reference: https://greasyfork.org/ru/scripts/422576-udemy-subtitle-downloader-v3/code if (!checkUdemyTokenExpire(udemyData.expires) || !udemyData.accessToken) { - console.error(localizationProvider/* localizationProvider */.V.get("udemyAccessTokenExpired")); + console.error(localizationProvider.get("udemyAccessTokenExpired")); return undefined; } @@ -3505,13 +3432,13 @@ async function getLectureData(udemyData, courseId, lectureId) { function udemyUtils_getSubtitlesFileURL(captions, detectedLanguage, responseLang) { let subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.locale_id) === detectedLanguage, + (caption) => langTo6391(caption.locale_id) === detectedLanguage, ); if (!subtitle) { subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.locale_id) === responseLang, + (caption) => langTo6391(caption.locale_id) === responseLang, ) || captions?.[0]; } @@ -3535,7 +3462,7 @@ function getModuleData() { ".ud-app-loader[data-module-id='course-taking']", )?.dataset?.moduleArgs; if (!moduleArgs) { - console.error(localizationProvider/* localizationProvider */.V.get("udemyModuleArgsNotFound")); + console.error(localizationProvider.get("udemyModuleArgsNotFound")); return {}; } return JSON.parse(moduleArgs); @@ -3558,22 +3485,22 @@ function getVideoURLFromPlayer() { async function udemyUtils_getVideoData(udemyData, responseLang = "en") { let translationHelp = null; const data = udemyUtils_getPlayerData(); - debug/* default */.Z.log("udemyData", udemyData); + debug/* default */.A.log("udemyData", udemyData); const moduleData = getModuleData(); - debug/* default */.Z.log("moduleData: ", moduleData); + debug/* default */.A.log("moduleData: ", moduleData); const courseId = moduleData.courseId; const lectureId = getLectureId(); - debug/* default */.Z.log(`CourseId: ${courseId}, lectureId: ${lectureId}`); + debug/* default */.A.log(`CourseId: ${courseId}, lectureId: ${lectureId}`); const courseLang = await getCourseLang(courseId); - debug/* default */.Z.log("courseLang Data:", courseLang); + debug/* default */.A.log("courseLang Data:", courseLang); const lectureData = await getLectureData(udemyData, courseId, lectureId); console.log("lecture Data:", lectureData); let detectedLanguage = courseLang?.locale?.locale; - detectedLanguage = detectedLanguage ? (0,utils/* langTo6391 */.eL)(detectedLanguage) : "en"; + detectedLanguage = detectedLanguage ? langTo6391(detectedLanguage) : "en"; if (!availableLangs.includes(detectedLanguage)) { detectedLanguage = "en"; @@ -3614,120 +3541,266 @@ async function udemyUtils_getVideoData(udemyData, responseLang = "en") { translationHelp, }; - debug/* default */.Z.log("udemy video data:", videoData); + debug/* default */.A.log("udemy video data:", videoData); console.log("[VOT] Detected language: ", videoData.detectedLanguage); return videoData; } -const udemyUtils = { +/* harmony default export */ const udemyUtils = ({ getPlayer: udemyUtils_getPlayer, getPlayerData: udemyUtils_getPlayerData, getVideoData: udemyUtils_getVideoData, getModuleData, getCourseLang, getLectureData, -}; +}); -// EXTERNAL MODULE: ./node_modules/requestidlecallback-polyfill/index.js -var requestidlecallback_polyfill = __webpack_require__("./node_modules/requestidlecallback-polyfill/index.js"); -;// CONCATENATED MODULE: ./src/utils/EventImpl.js -class EventImpl { - constructor() { - this.listeners = new Set(); - } - hasListener(e) { - return this.listeners.has(e); - } - dispatchToListener(handler, ...args) { - try { - handler(...args); - } catch (exception) { - console.error("[VOT]", exception); - } - } - addListener(handler) { - if (this.hasListener(handler)) { - throw new Error("[VOT] The listener has already been added."); - } - this.listeners.add(handler); - } - removeListener(handler) { - if (!this.hasListener(handler)) { - throw new Error("[VOT] The listener has not been added yet."); - } - this.listeners.delete(handler); - } - dispatch(...args) { - for (const handler of Array.from(this.listeners)) { - this.dispatchToListener(handler, ...args); - } - } +;// CONCATENATED MODULE: ./src/utils/bannedvideoUtils.js + + +async function getVideoInfo(videoId) { + return await fetch(`https://api.banned.video/graphql`, { + method: "POST", + body: JSON.stringify({ + operationName: "GetVideo", + query: `query GetVideo($id: String!) { + getVideo(id: $id) { + ...DisplayVideoFields + videoUrl: directUrl + live + } + } + + fragment DisplayVideoFields on Video { + title + description: summary + duration: videoDuration + }`, + variables: { + id: videoId, + }, + }), + headers: { + "User-Agent": "bannedVideoFrontEnd", + "apollographql-client-name": "banned-web", + "apollographql-client-version": "1.3", + "content-type": "application/json", + }, + }) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + data: { + getVideo: {}, + }, + }; + }); } -;// CONCATENATED MODULE: ./src/utils/VideoObserver.js +async function bannedvideoUtils_getVideoData(videoId) { + const videoData = await getVideoInfo(videoId); + debug/* default */.A.log("banned.video video data:", videoData); + const { videoUrl, duration, live, description, title } = + videoData.data.getVideo; -function filterVideoNodes(e) { - return Array.from(e) - .map((e) => { - const result = []; - if (e instanceof HTMLVideoElement) { - result.push(e); - } - if (e instanceof HTMLElement) { - result.push(...Array.from(e.querySelectorAll("video"))); - } - if (e?.shadowRoot?.querySelectorAll) { - result.push(...Array.from(e.shadowRoot.querySelectorAll("video"))); - } - return result; - }) - .flat(); + // TODO: Add detect language from title + description + + return { + url: videoUrl, + duration, + live, + title, + description, + }; } -class VideoObserver { - constructor() { - this.onVideoAdded = new EventImpl(); - this.onVideoRemoved = new EventImpl(); - this.handleVideoAddedBound = this.handleVideoAdded.bind(this); - this.handleVideoRemovedBound = this.handleVideoRemoved.bind(this); - this.observer = new MutationObserver((mutationsList) => { - window.requestIdleCallback( - () => { - mutationsList.forEach((mutation) => { - if ("childList" !== mutation.type) return; +/* harmony default export */ const bannedvideoUtils = ({ + getVideoData: bannedvideoUtils_getVideoData, +}); - filterVideoNodes(mutation.addedNodes).forEach( - this.handleVideoAddedBound, - ); - filterVideoNodes(mutation.removedNodes).forEach( - this.handleVideoRemovedBound, - ); - }); +;// CONCATENATED MODULE: ./src/utils/crypto.js +async function getHmacSha1(hmacKey, salt) { + const utf8Encoder = new TextEncoder("utf-8"); + salt = utf8Encoder.encode(salt); + + return window.crypto.subtle + .importKey( + "raw", + utf8Encoder.encode(hmacKey), + { name: "HMAC", hash: { name: "SHA-1" } }, + false, + ["sign", "verify"], + ) + .then((key) => window.crypto.subtle.sign("HMAC", key, salt)) + .then((arrayBuffer) => + btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))), + ) + .catch((err) => { + console.error(err); + return false; + }); +} + +;// CONCATENATED MODULE: ./src/utils/weverseUtils.js + + + +const API_ORIGIN = "https://global.apis.naver.com/weverse/wevweb"; // find as REACT_APP_API_GW_ORIGIN in main..js +const API_APP_ID = "be4d79eb8fc7bd008ee82c8ec4ff6fd4"; // find as REACT_APP_API_APP_ID in main..js +const API_HMAC_KEY = "1b9cb6378d959b45714bec49971ade22e6e24e42"; // find as c.active near `createHmac("sha1"...` in main..js + +async function createHash(pathname) { + // pathname example: /post/v1.0/post-3-142049908/preview?fieldSet=postForPreview... + const timestamp = Date.now(); + + let salt = pathname.substring(0, Math.min(255, pathname.length)) + timestamp; + // example salt is /video/v1.1/vod/67134/inKey?gcc=RU&appId=be4d79eb8fc7bd008ee82c8ec4ff6fd4&language=en&os=WEB&platform=WEB&wpf=pc1707527163588 + + const sign = await getHmacSha1(API_HMAC_KEY, salt); + + return { + wmsgpad: timestamp, + wmd: sign, + }; +} + +function getURLData() { + return { + appId: API_APP_ID, + language: "en", + os: "WEB", + platform: "WEB", + wpf: "pc", + }; +} + +async function getVideoPreview(postId) { + const pathname = + `/post/v1.0/post-${postId}/preview?` + + new URLSearchParams({ + fieldSet: "postForPreview", + ...getURLData(), + }); // ! DON'T EDIT ME + + const hash = await createHash(pathname); + + return await fetch(API_ORIGIN + pathname + "&" + new URLSearchParams(hash)) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + extension: { + video: {}, }, - { timeout: 1e3 }, - ); + }; }); - } - enable() { - this.observer.observe(document, { - childList: true, - subtree: true, +} + +async function getVideoInKey(videoId) { + const pathname = + `/video/v1.1/vod/${videoId}/inKey?` + + new URLSearchParams({ + gcc: "RU", + ...getURLData(), + }); // ! DON'T EDIT ME + const hash = await createHash(pathname); + + return await fetch(API_ORIGIN + pathname + "&" + new URLSearchParams(hash), { + method: "POST", + }) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return {}; }); - document.querySelectorAll("video").forEach(this.handleVideoAddedBound); - } - disable() { - this.observer.disconnect(); +} + +async function weverseUtils_getVideoInfo(infraVideoId, inkey, serviceId) { + const timestamp = Date.now(); + return await fetch( + `https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${infraVideoId}?` + + new URLSearchParams({ + key: inkey, + sid: serviceId, + // pid: "863c411f-fbf0-4b67-868a-ef54427e5316", // возможно не нужен + nonce: timestamp, + devt: "html5_pc", + prv: "N", + aup: "N", + stpb: "N", + cpl: "en", + env: "prod", + lc: "en", + adi: [ + { + adSystem: null, + }, + ], + adu: "/", + }), + ) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + videos: { + list: [], + }, + }; + }); +} + +function extractVideoInfo(videoList) { + return videoList.find( + (video) => video.useP2P === false && video.source.includes(".mp4"), + ); +} + +async function weverseUtils_getVideoData() { + // ! When translating using a regular link (like this https://weverse.io/aespa/live/3-142049908), + // ! we will get an error, so we have to do this + + const postId = new URL(window.location).pathname.match( + /([^/]+)\/(live|media)\/([^/]+)/, + )?.[3]; + + const videoPreview = await getVideoPreview(postId); + debug/* default */.A.log("weverse video preview data:", videoPreview); + + const { videoId, serviceId, infraVideoId } = videoPreview.extension.video; + + if (!(videoId && serviceId && infraVideoId)) { + return false; } - handleVideoAdded(video) { - this.onVideoAdded.dispatch(video); + + const { inKey } = await getVideoInKey(videoId); + debug/* default */.A.log("weverse video inKey data:", videoPreview); + if (!inKey) { + return false; } - handleVideoRemoved(video) { - document.contains(video) || this.onVideoRemoved.dispatch(video); + + const videoData = await weverseUtils_getVideoInfo(infraVideoId, inKey, serviceId); + debug/* default */.A.log("weverse video data:", videoData); + + const videoSource = extractVideoInfo(videoData.videos.list); + if (!videoSource) { + return false; } + + const { source: url, duration } = videoSource; + return { + url, + duration, + }; } +/* harmony default export */ const weverseUtils = ({ + getVideoData: weverseUtils_getVideoData, +}); + ;// CONCATENATED MODULE: ./src/config/sites.js @@ -3820,12 +3893,24 @@ const sites = () => { selector: ".videoplayer_media", }, { - // TODO: video selector: ".vp-video-wrapper > .vp-video > .vp-telecine > video" host: "vimeo", url: "https://vimeo.com/", - match: /^(player.)?vimeo.com$/, + match: /^vimeo.com$/, + selector: ".player", + }, + { + additionalData: "embed", + host: "vimeo", + url: "https://player.vimeo.com/", + match: /^player.vimeo.com$/, selector: ".player", }, + { + host: "ok.ru", + url: "https://ok.ru/", + match: /^ok.ru$/, + selector: ".html5-vpl_vid", + }, { host: "nine_gag", url: "https://9gag.com/gag/", @@ -3842,7 +3927,7 @@ const sites = () => { host: "bitchute", url: "https://www.bitchute.com/video/", match: /^(www.)?bitchute.com$/, - selector: ".plyr__video-wrapper", + selector: "#player", }, { host: "rutube", @@ -3953,11 +4038,169 @@ const sites = () => { match: /^coursehunter.net$/, selector: "#oframeplayer > pjsdiv:nth-of-type(1)", }, + { + host: "googledrive", + url: "https://drive.google.com/file/d/", + match: /^youtube.googleapis.com$/, + selector: ".html5-video-container", + }, + { + host: "bannedvideo", + url: "https://banned.video/watch?id=", + match: /^(www.)?banned.video$/, + selector: ".vjs-v7", + }, + { + host: "facebook", + url: "https://facebook.com", // <-- there should be no slash because we take the whole pathname + match: (url) => + url.host.includes("facebook.com") && url.pathname.includes("/videos/"), + selector: 'div[data-pagelet="WatchPermalinkVideo"]', + }, + { + additionalData: "reels", + host: "facebook", + url: "https://facebook.com", // <-- there should be no slash because we take the whole pathname + match: (url) => + url.host.includes("facebook.com") && url.pathname.includes("/reel/"), + selector: 'div[role="main"]', + }, + { + host: "weverse", + url: "https://weverse.io/", + match: /^weverse.io$/, + selector: ".webplayer-internal-source-wrapper", + }, + { + host: "newgrounds", + url: "https://www.newgrounds.com/", + match: /^www.newgrounds.com$/, + selector: ".ng-video-player", + }, + { + // TODO: Добавить поддержку tips и платных курсов + host: "egghead", + url: "https://egghead.io", + match: /^egghead.io$/, + selector: ".cueplayer-react-video-holder", + }, + { + host: "youku", + // Что-то перекрывает кнопку и не дает её нажать + url: "https://v.youku.com/", + match: /^v.youku.com$/, + selector: "#ykPlayer", + }, + // Нужно куда-то заливать данные о плейлисте + // { + // host: "epicgames", + // url: "https://dev.epicgames.com/community/learning/tutorials/", + // match: /^dev.epicgames.com$/, + // selector: "#vjs_video_3", + // }, ]; }; /* harmony default export */ const config_sites = (sites()); +// EXTERNAL MODULE: ./node_modules/requestidlecallback-polyfill/index.js +var requestidlecallback_polyfill = __webpack_require__("./node_modules/requestidlecallback-polyfill/index.js"); +;// CONCATENATED MODULE: ./src/utils/EventImpl.js +class EventImpl { + constructor() { + this.listeners = new Set(); + } + hasListener(e) { + return this.listeners.has(e); + } + dispatchToListener(handler, ...args) { + try { + handler(...args); + } catch (exception) { + console.error("[VOT]", exception); + } + } + addListener(handler) { + if (this.hasListener(handler)) { + throw new Error("[VOT] The listener has already been added."); + } + this.listeners.add(handler); + } + removeListener(handler) { + if (!this.hasListener(handler)) { + throw new Error("[VOT] The listener has not been added yet."); + } + this.listeners.delete(handler); + } + dispatch(...args) { + for (const handler of Array.from(this.listeners)) { + this.dispatchToListener(handler, ...args); + } + } +} + +;// CONCATENATED MODULE: ./src/utils/VideoObserver.js + + + +function filterVideoNodes(nodes) { + return Array.from(nodes).flatMap((node) => { + if (node instanceof HTMLVideoElement) { + return [node]; + } + if (node instanceof HTMLElement) { + return Array.from(node.querySelectorAll("video")); + } + return node.shadowRoot + ? Array.from(node.shadowRoot.querySelectorAll("video")) + : []; + }); +} + +class VideoObserver { + constructor() { + this.onVideoAdded = new EventImpl(); + this.onVideoRemoved = new EventImpl(); + this.handleVideoAddedBound = this.handleVideoAdded.bind(this); + this.handleVideoRemovedBound = this.handleVideoRemoved.bind(this); + this.observer = new MutationObserver((mutationsList) => { + window.requestIdleCallback( + () => { + mutationsList.forEach((mutation) => { + if (mutation.type !== "childList") return; + + filterVideoNodes(mutation.addedNodes).forEach( + this.handleVideoAddedBound, + ); + filterVideoNodes(mutation.removedNodes).forEach( + this.handleVideoRemovedBound, + ); + }); + }, + { timeout: 1000 }, + ); + }); + } + enable() { + this.observer.observe(document, { + childList: true, + subtree: true, + }); + document.querySelectorAll("video").forEach(this.handleVideoAddedBound); + } + disable() { + this.observer.disconnect(); + } + handleVideoAdded(video) { + this.onVideoAdded.dispatch(video); + } + handleVideoRemoved(video) { + if (!document.contains(video)) { + this.onVideoRemoved.dispatch(video); + } + } +} + ;// CONCATENATED MODULE: ./src/index.js @@ -3983,6 +4226,9 @@ const sites = () => { + + + @@ -4002,7 +4248,7 @@ const videoLipSyncEvents = [ function genOptionsByOBJ(obj, conditionString, validateLangs = false) { return obj.map((code) => ({ label: `${validateLangs && !actualTTS.includes(code) ? "❌ " : ""}${ - localizationProvider/* localizationProvider */.V.get("langs")[code] ?? code.toUpperCase() + localizationProvider.get("langs")[code] ?? code.toUpperCase() }`, value: code, selected: conditionString === code, @@ -4021,14 +4267,14 @@ function translateVideo( translationHelp, callback, ) { - debug/* default */.Z.log( + debug/* default */.A.log( `Translate video (url: ${url}, duration: ${duration}, requestLang: ${requestLang}, responseLang: ${responseLang})`, ); - debug/* default */.Z.log("translationHelp:", translationHelp); + debug/* default */.A.log("translationHelp:", translationHelp); if ( true && translationPanding) { - debug/* default */.Z.log("translationPanding return"); + debug/* default */.A.log("translationPanding return"); return; } @@ -4043,9 +4289,9 @@ function translateVideo( (success, response) => { translationPanding = false; - debug/* default */.Z.log("[exec callback] Requesting video translation"); + debug/* default */.A.log("[exec callback] Requesting video translation"); if (!success) { - callback(false, localizationProvider/* localizationProvider */.V.get("requestTranslationFailed")); + callback(false, localizationProvider.get("requestTranslationFailed")); return; } @@ -4061,15 +4307,15 @@ function translateVideo( callback( !!translateResponse.url, translateResponse.url || - localizationProvider/* localizationProvider */.V.get("audioNotReceived"), + localizationProvider.get("audioNotReceived"), ); break; case 2: callback( false, translateResponse.remainingTime - ? (0,utils/* secsToStrTime */.PG)(translateResponse.remainingTime) - : localizationProvider/* localizationProvider */.V.get("translationTakeFewMinutes"), + ? secsToStrTime(translateResponse.remainingTime) + : localizationProvider.get("translationTakeFewMinutes"), ); break; case 3: @@ -4088,7 +4334,7 @@ function translateVideo( Он появляется при первом запросе с 17=1, но не исключено, что может появится и просто так */ - callback(false, localizationProvider/* localizationProvider */.V.get("videoBeingTranslated")); + callback(false, localizationProvider.get("videoBeingTranslated")); break; } }, @@ -4096,7 +4342,7 @@ function translateVideo( } function translateStream(url, requestLang, responseLang, callback) { - debug/* default */.Z.log( + debug/* default */.A.log( `Translate stream (url: ${url}, requestLang: ${requestLang}, responseLang: ${responseLang})`, ); @@ -4105,9 +4351,9 @@ function translateStream(url, requestLang, responseLang, callback) { requestLang, responseLang, (success, response) => { - debug/* default */.Z.log("[exec callback] Requesting stream translation"); + debug/* default */.A.log("[exec callback] Requesting stream translation"); if (!success) { - callback(false, localizationProvider/* localizationProvider */.V.get("requestTranslationFailed")); + callback(false, localizationProvider.get("requestTranslationFailed")); return; } @@ -4119,14 +4365,14 @@ function translateStream(url, requestLang, responseLang, callback) { callback( false, streamResponse.interval, - localizationProvider/* localizationProvider */.V.get("translationTakeFewMinutes"), + localizationProvider.get("translationTakeFewMinutes"), ); break; case 20: callback( true, streamResponse.interval, - streamResponse || localizationProvider/* localizationProvider */.V.get("audioNotReceived"), + streamResponse || localizationProvider.get("audioNotReceived"), ); break; case 0: @@ -4134,7 +4380,7 @@ function translateStream(url, requestLang, responseLang, callback) { callback( false, streamResponse.interval, - localizationProvider/* localizationProvider */.V.get("streamNoConnectionToServer"), + localizationProvider.get("streamNoConnectionToServer"), ); break; } @@ -4145,7 +4391,7 @@ function translateStream(url, requestLang, responseLang, callback) { class VideoHandler { // translate properties translateFromLang = "en"; // default language of video - translateToLang = utils/* lang */.KQ; // default language of audio response + translateToLang = lang; // default language of audio response timer; @@ -4153,7 +4399,11 @@ class VideoHandler { videoData = ""; firstPlay = true; audio = new Audio(); - hls = (0,utils/* initHls */.QZ)(); // debug enabled only in dev mode + hls = initHls(); // debug enabled only in dev mode + + videoTranslations = []; + videoTranslationTTL = 7200; + downloadTranslationUrl = null; downloadSubtitlesUrl = null; @@ -4169,7 +4419,7 @@ class VideoHandler { videoLastSrcObject = null; constructor(video, container, site) { - debug/* default */.Z.log( + debug/* default */.A.log( "[VideoHandler] add video:", video, "container:", @@ -4180,16 +4430,7 @@ class VideoHandler { this.container = container; this.site = site; this.handleSrcChangedBound = this.handleSrcChanged.bind(this); - this.srcObserver = new MutationObserver(this.handleSrcChangedBound); - this.srcObserver.observe(this.video, { - attributeFilter: ["src", "currentSrc"], - }); - this.srcObjectInterval = setInterval(async () => { - if (this.videoLastSrcObject !== this.video.srcObject) { - this.videoLastSrcObject = this.video.srcObject; - await this.handleSrcChanged(); - } - }, 100); + this.video.addEventListener("loadedmetadata", this.handleSrcChangedBound); this.stopTranslationBound = this.stopTranslation.bind(this); this.handleVideoEventBound = this.handleVideoEvent.bind(this); this.changeOpacityOnEventBound = this.changeOpacityOnEvent.bind(this); @@ -4200,52 +4441,46 @@ class VideoHandler { async init() { if (this.initialized) return; - this.data = { - autoTranslate: await storage/* votStorage */.i.get("autoTranslate", 0, true), - dontTranslateLanguage: await storage/* votStorage */.i.get( - "dontTranslateLanguage", - utils/* lang */.KQ, - ), - dontTranslateYourLang: await storage/* votStorage */.i.get( - "dontTranslateYourLang", - 1, - true, - ), - autoSetVolumeYandexStyle: await storage/* votStorage */.i.get( + const audioProxyDefault = + lang === "uk" && "cloudflare" === "cloudflare" ? 1 : 0; + + const dataPromises = { + autoTranslate: storage/* votStorage */.d.get("autoTranslate", 0, true), + dontTranslateLanguage: storage/* votStorage */.d.get("dontTranslateLanguage", lang), + dontTranslateYourLang: storage/* votStorage */.d.get("dontTranslateYourLang", 1, true), + autoSetVolumeYandexStyle: storage/* votStorage */.d.get( "autoSetVolumeYandexStyle", 1, true, ), - autoVolume: - (await storage/* votStorage */.i.get("autoVolume", config/* defaultAutoVolume */.sN, true)) / 100, - showVideoSlider: await storage/* votStorage */.i.get("showVideoSlider", 1, true), - syncVolume: await storage/* votStorage */.i.get("syncVolume", 0, true), - subtitlesMaxLength: await storage/* votStorage */.i.get("subtitlesMaxLength", 300, true), - highlightWords: await storage/* votStorage */.i.get("highlightWords", 0, true), - responseLanguage: await storage/* votStorage */.i.get("responseLanguage", utils/* lang */.KQ), - defaultVolume: await storage/* votStorage */.i.get("defaultVolume", 100, true), - udemyData: await storage/* votStorage */.i.get("udemyData", { - accessToken: "", - expires: 0, - }), - audioProxy: await storage/* votStorage */.i.get( - "audioProxy", - utils/* lang */.KQ === "uk" && "cloudflare" === "cloudflare" ? 1 : 0, - true, - ), - showPiPButton: await storage/* votStorage */.i.get("showPiPButton", 0, true), - translateAPIErrors: await storage/* votStorage */.i.get("translateAPIErrors", 1, true), - translationService: await storage/* votStorage */.i.get( + autoVolume: storage/* votStorage */.d.get("autoVolume", config/* defaultAutoVolume */.JD, true), + showVideoSlider: storage/* votStorage */.d.get("showVideoSlider", 1, true), + syncVolume: storage/* votStorage */.d.get("syncVolume", 0, true), + subtitlesMaxLength: storage/* votStorage */.d.get("subtitlesMaxLength", 300, true), + highlightWords: storage/* votStorage */.d.get("highlightWords", 0, true), + responseLanguage: storage/* votStorage */.d.get("responseLanguage", lang), + defaultVolume: storage/* votStorage */.d.get("defaultVolume", 100, true), + udemyData: storage/* votStorage */.d.get("udemyData", { accessToken: "", expires: 0 }), + audioProxy: storage/* votStorage */.d.get("audioProxy", audioProxyDefault, true), + showPiPButton: storage/* votStorage */.d.get("showPiPButton", 0, true), + translateAPIErrors: storage/* votStorage */.d.get("translateAPIErrors", 1, true), + translationService: storage/* votStorage */.d.get( "translationService", - config/* defaultTranslationService */.kF, - ), - detectService: await storage/* votStorage */.i.get( - "detectService", - config/* defaultDetectService */.EY, + config/* defaultTranslationService */.mE, ), - m3u8ProxyHost: await storage/* votStorage */.i.get("m3u8ProxyHost", config/* m3u8ProxyHost */.e6), - proxyWorkerHost: await storage/* votStorage */.i.get("proxyWorkerHost", config/* proxyWorkerHost */.ez), + detectService: storage/* votStorage */.d.get("detectService", config/* defaultDetectService */.K2), + m3u8ProxyHost: storage/* votStorage */.d.get("m3u8ProxyHost", config/* m3u8ProxyHost */.se), + proxyWorkerHost: storage/* votStorage */.d.get("proxyWorkerHost", config/* proxyWorkerHost */.Pm), }; + + const dataEntries = await Promise.all( + Object.entries(dataPromises).map(async ([key, promise]) => [ + key, + await promise, + ]), + ); + this.data = Object.fromEntries(dataEntries); + this.videoData = await this.getVideoData(); console.log("[db] data from db: ", this.data); @@ -4261,10 +4496,12 @@ class VideoHandler { this.initUI(); this.initUIEvents(); - const hide = + const videoHasNoSource = !this.video.src && !this.video.currentSrc && !this.video.srcObject; - this.votButton.container.hidden = hide; - hide && (this.votMenu.container.hidden = hide); + this.votButton.container.hidden = videoHasNoSource; + if (videoHasNoSource) { + this.votMenu.container.hidden = true; + } await this.updateSubtitles(); await this.changeSubtitlesLang("disabled"); @@ -4288,14 +4525,14 @@ class VideoHandler { // VOT Button { this.votButton = ui.createVOTButton( - localizationProvider/* localizationProvider */.V.get("translateVideo"), + localizationProvider.get("translateVideo"), ); this.container.appendChild(this.votButton.container); this.votButton.pipButton.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data?.showPiPButton; + !isPiPAvailable() || !this.data?.showPiPButton; this.votButton.separator2.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data?.showPiPButton; + !isPiPAvailable() || !this.data?.showPiPButton; this.votButton.container.addEventListener("click", (e) => { e.preventDefault(); @@ -4306,7 +4543,7 @@ class VideoHandler { // VOT Menu { - this.votMenu = ui.createVOTMenu(localizationProvider/* localizationProvider */.V.get("VOTSettings")); + this.votMenu = ui.createVOTMenu(localizationProvider.get("VOTSettings")); this.container.appendChild(this.votMenu.container); this.votDownloadButton = ui.createIconButton( @@ -4328,18 +4565,18 @@ class VideoHandler { this.votTranslationLanguageSelect = ui.createVOTLanguageSelect({ fromTitle: - localizationProvider/* localizationProvider */.V.get("langs")[this.video.detectedLanguage], - fromDialogTitle: localizationProvider/* localizationProvider */.V.get("videoLanguage"), + localizationProvider.get("langs")[this.video.detectedLanguage], + fromDialogTitle: localizationProvider.get("videoLanguage"), fromItems: [ { - label: localizationProvider/* localizationProvider */.V.get("langs")["auto"], + label: localizationProvider.get("langs")["auto"], value: "auto", selected: "", }, ...genOptionsByOBJ(availableLangs, this.videoData.detectedLanguage), ], fromOnSelectCB: async (e) => { - debug/* default */.Z.log( + debug/* default */.A.log( "[fromOnSelectCB] select from language", e.target.dataset.votValue, ); @@ -4349,8 +4586,8 @@ class VideoHandler { this.videoData.responseLanguage, ); }, - toTitle: localizationProvider/* localizationProvider */.V.get("langs")[this.video.responseLanguage], - toDialogTitle: localizationProvider/* localizationProvider */.V.get("translationLanguage"), + toTitle: localizationProvider.get("langs")[this.video.responseLanguage], + toDialogTitle: localizationProvider.get("translationLanguage"), toItems: [ ...genOptionsByOBJ( availableLangs, @@ -4370,10 +4607,10 @@ class VideoHandler { ], toOnSelectCB: async (e) => { const newLang = e.target.dataset.votValue; - debug/* default */.Z.log("[toOnSelectCB] select to language", newLang); + debug/* default */.A.log("[toOnSelectCB] select to language", newLang); this.data.responseLanguage = this.translateToLang = newLang; - await storage/* votStorage */.i.set("responseLanguage", this.data.responseLanguage); - debug/* default */.Z.log( + await storage/* votStorage */.d.set("responseLanguage", this.data.responseLanguage); + debug/* default */.A.log( "Response Language value changed. New value: ", this.data.responseLanguage, ); @@ -4390,11 +4627,11 @@ class VideoHandler { ); this.votSubtitlesSelect = ui.createVOTSelect( - localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), - localizationProvider/* localizationProvider */.V.get("VOTSubtitles"), + localizationProvider.get("VOTSubtitlesDisabled"), + localizationProvider.get("VOTSubtitles"), [ { - label: localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), + label: localizationProvider.get("VOTSubtitlesDisabled"), value: "disabled", selected: true, disabled: false, @@ -4405,7 +4642,7 @@ class VideoHandler { await this.changeSubtitlesLang(e.target.dataset.votValue); }, labelElement: ui.createVOTSelectLabel( - localizationProvider/* localizationProvider */.V.get("VOTSubtitles"), + localizationProvider.get("VOTSubtitles"), ), }, ); @@ -4413,7 +4650,7 @@ class VideoHandler { this.votMenu.bodyContainer.appendChild(this.votSubtitlesSelect.container); this.votVideoVolumeSlider = ui.createSlider( - `${localizationProvider/* localizationProvider */.V.get("VOTVolume")}: ${ + `${localizationProvider.get("VOTVolume")}: ${ this.getVideoVolume() * 100 }%`, this.getVideoVolume() * 100, @@ -4426,7 +4663,7 @@ class VideoHandler { ); this.votVideoTranslationVolumeSlider = ui.createSlider( - `${localizationProvider/* localizationProvider */.V.get("VOTVolumeTranslation")}: ${ + `${localizationProvider.get("VOTVolumeTranslation")}: ${ this.data?.defaultVolume ?? 100 }%`, this.data?.defaultVolume ?? 100, @@ -4447,19 +4684,19 @@ class VideoHandler { // VOT Settings { this.votSettingsDialog = ui.createDialog( - localizationProvider/* localizationProvider */.V.get("VOTSettings"), + localizationProvider.get("VOTSettings"), ); document.documentElement.appendChild(this.votSettingsDialog.container); this.votTranslationHeader = ui.createHeader( - localizationProvider/* localizationProvider */.V.get("translationSettings"), + localizationProvider.get("translationSettings"), ); this.votSettingsDialog.bodyContainer.appendChild( this.votTranslationHeader, ); this.votAutoTranslateCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTAutoTranslate"), + localizationProvider.get("VOTAutoTranslate"), this.data?.autoTranslate ?? false, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4467,24 +4704,24 @@ class VideoHandler { ); this.votDontTranslateYourLangSelect = ui.createVOTSelect( - localizationProvider/* localizationProvider */.V.get("langs")[ - storage/* votStorage */.i.syncGet("dontTranslateLanguage", utils/* lang */.KQ) + localizationProvider.get("langs")[ + storage/* votStorage */.d.syncGet("dontTranslateLanguage", lang) ], - localizationProvider/* localizationProvider */.V.get("VOTDontTranslateYourLang"), + localizationProvider.get("VOTDontTranslateYourLang"), genOptionsByOBJ( availableLangs, - storage/* votStorage */.i.syncGet("dontTranslateLanguage", utils/* lang */.KQ), + storage/* votStorage */.d.syncGet("dontTranslateLanguage", lang), ), { onSelectCb: async (e) => { this.data.dontTranslateLanguage = e.target.dataset.votValue; - await storage/* votStorage */.i.set( + await storage/* votStorage */.d.set( "dontTranslateLanguage", this.data.dontTranslateLanguage, ); }, labelElement: ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTDontTranslateYourLang"), + localizationProvider.get("VOTDontTranslateYourLang"), this.data?.dontTranslateYourLang ?? true, ).container, }, @@ -4495,17 +4732,15 @@ class VideoHandler { ); this.votAutoSetVolumeCheckbox = ui.createCheckbox( - `${localizationProvider/* localizationProvider */.V.get("VOTAutoSetVolume")}`, + `${localizationProvider.get("VOTAutoSetVolume")}`, this.data?.autoSetVolumeYandexStyle ?? true, ); this.votSettingsDialog.bodyContainer.appendChild( this.votAutoSetVolumeCheckbox.container, ); this.votAutoSetVolumeSlider = ui.createSlider( - `${ - (this.data?.autoVolume ?? config/* defaultAutoVolume */.sN) * 100 - }%`, - (this.data?.autoVolume ?? config/* defaultAutoVolume */.sN) * 100, + `${(this.data?.autoVolume ?? config/* defaultAutoVolume */.JD) * 100}%`, + (this.data?.autoVolume ?? config/* defaultAutoVolume */.JD) * 100, 0, 100, ); @@ -4514,7 +4749,7 @@ class VideoHandler { ); this.votShowVideoSliderCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTShowVideoSlider"), + localizationProvider.get("VOTShowVideoSlider"), this.data?.showVideoSlider ?? false, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4523,7 +4758,7 @@ class VideoHandler { // udemy only this.votUdemyDataTextfield = ui.createTextfield( - localizationProvider/* localizationProvider */.V.get("VOTUdemyData"), + localizationProvider.get("VOTUdemyData"), this.data?.udemyData?.accessToken ?? "", ); this.votUdemyDataTextfield.container.hidden = this.site.host !== "udemy"; @@ -4533,56 +4768,57 @@ class VideoHandler { // youtube only this.votSyncVolumeCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTSyncVolume"), + localizationProvider.get("VOTSyncVolume"), this.data?.syncVolume ?? false, ); this.votSyncVolumeCheckbox.container.hidden = - this.site.host !== "youtube" || this.site.additionalData === "mobile"; + !["youtube", "googledrive"].includes(this.site.host) || + this.site.additionalData === "mobile"; this.votSettingsDialog.bodyContainer.appendChild( this.votSyncVolumeCheckbox.container, ); this.votTranslationServiceSelect = ui.createVOTSelect( - storage/* votStorage */.i.syncGet("translationService", config/* defaultTranslationService */.kF), - localizationProvider/* localizationProvider */.V.get("VOTTranslationService"), + storage/* votStorage */.d.syncGet("translationService", config/* defaultTranslationService */.mE), + localizationProvider.get("VOTTranslationService"), genOptionsByOBJ( translateServices, - storage/* votStorage */.i.syncGet("translationService", config/* defaultTranslationService */.kF), + storage/* votStorage */.d.syncGet("translationService", config/* defaultTranslationService */.mE), ), { onSelectCb: async (e) => { this.data.translationService = e.target.dataset.votValue; - await storage/* votStorage */.i.set( + await storage/* votStorage */.d.set( "translationService", this.data.translationService, ); }, labelElement: ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTTranslateAPIErrors"), + localizationProvider.get("VOTTranslateAPIErrors"), this.data.translateAPIErrors ?? true, ).container, }, ); this.votTranslationServiceSelect.container.hidden = - localizationProvider/* localizationProvider */.V.lang === "ru"; + localizationProvider.lang === "ru"; this.votSettingsDialog.bodyContainer.appendChild( this.votTranslationServiceSelect.container, ); this.votDetectServiceSelect = ui.createVOTSelect( - storage/* votStorage */.i.syncGet("detectService", config/* defaultDetectService */.EY), - localizationProvider/* localizationProvider */.V.get("VOTDetectService"), + storage/* votStorage */.d.syncGet("detectService", config/* defaultDetectService */.K2), + localizationProvider.get("VOTDetectService"), genOptionsByOBJ( detectServices, - storage/* votStorage */.i.syncGet("detectService", config/* defaultDetectService */.EY), + storage/* votStorage */.d.syncGet("detectService", config/* defaultDetectService */.K2), ), { onSelectCb: async (e) => { this.data.detectService = e.target.dataset.votValue; - await storage/* votStorage */.i.set("detectService", this.data.detectService); + await storage/* votStorage */.d.set("detectService", this.data.detectService); }, labelElement: ui.createVOTSelectLabel( - localizationProvider/* localizationProvider */.V.get("VOTDetectService"), + localizationProvider.get("VOTDetectService"), ), }, ); @@ -4593,12 +4829,12 @@ class VideoHandler { // SUBTITLES this.votSubtitlesHeader = ui.createHeader( - localizationProvider/* localizationProvider */.V.get("subtitlesSettings"), + localizationProvider.get("subtitlesSettings"), ); this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader); this.votSubtitlesMaxLengthSlider = ui.createSlider( - `${localizationProvider/* localizationProvider */.V.get("VOTSubtitlesMaxLength")}: ${ + `${localizationProvider.get("VOTSubtitlesMaxLength")}: ${ this.data?.subtitlesMaxLength ?? 300 }`, this.data?.subtitlesMaxLength ?? 300, @@ -4610,7 +4846,7 @@ class VideoHandler { ); this.votSubtitlesHighlightWordsCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTHighlightWords"), + localizationProvider.get("VOTHighlightWords"), this.data?.highlightWords ?? false, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4620,14 +4856,14 @@ class VideoHandler { // PROXY this.votProxyHeader = ui.createHeader( - localizationProvider/* localizationProvider */.V.get("proxySettings"), + localizationProvider.get("proxySettings"), ); this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader); this.votM3u8ProxyHostTextfield = ui.createTextfield( - localizationProvider/* localizationProvider */.V.get("VOTM3u8ProxyHost"), + localizationProvider.get("VOTM3u8ProxyHost"), this.data?.m3u8ProxyHost, - config/* m3u8ProxyHost */.e6, + config/* m3u8ProxyHost */.se, ); this.votSettingsDialog.bodyContainer.appendChild( this.votM3u8ProxyHostTextfield.container, @@ -4635,9 +4871,9 @@ class VideoHandler { // cf version only this.votProxyWorkerHostTextfield = ui.createTextfield( - localizationProvider/* localizationProvider */.V.get("VOTProxyWorkerHost"), + localizationProvider.get("VOTProxyWorkerHost"), this.data?.proxyWorkerHost, - config/* proxyWorkerHost */.ez, + config/* proxyWorkerHost */.Pm, ); this.votProxyWorkerHostTextfield.container.hidden = "cloudflare" !== "cloudflare"; @@ -4647,7 +4883,7 @@ class VideoHandler { // cf version only this.votAudioProxyCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTAudioProxy"), + localizationProvider.get("VOTAudioProxy"), this.data?.audioProxy ?? false, ); this.votAudioProxyCheckbox.container.hidden = "cloudflare" !== "cloudflare"; @@ -4657,27 +4893,27 @@ class VideoHandler { // ABOUT - this.votAboutHeader = ui.createHeader(localizationProvider/* localizationProvider */.V.get("about")); + this.votAboutHeader = ui.createHeader(localizationProvider.get("about")); this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader); this.votLanguageSelect = ui.createVOTSelect( - localizationProvider/* localizationProvider */.V.get("langs")[ - storage/* votStorage */.i.syncGet("locale-lang-override", "auto") + localizationProvider.get("langs")[ + storage/* votStorage */.d.syncGet("locale-lang-override", "auto") ], - localizationProvider/* localizationProvider */.V.get("VOTMenuLanguage"), + localizationProvider.get("VOTMenuLanguage"), genOptionsByOBJ( - localizationProvider/* availableLocales */.Z, - storage/* votStorage */.i.syncGet("locale-lang-override", "auto"), + availableLocales, + storage/* votStorage */.d.syncGet("locale-lang-override", "auto"), ), { onSelectCb: async (e) => { - await storage/* votStorage */.i.set( + await storage/* votStorage */.d.set( "locale-lang-override", e.target.dataset.votValue, ); }, labelElement: ui.createVOTSelectLabel( - localizationProvider/* localizationProvider */.V.get("VOTMenuLanguage"), + localizationProvider.get("VOTMenuLanguage"), ), }, ); @@ -4687,16 +4923,16 @@ class VideoHandler { ); this.votShowPiPButtonCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTShowPiPButton"), + localizationProvider.get("VOTShowPiPButton"), this.data?.showPiPButton ?? false, ); - this.votShowPiPButtonCheckbox.container.hidden = !(0,utils/* isPiPAvailable */.qq)(); + this.votShowPiPButtonCheckbox.container.hidden = !isPiPAvailable(); this.votSettingsDialog.bodyContainer.appendChild( this.votShowPiPButtonCheckbox.container, ); this.votVersionInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTVersion")}:`, + `${localizationProvider.get("VOTVersion")}:`, true ? `cloudflare ${GM_info.script.version}` : 0, @@ -4706,7 +4942,7 @@ class VideoHandler { ); this.votAuthorsInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTAuthors")}:`, + `${localizationProvider.get("VOTAuthors")}:`, GM_info.script.author, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4714,7 +4950,7 @@ class VideoHandler { ); this.votLoaderInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTLoader")}:`, + `${localizationProvider.get("VOTLoader")}:`, `${GM_info.scriptHandler} v${GM_info.version}`, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4722,7 +4958,7 @@ class VideoHandler { ); this.votBrowserInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTBrowser")}:`, + `${localizationProvider.get("VOTBrowser")}:`, `${browserInfo.browser.name} ${browserInfo.browser.version} (${browserInfo.os.name} ${browserInfo.os.version})`, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4730,7 +4966,7 @@ class VideoHandler { ); this.votResetSettingsButton = ui.createButton( - localizationProvider/* localizationProvider */.V.get("resetSettings"), + localizationProvider.get("resetSettings"), ); this.votSettingsDialog.bodyContainer.appendChild( this.votResetSettingsButton, @@ -4741,38 +4977,47 @@ class VideoHandler { initUIEvents() { // VOT Button { - this.votButton.translateButton.addEventListener("click", async () => { - if (this.audio.src) { - debug/* default */.Z.log("[click translationBtn] audio.src is not empty"); - this.stopTraslate(); - return; - } - - try { - debug/* default */.Z.log("[click translationBtn] trying execute translation"); - const VIDEO_ID = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); + this.votButton.translateButton.addEventListener("click", () => { + (async () => { + if (this.audio.src) { + debug/* default */.A.log("[click translationBtn] audio.src is not empty"); + this.stopTranslate(); + return; + } - if (!VIDEO_ID) { - throw new VOTLocalizedError("VOTNoVideoIDFound"); + if (this.hls.url) { + debug/* default */.A.log("[click translationBtn] hls is not empty"); + this.stopTranslate(); + return; } - await this.translateExecutor(VIDEO_ID); - } catch (err) { - console.error("[VOT]", err); - if (err?.name === "VOTLocalizedError") { - this.transformBtn("error", err.localizedMessage); - } else { - this.transformBtn("error", err); + try { + debug/* default */.A.log("[click translationBtn] trying execute translation"); + + if (!this.videoData.videoId) { + throw new VOTLocalizedError("VOTNoVideoIDFound"); + } + + await this.translateExecutor(this.videoData.videoId); + } catch (err) { + console.error("[VOT]", err); + if (err?.name === "VOTLocalizedError") { + this.transformBtn("error", err.localizedMessage); + } else { + this.transformBtn("error", err); + } } - } + })(); }); - this.votButton.pipButton.addEventListener("click", async () => { - if (this.video !== document.pictureInPictureElement) { - await this.video.requestPictureInPicture(); - } else { - await document.exitPictureInPicture(); - } + this.votButton.pipButton.addEventListener("click", () => { + (async () => { + if (this.video !== document.pictureInPictureElement) { + await this.video.requestPictureInPicture(); + } else { + await document.exitPictureInPicture(); + } + })(); }); this.votButton.menuButton.addEventListener("click", () => { @@ -4798,9 +5043,8 @@ class VideoHandler { this.votSettingsButton.addEventListener("click", () => { this.votSettingsDialog.container.hidden = !this.votSettingsDialog.container.hidden; - if (document.fullscreen === undefined || document.fullscreen) { + if (document.fullscreenElement || document.webkitFullscreenElement) { document.webkitExitFullscreen && document.webkitExitFullscreen(); - document.mozCancelFullscreen && document.mozCancelFullscreen(); document.exitFullscreen && document.exitFullscreen(); } }); @@ -4834,128 +5078,139 @@ class VideoHandler { this.votVideoTranslationVolumeSlider.input.addEventListener( "input", - async (e) => { - this.data.defaultVolume = Number(e.target.value); - await storage/* votStorage */.i.set("defaultVolume", this.data.defaultVolume); - this.votVideoTranslationVolumeSlider.label.querySelector( - "strong", - ).innerHTML = `${this.data.defaultVolume}%`; - this.audio.volume = this.data.defaultVolume / 100; - if (this.data.syncVolume === 1) { - this.syncTranslationWithVideo(this.data.defaultVolume); - } + (e) => { + (async () => { + this.data.defaultVolume = Number(e.target.value); + await storage/* votStorage */.d.set("defaultVolume", this.data.defaultVolume); + this.votVideoTranslationVolumeSlider.label.querySelector( + "strong", + ).innerHTML = `${this.data.defaultVolume}%`; + this.audio.volume = this.data.defaultVolume / 100; + if (this.data.syncVolume === 1) { + this.syncTranslationWithVideo(this.data.defaultVolume); + } + })(); }, ); } // VOT Settings { - this.votAutoTranslateCheckbox.input.addEventListener( - "change", - async (e) => { + this.votAutoTranslateCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.autoTranslate = Number(e.target.checked); - await storage/* votStorage */.i.set("autoTranslate", this.data.autoTranslate); - debug/* default */.Z.log( + await storage/* votStorage */.d.set("autoTranslate", this.data.autoTranslate); + debug/* default */.A.log( "autoTranslate value changed. New value: ", this.data.autoTranslate, ); - }, - ); + })(); + }); this.votDontTranslateYourLangSelect.labelElement.addEventListener( "change", - async (e) => { - this.data.dontTranslateYourLang = Number(e.target.checked); - await storage/* votStorage */.i.set( - "dontTranslateYourLang", - this.data.dontTranslateYourLang, - ); - debug/* default */.Z.log( - "dontTranslateYourLang value changed. New value: ", - this.data.dontTranslateYourLang, - ); + (e) => { + (async () => { + this.data.dontTranslateYourLang = Number(e.target.checked); + await storage/* votStorage */.d.set( + "dontTranslateYourLang", + this.data.dontTranslateYourLang, + ); + debug/* default */.A.log( + "dontTranslateYourLang value changed. New value: ", + this.data.dontTranslateYourLang, + ); + })(); }, ); - this.votAutoSetVolumeCheckbox.input.addEventListener( - "change", - async (e) => { + this.votAutoSetVolumeCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.autoSetVolumeYandexStyle = Number(e.target.checked); - await storage/* votStorage */.i.set( + await storage/* votStorage */.d.set( "autoSetVolumeYandexStyle", this.data.autoSetVolumeYandexStyle, ); - debug/* default */.Z.log( + debug/* default */.A.log( "autoSetVolumeYandexStyle value changed. New value: ", this.data.autoSetVolumeYandexStyle, ); - }, - ); + })(); + }); - this.votAutoSetVolumeSlider.input.addEventListener("input", async (e) => { - const presetAutoVolume = Number(e.target.value); - this.data.autoVolume = presetAutoVolume / 100; - await storage/* votStorage */.i.set("autoVolume", presetAutoVolume); - this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML = - `${presetAutoVolume}%`; + this.votAutoSetVolumeSlider.input.addEventListener("input", (e) => { + (async () => { + const presetAutoVolume = Number(e.target.value); + this.data.autoVolume = (presetAutoVolume / 100).toFixed(2); + await storage/* votStorage */.d.set("autoVolume", this.data.autoVolume); + this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML = + `${presetAutoVolume}%`; + })(); }); - this.votShowVideoSliderCheckbox.input.addEventListener( - "change", - async (e) => { + this.votShowVideoSliderCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.showVideoSlider = Number(e.target.checked); - await storage/* votStorage */.i.set("showVideoSlider", this.data.showVideoSlider); - debug/* default */.Z.log( + await storage/* votStorage */.d.set("showVideoSlider", this.data.showVideoSlider); + debug/* default */.A.log( "showVideoSlider value changed. New value: ", this.data.showVideoSlider, ); this.votVideoVolumeSlider.container.hidden = this.data.showVideoSlider !== 1 || this.votButton.container.dataset.status !== "success"; - }, - ); + })(); + }); - this.votUdemyDataTextfield.input.addEventListener("change", async (e) => { - this.data.udemyData = { - accessToken: e.target.value, - expires: new Date().getTime(), - }; - await storage/* votStorage */.i.set("udemyData", this.data.udemyData); - debug/* default */.Z.log("udemyData value changed. New value: ", this.data.udemyData); - window.location.reload(); + this.votUdemyDataTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.udemyData = { + accessToken: e.target.value, + expires: new Date().getTime(), + }; + await storage/* votStorage */.d.set("udemyData", this.data.udemyData); + debug/* default */.A.log( + "udemyData value changed. New value: ", + this.data.udemyData, + ); + window.location.reload(); + })(); }); - this.votSyncVolumeCheckbox.input.addEventListener("change", async (e) => { - this.data.syncVolume = Number(e.target.checked); - await storage/* votStorage */.i.set("syncVolume", this.data.syncVolume); - debug/* default */.Z.log( - "syncVolume value changed. New value: ", - this.data.syncVolume, - ); + this.votSyncVolumeCheckbox.input.addEventListener("change", (e) => { + (async () => { + this.data.syncVolume = Number(e.target.checked); + await storage/* votStorage */.d.set("syncVolume", this.data.syncVolume); + debug/* default */.A.log( + "syncVolume value changed. New value: ", + this.data.syncVolume, + ); + })(); }); this.votTranslationServiceSelect.labelElement.addEventListener( "change", - async (e) => { - this.data.translateAPIErrors = Number(e.target.checked); - await storage/* votStorage */.i.set( - "translateAPIErrors", - this.data.translateAPIErrors, - ); - debug/* default */.Z.log( - "translateAPIErrors value changed. New value: ", - this.data.translateAPIErrors, - ); + (e) => { + (async () => { + this.data.translateAPIErrors = Number(e.target.checked); + await storage/* votStorage */.d.set( + "translateAPIErrors", + this.data.translateAPIErrors, + ); + debug/* default */.A.log( + "translateAPIErrors value changed. New value: ", + this.data.translateAPIErrors, + ); + })(); }, ); // SUBTITLES - this.votSubtitlesMaxLengthSlider.input.addEventListener( - "input", - async (e) => { + this.votSubtitlesMaxLengthSlider.input.addEventListener("input", (e) => { + (async () => { this.data.subtitlesMaxLength = Number(e.target.value); - await storage/* votStorage */.i.set( + await storage/* votStorage */.d.set( "subtitlesMaxLength", this.data.subtitlesMaxLength, ); @@ -4963,81 +5218,84 @@ class VideoHandler { "strong", ).innerHTML = `${this.data.subtitlesMaxLength}`; this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength); - }, - ); + })(); + }); this.votSubtitlesHighlightWordsCheckbox.input.addEventListener( "change", - async (e) => { - this.data.highlightWords = Number(e.target.checked); - await storage/* votStorage */.i.set("highlightWords", this.data.highlightWords); - debug/* default */.Z.log( - "highlightWords value changed. New value: ", - this.data.highlightWords, - ); - this.subtitlesWidget.setHighlightWords(this.data.highlightWords); + (e) => { + (async () => { + this.data.highlightWords = Number(e.target.checked); + await storage/* votStorage */.d.set("highlightWords", this.data.highlightWords); + debug/* default */.A.log( + "highlightWords value changed. New value: ", + this.data.highlightWords, + ); + this.subtitlesWidget.setHighlightWords(this.data.highlightWords); + })(); }, ); - this.votShowPiPButtonCheckbox.input.addEventListener( - "change", - async (e) => { + this.votShowPiPButtonCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.showPiPButton = Number(e.target.checked); - await storage/* votStorage */.i.set("showPiPButton", this.data.showPiPButton); - debug/* default */.Z.log( + await storage/* votStorage */.d.set("showPiPButton", this.data.showPiPButton); + debug/* default */.A.log( "showPiPButton value changed. New value: ", this.data.showPiPButton, ); this.votButton.pipButton.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data.showPiPButton; + !isPiPAvailable() || !this.data.showPiPButton; this.votButton.separator2.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data.showPiPButton; - }, - ); + !isPiPAvailable() || !this.data.showPiPButton; + })(); + }); // PROXY - this.votM3u8ProxyHostTextfield.input.addEventListener( - "change", - async (e) => { - this.data.m3u8ProxyHost = e.target.value || config/* m3u8ProxyHost */.e6; - await storage/* votStorage */.i.set("m3u8ProxyHost", this.data.m3u8ProxyHost); - debug/* default */.Z.log( + this.votM3u8ProxyHostTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.m3u8ProxyHost = e.target.value || config/* m3u8ProxyHost */.se; + await storage/* votStorage */.d.set("m3u8ProxyHost", this.data.m3u8ProxyHost); + debug/* default */.A.log( "m3u8ProxyHost value changed. New value: ", this.data.m3u8ProxyHost, ); - }, - ); + })(); + }); - this.votProxyWorkerHostTextfield.input.addEventListener( - "change", - async (e) => { - this.data.proxyWorkerHost = e.target.value || config/* proxyWorkerHost */.ez; - await storage/* votStorage */.i.set("proxyWorkerHost", this.data.proxyWorkerHost); - debug/* default */.Z.log( + this.votProxyWorkerHostTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.proxyWorkerHost = e.target.value || config/* proxyWorkerHost */.Pm; + await storage/* votStorage */.d.set("proxyWorkerHost", this.data.proxyWorkerHost); + debug/* default */.A.log( "proxyWorkerHost value changed. New value: ", this.data.proxyWorkerHost, ); window.location.reload(); - }, - ); + })(); + }); - this.votAudioProxyCheckbox.input.addEventListener("change", async (e) => { - this.data.audioProxy = Number(e.target.checked); - await storage/* votStorage */.i.set("audioProxy", this.data.audioProxy); - debug/* default */.Z.log( - "audioProxy value changed. New value: ", - this.data.audioProxy, - ); + this.votAudioProxyCheckbox.input.addEventListener("change", (e) => { + (async () => { + this.data.audioProxy = Number(e.target.checked); + await storage/* votStorage */.d.set("audioProxy", this.data.audioProxy); + debug/* default */.A.log( + "audioProxy value changed. New value: ", + this.data.audioProxy, + ); + })(); }); - this.votResetSettingsButton.addEventListener("click", async () => { - localizationProvider/* localizationProvider */.V.reset(); - const valuesForClear = await storage/* votStorage */.i.list(); - valuesForClear - .filter((v) => !localizationProvider/* localizationProvider */.V.gmValues.includes(v)) - .forEach((v) => storage/* votStorage */.i.syncDelete(v)); - window.location.reload(); + this.votResetSettingsButton.addEventListener("click", () => { + (async () => { + localizationProvider.reset(); + const valuesForClear = await storage/* votStorage */.d.list(); + valuesForClear + .filter((v) => !localizationProvider.gmValues.includes(v)) + .forEach((v) => storage/* votStorage */.d.syncDelete(v)); + window.location.reload(); + })(); }); } } @@ -5045,7 +5303,10 @@ class VideoHandler { releaseExtraEvents() { clearInterval(this.resizeInterval); this.resizeObserver?.disconnect(); - if (this.site.host === "youtube" && this.site.additionalData !== "mobile") { + if ( + ["youtube", "googledrive"].includes(this.site.host) && + this.site.additionalData !== "mobile" + ) { this.syncVolumeObserver?.disconnect(); } @@ -5094,7 +5355,10 @@ class VideoHandler { ); }, 500); // Sync volume slider with original video (youtube only) - if (this.site.host === "youtube" && this.site.additionalData !== "mobile") { + if ( + ["youtube", "googledrive"].includes(this.site.host) && + this.site.additionalData !== "mobile" + ) { this.syncVolumeObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if ( @@ -5132,7 +5396,7 @@ class VideoHandler { const isSettings = settings.contains(e); const isTempDialog = tempDialog?.contains(e) ?? false; - debug/* default */.Z.log( + debug/* default */.A.log( `[document click] ${isButton} ${isMenu} ${isVideo} ${isSettings} ${isTempDialog}`, ); if (!(!isButton && !isMenu && !isSettings && !isTempDialog)) return; @@ -5194,25 +5458,26 @@ class VideoHandler { this.container.draggable = false; } - addExtraEventListener(this.video, "abort", () => { - debug/* default */.Z.log("lipsync mode is abort"); + addExtraEventListener(this.video, "emptied", () => { + debug/* default */.A.log("lipsync mode is emptied"); this.stopTranslation(); - this.videoData = ""; }); addExtraEventListener(this.video, "progress", async () => { - if (!(this.firstPlay && this.data.autoTranslate === 1)) { + if ( + !(this.firstPlay && this.data.autoTranslate === 1) || + getVideoId(this.site.host, this.video) !== this.videoData.videoId + ) { return; } - const VIDEO_ID = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); - if (!VIDEO_ID) { + if (!this.videoData.videoId) { throw new VOTLocalizedError("VOTNoVideoIDFound"); } try { - await this.translateExecutor(VIDEO_ID); this.firstPlay = false; + await this.translateExecutor(this.videoData.videoId); } catch (err) { console.error("[VOT]", err); if (err?.name === "VOTLocalizedError") { @@ -5235,7 +5500,7 @@ class VideoHandler { this.logout(1); this.timer = setTimeout(() => { this.logout(0); - }, 2000); + }, 1000); } changeOpacityOnEvent(event) { @@ -5245,11 +5510,11 @@ class VideoHandler { } async changeSubtitlesLang(subs) { - debug/* default */.Z.log("[onchange] subtitles", subs); + debug/* default */.A.log("[onchange] subtitles", subs); this.votSubtitlesSelect.setSelected(subs); if (subs === "disabled") { this.votSubtitlesSelect.setTitle( - localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), + localizationProvider.get("VOTSubtitlesDisabled"), ); this.subtitlesWidget.setContent(null); this.votDownloadSubtitlesButton.hidden = true; @@ -5267,24 +5532,24 @@ class VideoHandler { async updateSubtitlesLangSelect() { const updatedOptions = [ { - label: localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), + label: localizationProvider.get("VOTSubtitlesDisabled"), value: "disabled", selected: true, disabled: false, }, ...this.subtitlesList.map((s, idx) => ({ label: - (localizationProvider/* localizationProvider */.V.get("langs")[s.language] ?? + (localizationProvider.get("langs")[s.language] ?? s.language.toUpperCase()) + (s.translatedFromLanguage - ? ` ${localizationProvider/* localizationProvider */.V.get("VOTTranslatedFrom")} ${ - localizationProvider/* localizationProvider */.V.get("langs")[s.translatedFromLanguage] ?? + ? ` ${localizationProvider.get("VOTTranslatedFrom")} ${ + localizationProvider.get("langs")[s.translatedFromLanguage] ?? s.translatedFromLanguage.toUpperCase() }` : "") + (s.source !== "yandex" ? ` ${s.source}` : "") + (s.isAutoGenerated - ? ` (${localizationProvider/* localizationProvider */.V.get("VOTAutogenerated")})` + ? ` (${localizationProvider.get("VOTAutogenerated")})` : ""), value: idx, selected: false, @@ -5300,11 +5565,9 @@ class VideoHandler { async updateSubtitles() { await this.changeSubtitlesLang("disabled"); - const VIDEO_ID = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); - - if (!VIDEO_ID) { + if (!this.videoData.videoId) { console.error( - `[VOT] ${localizationProvider/* localizationProvider */.V.getDefault("VOTNoVideoIDFound")}`, + `[VOT] ${localizationProvider.getDefault("VOTNoVideoIDFound")}`, ); this.subtitlesList = []; this.subtitlesListVideoId = null; @@ -5312,27 +5575,19 @@ class VideoHandler { return; } - if (this.subtitlesListVideoId === VIDEO_ID) { + if (this.subtitlesListVideoId === this.videoData.videoId) { return; } - if (!this.videoData.detectedLanguage) { - this.videoData = await this.getVideoData(); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.videoData.responseLanguage, - ); - } - this.subtitlesList = await subtitles_getSubtitles( this.site, - VIDEO_ID, + this.videoData.videoId, this.videoData.detectedLanguage, ); if (!this.subtitlesList) { await this.changeSubtitlesLang("disabled"); } else { - this.subtitlesListVideoId = VIDEO_ID; + this.subtitlesListVideoId = this.videoData.videoId; } await this.updateSubtitlesLangSelect(); } @@ -5340,7 +5595,7 @@ class VideoHandler { // Get video volume in 0.00-1.00 format getVideoVolume() { let videoVolume = this.video?.volume; - if (this.site.host === "youtube") { + if (["youtube", "googledrive"].includes(this.site.host)) { videoVolume = youtubeUtils.getVideoVolume() || videoVolume; } return videoVolume; @@ -5348,7 +5603,7 @@ class VideoHandler { // Set video volume in 0.00-1.00 format setVideoVolume(volume) { - if (this.site.host === "youtube") { + if (["youtube", "googledrive"].includes(this.site.host)) { const videoVolume = youtubeUtils.setVideoVolume(volume); if (videoVolume) { return; @@ -5373,10 +5628,10 @@ class VideoHandler { setSelectMenuValues(from, to) { this.votTranslationLanguageSelect.fromSelect.setTitle( - localizationProvider/* localizationProvider */.V.get("langs")[from], + localizationProvider.get("langs")[from], ); this.votTranslationLanguageSelect.toSelect.setTitle( - localizationProvider/* localizationProvider */.V.get("langs")[to], + localizationProvider.get("langs")[to], ); this.votTranslationLanguageSelect.fromSelect.setSelected(from); this.votTranslationLanguageSelect.toSelect.setSelected(to); @@ -5410,17 +5665,16 @@ class VideoHandler { } async getVideoData() { - const videoData = {}; - - // ! should be null for ALL websites except coursera and udemy ! - // else use direct link: `{url: xxx.mp4}` - videoData.translationHelp = null; - - videoData.isStream = false; // by default, we request the translation of the video - videoData.duration = this.video?.duration || 343; // ! if 0 - we get 400 error - videoData.videoId = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); - videoData.detectedLanguage = this.translateFromLang; - videoData.responseLanguage = this.translateToLang; + const videoData = { + // ! should be null for ALL websites except coursera and udemy ! + // else use direct link: `{url: xxx.mp4}` + translationHelp: null, + isStream: false, // by default, we request the translation of the video + duration: this.video?.duration || 343, // ! if 0 - we get 400 error + videoId: getVideoId(this.site.host, this.video), + detectedLanguage: this.translateFromLang, + responseLanguage: this.translateToLang, + }; if (!videoData.videoId) { this.ytData = {}; @@ -5436,11 +5690,15 @@ class VideoHandler { } } else if ( window.location.hostname.includes("rutube") || + window.location.hostname.includes("ok.ru") || window.location.hostname.includes("my.mail.ru") ) { videoData.detectedLanguage = "ru"; - } else if (window.location.hostname.includes("bilibili.com")) { + } else if (["bilibili", "youku"].includes(this.site.host)) { videoData.detectedLanguage = "zh"; + } else if (["vk"].includes(this.site.host)) { + const trackLang = document.getElementsByTagName("track")?.[0]?.srclang; + videoData.detectedLanguage = trackLang || "auto"; } else if (window.location.hostname.includes("coursera.org")) { const courseraData = await courseraUtils.getVideoData( this.translateToLang, @@ -5455,6 +5713,25 @@ class VideoHandler { url: coursehunterData.url, }; videoData.duration = coursehunterData.duration || videoData.duration; + } else if (window.location.hostname.includes("banned.video")) { + const bannedvideoData = await bannedvideoUtils.getVideoData( + videoData.videoId, + ); + videoData.translationHelp = { + url: bannedvideoData.url, + }; + + videoData.duration = bannedvideoData.duration || videoData.duration; + videoData.isStream = bannedvideoData.live; + } else if (window.location.hostname.includes("weverse.io")) { + const weverseData = await weverseUtils.getVideoData(); + videoData.detectedLanguage = "ko"; + if (weverseData) { + videoData.translationHelp = { + url: weverseData.url, + }; + videoData.duration = weverseData.duration || videoData.duration; + } } else if (window.location.hostname.includes("udemy.com")) { const udemyData = await udemyUtils.getVideoData( this.data.udemyData, @@ -5464,25 +5741,25 @@ class VideoHandler { videoData.detectedLanguage = udemyData.detectedLanguage; videoData.translationHelp = udemyData.translationHelp; } else if ( - this.site.host === "vk" || - this.site.host === "piped" || - this.site.host === "invidious" || - this.site.host === "bitchute" || - this.site.host === "rumble" || - this.site.host === "peertube" || - this.site.host === "dailymotion" || - this.site.host === "trovo" || - this.site.host === "yandexdisk" || - this.site.host === "coursehunter" + [ + "piped", + "invidious", + "bitchute", + "rumble", + "peertube", + "dailymotion", + "trovo", + "yandexdisk", + "coursehunter", + ].includes(this.site.host) ) { videoData.detectedLanguage = "auto"; } return videoData; } - videoValidator() { - if (this.site.host === "youtube") { - debug/* default */.Z.log("VideoValidator videoData: ", this.videoData); + if (["youtube", "ok.ru", "vk"].includes(this.site.host)) { + debug/* default */.A.log("VideoValidator videoData: ", this.videoData); if ( this.data.dontTranslateYourLang === 1 && this.videoData.detectedLanguage === this.data.dontTranslateLanguage && @@ -5496,7 +5773,7 @@ class VideoHandler { // if (this.ytData.isLive) { // throw new VOTLocalizedError("VOTLiveNotSupported"); // } - if (this.videoData.duration > 14_400) { + if (!this.videoData.isStream && this.videoData.duration > 14_400) { throw new VOTLocalizedError("VOTVideoIsTooLong"); } } @@ -5504,7 +5781,7 @@ class VideoHandler { } lipSync(mode = false) { - debug/* default */.Z.log("lipsync video", this.video); + debug/* default */.A.log("lipsync video", this.video); if (!this.video) { return; } @@ -5512,12 +5789,12 @@ class VideoHandler { this.audio.playbackRate = this.video.playbackRate; if (!mode) { - debug/* default */.Z.log("lipsync mode is not set"); + debug/* default */.A.log("lipsync mode is not set"); return; } - if (mode === "play") { - debug/* default */.Z.log("lipsync mode is play"); + if (mode == "play") { + debug/* default */.A.log("lipsync mode is play"); const audioPromise = this.audio.play(); if (audioPromise !== undefined) { audioPromise.catch((e) => { @@ -5525,15 +5802,15 @@ class VideoHandler { if (e.name === "NotAllowedError") { this.transformBtn( "error", - localizationProvider/* localizationProvider */.V.get("grantPermissionToAutoPlay"), + localizationProvider.get("grantPermissionToAutoPlay"), ); throw new VOTLocalizedError("grantPermissionToAutoPlay"); } else if (e.name === "NotSupportedError") { this.transformBtn( "error", sitesChromiumBlocked.includes(window.location.hostname) - ? localizationProvider/* localizationProvider */.V.get("neededAdditionalExtension") - : localizationProvider/* localizationProvider */.V.get("audioFormatNotSupported"), + ? localizationProvider.get("neededAdditionalExtension") + : localizationProvider.get("audioFormatNotSupported"), ); throw sitesChromiumBlocked.includes(window.location.hostname) ? new VOTLocalizedError("neededAdditionalExtension") @@ -5543,69 +5820,49 @@ class VideoHandler { } return; } - if (mode === "pause") { - debug/* default */.Z.log("lipsync mode is pause"); - this.audio.pause(); - } - if (mode === "stop") { - debug/* default */.Z.log("lipsync mode is stop"); - this.audio.pause(); - } - if (mode === "waiting") { - debug/* default */.Z.log("lipsync mode is waiting"); + // video is inactive + if (["pause", "stop", "waiting"].includes(mode)) { + debug/* default */.A.log(`lipsync mode is ${mode}`); this.audio.pause(); } - if (mode === "playing") { - debug/* default */.Z.log("lipsync mode is playing"); + + if (mode == "playing") { + debug/* default */.A.log("lipsync mode is playing"); this.audio.play(); } } // Define a function to handle common events handleVideoEvent(event) { - debug/* default */.Z.log(`video ${event.type}`); + debug/* default */.A.log(`video ${event.type}`); this.lipSync(event.type); } // Default actions on stop translate - stopTraslate() { + stopTranslate() { videoLipSyncEvents.forEach((e) => this.video.removeEventListener(e, this.handleVideoEventBound), ); this.audio.pause(); - //! video.removeEventListener(".translate", stopTraslate, false); // why??? this.audio.src = ""; this.audio.removeAttribute("src"); this.votVideoVolumeSlider.container.hidden = true; this.votVideoTranslationVolumeSlider.container.hidden = true; this.votDownloadButton.hidden = true; this.downloadTranslationUrl = null; - this.transformBtn("none", localizationProvider/* localizationProvider */.V.get("translateVideo")); + this.transformBtn("none", localizationProvider.get("translateVideo")); + debug/* default */.A.log(`Volume on start: ${this.volumeOnStart}`); if (this.volumeOnStart) { - debug/* default */.Z.log(`Volume on start: ${this.volumeOnStart}`); - if (this.site.host === "youtube") { - youtubeUtils.setVideoVolume(this.volumeOnStart); - } else { - this.video.volume = this.volumeOnStart; - } + this.setVideoVolume(this.volumeOnStart); } + this.volumeOnStart = ""; clearInterval(this.streamPing); this.hls?.destroy(); - this.hls = (0,utils/* initHls */.QZ)(); + this.hls = initHls(); } async translateExecutor(VIDEO_ID) { - if (!this.videoData.detectedLanguage) { - this.videoData = await this.getVideoData(); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.videoData.responseLanguage, - ); - } - debug/* default */.Z.log("Run videoValidator"); - this.videoValidator(); - - debug/* default */.Z.log("Run translateFunc"); + debug/* default */.A.log("Run translateFunc"); this.translateFunc( VIDEO_ID, this.videoData.isStream, @@ -5615,6 +5872,94 @@ class VideoHandler { ); } + async updateTranslationErrorMsg(errorMessage) { + const translationTake = localizationProvider.get("translationTake"); + const VOTTranslatingError = localizationProvider.get("VOTTranslatingError"); + const lang = localizationProvider.lang; + + if (errorMessage?.name === "VOTLocalizedError") { + this.transformBtn("error", errorMessage.localizedMessage); + } else if ( + this.data.translateAPIErrors === 1 && + !errorMessage.includes(translationTake) && + lang !== "ru" + ) { + const translatedMessage = await translate(errorMessage, "ru", lang); + this.transformBtn("error", VOTTranslatingError); + this.transformBtn("error", translatedMessage); + } else { + this.transformBtn("error", errorMessage); + } + } + + afterUpdateTranslation(audioUrl) { + this.votVideoVolumeSlider.container.hidden = + this.data.showVideoSlider !== 1 || + this.votButton.container.dataset.status !== "success"; + this.votVideoTranslationVolumeSlider.container.hidden = + this.votButton.container.dataset.status !== "success"; + + if (this.data.autoSetVolumeYandexStyle === 1) { + this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; + this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = + `${this.data.autoVolume * 100}%`; + ui.updateSlider(this.votVideoVolumeSlider.input); + } + + this.votDownloadButton.hidden = false; + this.downloadTranslationUrl = audioUrl; + } + + // update translation audio src + updateTranslation(audioUrl) { + // ! Don't use this function for streams + this.audio.src = audioUrl; + + // cf version only + if ( + true && + this.data.audioProxy === 1 && + audioUrl.startsWith("https://vtrans.s3-private.mds.yandex.net/tts/prod/") + ) { + const audioPath = audioUrl.replace( + "https://vtrans.s3-private.mds.yandex.net/tts/prod/", + "", + ); + const proxiedAudioUrl = `https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${audioPath}`; + console.log(`[VOT] Audio proxied via ${proxiedAudioUrl}`); + this.audio.src = proxiedAudioUrl; + } + + this.volumeOnStart = this.getVideoVolume(); + if (typeof this.data.defaultVolume === "number") { + this.audio.volume = this.data.defaultVolume / 100; + } + if ( + typeof this.data.autoSetVolumeYandexStyle === "number" && + this.data.autoSetVolumeYandexStyle + ) { + this.setVideoVolume(this.data.autoVolume); + } + + switch (this.site.host) { + case "twitter": + document + .querySelector('div[data-testid="app-bar-back"][role="button"]') + .addEventListener("click", this.stopTranslationBound); + break; + case "invidious": + case "piped": + break; + } + + if (this.video && !this.video.paused) this.lipSync("play"); + videoLipSyncEvents.forEach((e) => + this.video.addEventListener(e, this.handleVideoEventBound), + ); + this.transformBtn("success", localizationProvider.get("disableTranslate")); + this.afterUpdateTranslation(audioUrl); + } + // Define a function to translate a video and handle the callback translateFunc( VIDEO_ID, @@ -5629,42 +5974,20 @@ class VideoHandler { : `${this.site.url}${VIDEO_ID}`; // fix enabling the old requested voiceover when changing the language to the native language (#) + debug/* default */.A.log("Run videoValidator"); this.videoValidator(); if (isStream) { - debug/* default */.Z.log("Executed stream translation"); - // if (BUILD_MODE === "cloudflare") { - // // Temporarily stream translation is only available in the main version - // throw new VOTLocalizedError("VOTCloudflareDoesntSupportStreams"); - // } - + debug/* default */.A.log("Executed stream translation"); translateStream( videoURL, requestLang, responseLang, async (success, reqInterval, resOrError) => { - debug/* default */.Z.log("[exec callback] translateStream callback"); - if ((0,utils/* getVideoId */.gJ)(this.site.host, this.video) !== VIDEO_ID) return; + debug/* default */.A.log("[exec callback] translateStream callback"); + if (getVideoId(this.site.host, this.video) !== VIDEO_ID) return; if (!success || !resOrError.translatedInfo) { - if (resOrError?.name === "VOTLocalizedError") { - this.transformBtn("error", resOrError.localizedMessage); - } else { - if ( - this.data.translateAPIErrors === 1 && - localizationProvider/* localizationProvider */.V.lang !== "ru" - ) { - this.transformBtn( - "error", - `${localizationProvider/* localizationProvider */.V.get("VOTTranslatingError")}...`, - ); - this.transformBtn( - "error", - await translate(resOrError, "ru", localizationProvider/* localizationProvider */.V.lang), - ); - } else { - this.transformBtn("error", resOrError); - } - } + await this.updateTranslationErrorMsg(resOrError); if (reqInterval === 10) { // if wait translating @@ -5687,22 +6010,22 @@ class VideoHandler { this.transformBtn( "success", - localizationProvider/* localizationProvider */.V.get("disableTranslate"), + localizationProvider.get("disableTranslate"), ); console.log(resOrError); const pingId = resOrError.pingId; - debug/* default */.Z.log(`Stream pingId: ${pingId}`); + debug/* default */.A.log(`Stream pingId: ${pingId}`); // if you don't make ping requests, then the translation of the stream dies this.streamPing = setInterval( async () => await rsp(pingId, (result) => - debug/* default */.Z.log("Stream ping result: ", result), + debug/* default */.A.log("Stream ping result: ", result), ), reqInterval * 1000, ); - debug/* default */.Z.log(resOrError.translatedInfo.url); + debug/* default */.A.log(resOrError.translatedInfo.url); const streamURL = `https://${ this.data.m3u8ProxyHost }/?all=yes&origin=${encodeURIComponent( @@ -5710,22 +6033,22 @@ class VideoHandler { )}&referer=${encodeURIComponent( "https://strm.yandex.ru", )}&url=${encodeURIComponent(resOrError.translatedInfo.url)}`; - debug/* default */.Z.log(streamURL); + debug/* default */.A.log(streamURL); if (this.hls) { this.hls.on(Hls.Events.MEDIA_ATTACHED, function () { - debug/* default */.Z.log("audio and hls.js are now bound together !"); + debug/* default */.A.log("audio and hls.js are now bound together !"); }); - this.hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { - debug/* default */.Z.log( + this.hls.on(Hls.Events.MANIFEST_PARSED, function (data) { + debug/* default */.A.log( "manifest loaded, found " + - data.levels.length + + data?.levels?.length + " quality level", ); }); this.hls.loadSource(streamURL); this.hls.attachMedia(this.audio); - this.hls.on(Hls.Events.ERROR, function (event, data) { + this.hls.on(Hls.Events.ERROR, function (data) { if (data.fatal) { switch (data.type) { case Hls.ErrorTypes.MEDIA_ERROR: @@ -5748,7 +6071,7 @@ class VideoHandler { } } }); - debug/* default */.Z.log(this.hls); + debug/* default */.A.log(this.hls); } else if (this.audio.canPlayType("application/vnd.apple.mpegurl")) { // safari this.audio.src = streamURL; @@ -5757,7 +6080,9 @@ class VideoHandler { throw new VOTLocalizedError("audioFormatNotSupported"); } - youtubeUtils.videoSeek(this.video, 10); // 10 is the most successful number for streaming. With it, the audio is not so far behind the original + if (this.site.host === "youtube") { + youtubeUtils.videoSeek(this.video, 10); // 10 is the most successful number for streaming. With it, the audio is not so far behind the original + } this.volumeOnStart = this.getVideoVolume(); if (typeof this.data.defaultVolume === "number") { @@ -5785,21 +6110,7 @@ class VideoHandler { this.video.addEventListener(e, this.handleVideoEventBound), ); - this.votVideoVolumeSlider.container.hidden = - this.data.showVideoSlider !== 1 || - this.votButton.container.dataset.status !== "success"; - this.votVideoTranslationVolumeSlider.container.hidden = - this.votButton.container.dataset.status !== "success"; - - if (this.data.autoSetVolumeYandexStyle === 1) { - this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; - this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = - `${this.data.autoVolume * 100}%`; - ui.updateSlider(this.votVideoVolumeSlider.input); - } - - this.votDownloadButton.hidden = false; - this.downloadTranslationUrl = streamURL; + this.afterUpdateTranslation(streamURL); }, ); @@ -5810,6 +6121,20 @@ class VideoHandler { throw new VOTLocalizedError("VOTTranslationHelpNull"); } + const cachedTranslation = this.videoTranslations.find( + (t) => + t.videoId === VIDEO_ID && + t.expires > Date.now() / 1000 && + t.from === requestLang && + t.to === responseLang, + ); + + if (cachedTranslation) { + this.updateTranslation(cachedTranslation.url); + debug/* default */.A.log("[translateFunc] A cached translate was received"); + return; + } + translateVideo( videoURL, this.videoData.duration, @@ -5817,34 +6142,14 @@ class VideoHandler { responseLang, translationHelp, async (success, urlOrError) => { - debug/* default */.Z.log("[exec callback] translateVideo callback"); - if ((0,utils/* getVideoId */.gJ)(this.site.host, this.video) !== VIDEO_ID) return; + debug/* default */.A.log("[exec callback] translateVideo callback"); + if (getVideoId(this.site.host, this.video) !== VIDEO_ID) return; if (!success) { - if (urlOrError?.name === "VOTLocalizedError") { - this.transformBtn("error", urlOrError.localizedMessage); - } else { - if ( - this.data.translateAPIErrors === 1 && - !urlOrError.includes( - localizationProvider/* localizationProvider */.V.get("translationTake"), - ) && - localizationProvider/* localizationProvider */.V.lang !== "ru" - ) { - this.transformBtn( - "error", - localizationProvider/* localizationProvider */.V.get("VOTTranslatingError"), - ); - this.transformBtn( - "error", - await translate(urlOrError, "ru", localizationProvider/* localizationProvider */.V.lang), - ); - } else { - this.transformBtn("error", urlOrError); - } - } + await this.updateTranslationErrorMsg(urlOrError); + // if the error line contains information that the translation is being performed, then we wait if ( - urlOrError.includes(localizationProvider/* localizationProvider */.V.get("translationTake")) + urlOrError.includes(localizationProvider.get("translationTake")) ) { clearTimeout(this.autoRetry); this.autoRetry = setTimeout( @@ -5863,156 +6168,40 @@ class VideoHandler { return; } - this.audio.src = urlOrError; - - // cf version only - if ( - true && - this.data.audioProxy === 1 && - urlOrError.startsWith("https://") - ) { - const audioPath = urlOrError.replace( - "https://vtrans.s3-private.mds.yandex.net/tts/prod/", - "", - ); - const proxiedAudioUrl = `https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${audioPath}`; - console.log(`[VOT] Audio proxied via ${proxiedAudioUrl}`); - this.audio.src = proxiedAudioUrl; - } - - this.volumeOnStart = this.getVideoVolume(); - if (typeof this.data.defaultVolume === "number") { - this.audio.volume = this.data.defaultVolume / 100; - } - if ( - typeof this.data.autoSetVolumeYandexStyle === "number" && - this.data.autoSetVolumeYandexStyle - ) { - this.setVideoVolume(this.data.autoVolume); - } - - switch (this.site.host) { - case "twitter": - document - .querySelector('div[data-testid="app-bar-back"][role="button"]') - .addEventListener("click", this.stopTranslationBound); - break; - case "invidious": - case "piped": - break; - } - - if ( - !this.video.src && - !this.video.currentSrc && - !this.video.srcObject - ) { - this.stopTranslation(); - return; - } - - const siteHostnames = [ - "twitch", - "vimeo", - "facebook", - "rutube", - "twitter", - "bilibili", - "mail_ru", - "rumble", - "eporner", - ]; - for (let i = 0; i < siteHostnames.length; i++) { - if (this.site.host === siteHostnames[i]) { - const mutationObserver = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if ( - mutation.type === "attributes" && - mutation.attributeName === "src" && - mutation.target === this.video && - mutation.target.src !== "" - ) { - this.stopTranslation(); - this.firstPlay = true; - } - }); - }); - mutationObserver.observe(this.container, { - attributes: true, - childList: false, - subtree: true, - attributeOldValue: true, - }); - break; - } - } - - if (this.video && !this.video.paused) this.lipSync("play"); - videoLipSyncEvents.forEach((e) => - this.video.addEventListener(e, this.handleVideoEventBound), - ); - this.transformBtn( - "success", - localizationProvider/* localizationProvider */.V.get("disableTranslate"), - ); - - this.votVideoVolumeSlider.container.hidden = - this.data.showVideoSlider !== 1 || - this.votButton.container.dataset.status !== "success"; - this.votVideoTranslationVolumeSlider.container.hidden = - this.votButton.container.dataset.status !== "success"; - - if (this.data.autoSetVolumeYandexStyle === 1) { - this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; - this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = - `${this.data.autoVolume * 100}%`; - ui.updateSlider(this.votVideoVolumeSlider.input); - } + this.updateTranslation(urlOrError); - this.votDownloadButton.hidden = false; - this.downloadTranslationUrl = urlOrError; + this.videoTranslations.push({ + videoId: VIDEO_ID, + from: requestLang, + to: responseLang, + url: urlOrError, + expires: Date.now() / 1000 + this.videoTranslationTTL, + }); }, ); } // Define a function to stop translation and clean up stopTranslation() { - this.stopTraslate(); + this.stopTranslate(); this.syncVideoVolumeSlider(); } - async waitInitialization() { - let resolved = false; - return await Promise.race([ - new Promise(async (resolve) => { - await (0,utils/* sleep */._v)(1000); - if (!resolved) { - console.error("[VOT] Initialization timeout"); - } - resolved = true; - resolve(false); - }), - new Promise(async (resolve) => { - while (!this.initialized) { - await (0,utils/* sleep */._v)(100); - } - resolved = true; - resolve(true); - }), - ]); - } - async handleSrcChanged() { - debug/* default */.Z.log("[VideoHandler] src changed", this); - - if (!(await this.waitInitialization())) return; + debug/* default */.A.log("[VideoHandler] src changed", this); this.stopTranslation(); - this.videoData = await this.getVideoData(); - this.firstPlay = true; + this.videoData = await this.getVideoData(); + if (this.videoData.detectedLanguage) { + this.setSelectMenuValues( + this.videoData.detectedLanguage, + this.videoData.responseLanguage, + ); + } + const hide = !this.video.src && !this.video.currentSrc && !this.video.srcObject; this.votButton.container.hidden = hide; @@ -6029,24 +6218,16 @@ class VideoHandler { await this.updateSubtitles(); await this.changeSubtitlesLang("disabled"); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.data.responseLanguage ?? "ru", - ); this.translateToLang = this.data.responseLanguage ?? "ru"; } async release() { - debug/* default */.Z.log("[VideoHandler] release"); + debug/* default */.A.log("[VideoHandler] release"); - if (!(await this.waitInitialization())) return; this.initialized = false; - this.stopTranslation(); this.releaseExtraEvents(); this.subtitlesWidget.release(); - this.srcObserver.disconnect(); - clearInterval(this.srcObjectInterval); this.votButton.container.remove(); this.votMenu.container.remove(); } @@ -6076,17 +6257,17 @@ const videoObserver = new VideoObserver(); const videosWrappers = new WeakMap(); async function src_main() { - debug/* default */.Z.log("Loading extension..."); + debug/* default */.A.log("Loading extension..."); - await localizationProvider/* localizationProvider */.V.update(); + await localizationProvider.update(); - debug/* default */.Z.log(`Selected menu language: ${localizationProvider/* localizationProvider */.V.lang}`); + debug/* default */.A.log(`Selected menu language: ${localizationProvider.lang}`); if ( false ) {} - debug/* default */.Z.log("Extension compatibility passed..."); + debug/* default */.A.log("Extension compatibility passed..."); videoObserver.onVideoAdded.addListener((video) => { for (const site of getSites()) { @@ -6159,6 +6340,19 @@ src_main().catch((e) => { console.error("[VOT]", e); }); +// if (import.meta.webpackHot) { +// import.meta.webpackHot.monkeyReload(); +// import.meta.webpackHot.dispose(() => { +// for (const selector of [ +// ".vot-menu", +// ".vot-segmented-button", +// ".vot-subtitles-widget", +// ]) { +// document.querySelector(selector)?.remove(); +// } +// }); +// } + })(); /******/ })() diff --git a/dist/vot-min.user.js b/dist/vot-min.user.js index 19000a64..15450e0d 100644 --- a/dist/vot-min.user.js +++ b/dist/vot-min.user.js @@ -1,124 +1,131 @@ // ==UserScript== -// @name [VOT] - Voice Over Translation -// @name:de [VOT] - Voice-Over-Video-Übersetzung -// @name:es [VOT] - Traducción de vídeo en off -// @name:fr [VOT] - Traduction vidéo voix-off -// @name:it [VOT] - Traduzione Video fuori campo -// @name:ru [VOT] - Закадровый перевод видео -// @name:zh [VOT] - 画外音视频翻译 -// @description A small extension that adds a Yandex Browser video translation to other browsers +// @name [VOT] - Voice Over Translation +// @name:de [VOT] - Voice-Over-Video-Übersetzung +// @name:es [VOT] - Traducción de vídeo en off +// @name:fr [VOT] - Traduction vidéo voix-off +// @name:it [VOT] - Traduzione Video fuori campo +// @name:ru [VOT] - Закадровый перевод видео +// @name:zh [VOT] - 画外音视频翻译 +// @description A small extension that adds a Yandex Browser video translation to other browsers // @description:de Eine kleine Erweiterung, die eine Voice-over-Übersetzung von Videos aus dem Yandex-Browser zu anderen Browsern hinzufügt // @description:es Una pequeña extensión que agrega una traducción de voz en off de un video de Yandex Browser a otros navegadores // @description:fr Une petite extension qui ajoute la traduction vocale de la vidéo du Navigateur Yandex à d'autres navigateurs // @description:it Una piccola estensione che aggiunge la traduzione vocale del video dal browser Yandex ad altri browser // @description:ru Небольшое расширение, которое добавляет закадровый перевод видео из Яндекс Браузера в другие браузеры // @description:zh 一个小扩展,它增加了视频从Yandex浏览器到其他浏览器的画外音翻译 -// @version 1.5.0.5 -// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD -// @supportURL https://github.com/ilyhalight/voice-over-translation/issues -// @match *://*.youtube.com/* -// @match *://*.youtube-nocookie.com/* -// @match *://*.youtubekids.com/* -// @match *://*.twitch.tv/* -// @match *://*.xvideos.com/* -// @match *://*.pornhub.com/* -// @match *://*.vk.com/* -// @match *://*.vk.ru/* -// @match *://invidious.snopyta.org/* -// @match *://invidious.kavin.rocks/* -// @match *://vid.puffyan.us/* -// @match *://invidious.namazso.eu/* -// @match *://inv.riverside.rocks/* -// @match *://yt.artemislena.eu/* -// @match *://invidious.flokinet.to/* -// @match *://invidious.esmailelbob.xyz/* -// @match *://invidious.nerdvpn.de/* -// @match *://invidious.slipfox.xyz/* -// @match *://invidio.xamh.de/* -// @match *://invidious.dhusch.de/* -// @match *://*.piped.video/* -// @match *://piped.tokhmi.xyz/* -// @match *://piped.moomoo.me/* -// @match *://piped.syncpundit.io/* -// @match *://piped.mha.fi/* -// @match *://watch.whatever.social/* -// @match *://piped.garudalinux.org/* -// @match *://efy.piped.pages.dev/* -// @match *://watch.leptons.xyz/* -// @match *://piped.lunar.icu/* -// @match *://yt.dc09.ru/* -// @match *://piped.mint.lgbt/* -// @match *://*.il.ax/* -// @match *://piped.privacy.com.de/* -// @match *://piped.esmailelbob.xyz/* -// @match *://piped.projectsegfau.lt/* -// @match *://piped.in.projectsegfau.lt/* -// @match *://piped.us.projectsegfau.lt/* -// @match *://piped.privacydev.net/* -// @match *://piped.palveluntarjoaja.eu/* -// @match *://piped.smnz.de/* -// @match *://piped.adminforge.de/* -// @match *://piped.qdi.fi/* -// @match *://piped.hostux.net/* -// @match *://piped.chauvet.pro/* -// @match *://piped.jotoma.de/* -// @match *://piped.pfcd.me/* -// @match *://piped.frontendfriendly.xyz/* -// @match *://*.yewtu.be/* -// @match *://inv.vern.cc/* -// @match *://*.vimeo.com/* -// @match *://*.9gag.com/* -// @match *://*.twitter.com/* -// @match *://*.facebook.com/* -// @match *://*.rutube.ru/* -// @match *://*.bilibili.com/* -// @match *://my.mail.ru/* -// @match *://*.bitchute.com/* -// @match *://*.coursera.org/learn/* -// @match *://*.udemy.com/course/* -// @match *://*.tiktok.com/* -// @match *://proxitok.pabloferreiro.es/* -// @match *://proxitok.pussthecat.org/* -// @match *://tok.habedieeh.re/* -// @match *://proxitok.esmailelbob.xyz/* -// @match *://proxitok.privacydev.net/* -// @match *://tok.artemislena.eu/* -// @match *://tok.adminforge.de/* -// @match *://tik.hostux.net/* -// @match *://tt.vern.cc/* -// @match *://cringe.whatever.social/* -// @match *://proxitok.lunar.icu/* -// @match *://proxitok.privacy.com.de/* -// @match *://rumble.com/* -// @match *://*.eporner.com/* -// @match *://peertube.1312.media/* -// @match *://tube.shanti.cafe/* -// @match *://bee-tube.fr/* -// @match *://video.sadmin.io/* -// @match *://dalek.zone/* -// @match *://review.peertube.biz/* -// @match *://peervideo.club/* -// @match *://tube.la-dina.net/* -// @match *://peertube.tmp.rcp.tf/* -// @match *://geo.dailymotion.com/* -// @match *://trovo.live/* -// @match *://disk.yandex.ru/i/* -// @match *://coursehunter.net/* -// @connect api.browser.yandex.ru -// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-min.user.js -// @grant GM_xmlhttpRequest -// @grant GM_info -// @grant GM_setValue -// @grant GM_getValue -// @grant GM_deleteValue -// @grant GM_listValues -// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues -// @icon https://translate.yandex.ru/icons/favicon.ico -// @namespace vot-min -// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js -// @require https://cdn.jsdelivr.net/npm/hls.js@1 -// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-min.user.js +// @grant GM_addStyle +// @grant GM_deleteValue +// @grant GM_listValues +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_xmlhttpRequest +// @grant GM_info +// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js +// @require https://cdn.jsdelivr.net/npm/hls.js/dist/hls.light.min.js +// @match *://*.youtube.com/* +// @match *://*.youtube-nocookie.com/* +// @match *://*.youtubekids.com/* +// @match *://*.twitch.tv/* +// @match *://*.xvideos.com/* +// @match *://*.pornhub.com/* +// @match *://*.vk.com/* +// @match *://*.vk.ru/* +// @match *://invidious.snopyta.org/* +// @match *://invidious.kavin.rocks/* +// @match *://vid.puffyan.us/* +// @match *://invidious.namazso.eu/* +// @match *://inv.riverside.rocks/* +// @match *://yt.artemislena.eu/* +// @match *://invidious.flokinet.to/* +// @match *://invidious.esmailelbob.xyz/* +// @match *://invidious.nerdvpn.de/* +// @match *://invidious.slipfox.xyz/* +// @match *://invidio.xamh.de/* +// @match *://invidious.dhusch.de/* +// @match *://*.piped.video/* +// @match *://piped.tokhmi.xyz/* +// @match *://piped.moomoo.me/* +// @match *://piped.syncpundit.io/* +// @match *://piped.mha.fi/* +// @match *://watch.whatever.social/* +// @match *://piped.garudalinux.org/* +// @match *://efy.piped.pages.dev/* +// @match *://watch.leptons.xyz/* +// @match *://piped.lunar.icu/* +// @match *://yt.dc09.ru/* +// @match *://piped.mint.lgbt/* +// @match *://*.il.ax/* +// @match *://piped.privacy.com.de/* +// @match *://piped.esmailelbob.xyz/* +// @match *://piped.projectsegfau.lt/* +// @match *://piped.in.projectsegfau.lt/* +// @match *://piped.us.projectsegfau.lt/* +// @match *://piped.privacydev.net/* +// @match *://piped.palveluntarjoaja.eu/* +// @match *://piped.smnz.de/* +// @match *://piped.adminforge.de/* +// @match *://piped.qdi.fi/* +// @match *://piped.hostux.net/* +// @match *://piped.chauvet.pro/* +// @match *://piped.jotoma.de/* +// @match *://piped.pfcd.me/* +// @match *://piped.frontendfriendly.xyz/* +// @match *://*.yewtu.be/* +// @match *://inv.vern.cc/* +// @match *://*.vimeo.com/* +// @match *://*.9gag.com/* +// @match *://*.twitter.com/* +// @match *://*.facebook.com/* +// @match *://*.rutube.ru/* +// @match *://*.bilibili.com/* +// @match *://my.mail.ru/* +// @match *://*.bitchute.com/* +// @match *://*.coursera.org/learn/* +// @match *://*.udemy.com/course/* +// @match *://*.tiktok.com/* +// @match *://proxitok.pabloferreiro.es/* +// @match *://proxitok.pussthecat.org/* +// @match *://tok.habedieeh.re/* +// @match *://proxitok.esmailelbob.xyz/* +// @match *://proxitok.privacydev.net/* +// @match *://tok.artemislena.eu/* +// @match *://tok.adminforge.de/* +// @match *://tik.hostux.net/* +// @match *://tt.vern.cc/* +// @match *://cringe.whatever.social/* +// @match *://proxitok.lunar.icu/* +// @match *://proxitok.privacy.com.de/* +// @match *://rumble.com/* +// @match *://*.eporner.com/* +// @match *://peertube.1312.media/* +// @match *://tube.shanti.cafe/* +// @match *://bee-tube.fr/* +// @match *://video.sadmin.io/* +// @match *://dalek.zone/* +// @match *://review.peertube.biz/* +// @match *://peervideo.club/* +// @match *://tube.la-dina.net/* +// @match *://peertube.tmp.rcp.tf/* +// @match *://geo.dailymotion.com/* +// @match *://*.ok.ru/* +// @match *://trovo.live/* +// @match *://disk.yandex.ru/i/* +// @match *://coursehunter.net/* +// @match *://youtube.googleapis.com/embed/* +// @match *://*.banned.video/* +// @match *://*.weverse.io/* +// @match *://*.newgrounds.com/* +// @match *://*.egghead.io/* +// @match *://*.youku.com/* +// @connect api.browser.yandex.ru +// @namespace vot-min +// @version 1.5.1 +// @icon https://translate.yandex.ru/icons/favicon.ico +// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD +// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues +// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-min.user.js +// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot-min.user.js +// @supportURL https://github.com/ilyhalight/voice-over-translation/issues // ==/UserScript== -/*! For license information please see vot-min.js.LICENSE.txt */ -(()=>{var t={"./node_modules/bowser/es5.js":function(t){t.exports=function(t){var e={};function o(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,o),i.l=!0,i.exports}return o.m=t,o.c=e,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)o.d(n,i,function(e){return t[e]}.bind(null,i));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=90)}({17:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n=o(18),i=function(){function t(){}return t.getFirstMatch=function(t,e){var o=e.match(t);return o&&o.length>0&&o[1]||""},t.getSecondMatch=function(t,e){var o=e.match(t);return o&&o.length>1&&o[2]||""},t.matchAndReturnConst=function(t,e,o){if(t.test(e))return o},t.getWindowsVersionName=function(t){switch(t){case"NT":return"NT";case"XP":case"NT 5.1":return"XP";case"NT 5.0":return"2000";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return}},t.getMacOSVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),10===e[0])switch(e[1]){case 5:return"Leopard";case 6:return"Snow Leopard";case 7:return"Lion";case 8:return"Mountain Lion";case 9:return"Mavericks";case 10:return"Yosemite";case 11:return"El Capitan";case 12:return"Sierra";case 13:return"High Sierra";case 14:return"Mojave";case 15:return"Catalina";default:return}},t.getAndroidVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),!(1===e[0]&&e[1]<5))return 1===e[0]&&e[1]<6?"Cupcake":1===e[0]&&e[1]>=6?"Donut":2===e[0]&&e[1]<2?"Eclair":2===e[0]&&2===e[1]?"Froyo":2===e[0]&&e[1]>2?"Gingerbread":3===e[0]?"Honeycomb":4===e[0]&&e[1]<1?"Ice Cream Sandwich":4===e[0]&&e[1]<4?"Jelly Bean":4===e[0]&&e[1]>=4?"KitKat":5===e[0]?"Lollipop":6===e[0]?"Marshmallow":7===e[0]?"Nougat":8===e[0]?"Oreo":9===e[0]?"Pie":void 0},t.getVersionPrecision=function(t){return t.split(".").length},t.compareVersions=function(e,o,n){void 0===n&&(n=!1);var i=t.getVersionPrecision(e),a=t.getVersionPrecision(o),r=Math.max(i,a),s=0,l=t.map([e,o],(function(e){var o=r-t.getVersionPrecision(e),n=e+new Array(o+1).join(".0");return t.map(n.split("."),(function(t){return new Array(20-t.length).join("0")+t})).reverse()}));for(n&&(s=r-Math.min(i,a)),r-=1;r>=s;){if(l[0][r]>l[1][r])return 1;if(l[0][r]===l[1][r]){if(r===s)return 0;r-=1}else if(l[0][r]1?i-1:0),r=1;r0){var r=Object.keys(o),l=s.default.find(r,(function(t){return e.isOS(t)}));if(l){var d=this.satisfies(o[l]);if(void 0!==d)return d}var c=s.default.find(r,(function(t){return e.isPlatform(t)}));if(c){var u=this.satisfies(o[c]);if(void 0!==u)return u}}if(a>0){var h=Object.keys(i),p=s.default.find(h,(function(t){return e.isBrowser(t,!0)}));if(void 0!==p)return this.compareVersion(i[p])}},e.isBrowser=function(t,e){void 0===e&&(e=!1);var o=this.getBrowserName().toLowerCase(),n=t.toLowerCase(),i=s.default.getBrowserTypeByAlias(n);return e&&i&&(n=i.toLowerCase()),n===o},e.compareVersion=function(t){var e=[0],o=t,n=!1,i=this.getBrowserVersion();if("string"==typeof i)return">"===t[0]||"<"===t[0]?(o=t.substr(1),"="===t[1]?(n=!0,o=t.substr(2)):e=[],">"===t[0]?e.push(1):e.push(-1)):"="===t[0]?o=t.substr(1):"~"===t[0]&&(n=!0,o=t.substr(1)),e.indexOf(s.default.compareVersions(i,o,n))>-1},e.isOS=function(t){return this.getOSName(!0)===String(t).toLowerCase()},e.isPlatform=function(t){return this.getPlatformType(!0)===String(t).toLowerCase()},e.isEngine=function(t){return this.getEngineName(!0)===String(t).toLowerCase()},e.is=function(t,e){return void 0===e&&(e=!1),this.isBrowser(t,e)||this.isOS(t)||this.isPlatform(t)},e.some=function(t){var e=this;return void 0===t&&(t=[]),t.some((function(t){return e.is(t)}))},t}();e.default=d,t.exports=e.default},92:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=/version\/(\d+(\.?_?\d+)+)/i,r=[{test:[/googlebot/i],describe:function(t){var e={name:"Googlebot"},o=i.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/opera/i],describe:function(t){var e={name:"Opera"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opr\/|opios/i],describe:function(t){var e={name:"Opera"},o=i.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/SamsungBrowser/i],describe:function(t){var e={name:"Samsung Internet for Android"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Whale/i],describe:function(t){var e={name:"NAVER Whale Browser"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MZBrowser/i],describe:function(t){var e={name:"MZ Browser"},o=i.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/focus/i],describe:function(t){var e={name:"Focus"},o=i.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/swing/i],describe:function(t){var e={name:"Swing"},o=i.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/coast/i],describe:function(t){var e={name:"Opera Coast"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(t){var e={name:"Opera Touch"},o=i.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/yabrowser/i],describe:function(t){var e={name:"Yandex Browser"},o=i.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/ucbrowser/i],describe:function(t){var e={name:"UC Browser"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Maxthon|mxios/i],describe:function(t){var e={name:"Maxthon"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/epiphany/i],describe:function(t){var e={name:"Epiphany"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/puffin/i],describe:function(t){var e={name:"Puffin"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sleipnir/i],describe:function(t){var e={name:"Sleipnir"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/k-meleon/i],describe:function(t){var e={name:"K-Meleon"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/micromessenger/i],describe:function(t){var e={name:"WeChat"},o=i.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/qqbrowser/i],describe:function(t){var e={name:/qqbrowserlite/i.test(t)?"QQ Browser Lite":"QQ Browser"},o=i.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/msie|trident/i],describe:function(t){var e={name:"Internet Explorer"},o=i.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/\sedg\//i],describe:function(t){var e={name:"Microsoft Edge"},o=i.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/edg([ea]|ios)/i],describe:function(t){var e={name:"Microsoft Edge"},o=i.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/vivaldi/i],describe:function(t){var e={name:"Vivaldi"},o=i.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/seamonkey/i],describe:function(t){var e={name:"SeaMonkey"},o=i.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sailfish/i],describe:function(t){var e={name:"Sailfish"},o=i.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,t);return o&&(e.version=o),e}},{test:[/silk/i],describe:function(t){var e={name:"Amazon Silk"},o=i.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/phantom/i],describe:function(t){var e={name:"PhantomJS"},o=i.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/slimerjs/i],describe:function(t){var e={name:"SlimerJS"},o=i.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e={name:"BlackBerry"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e={name:"WebOS Browser"},o=i.default.getFirstMatch(a,t)||i.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/bada/i],describe:function(t){var e={name:"Bada"},o=i.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/tizen/i],describe:function(t){var e={name:"Tizen"},o=i.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/qupzilla/i],describe:function(t){var e={name:"QupZilla"},o=i.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/firefox|iceweasel|fxios/i],describe:function(t){var e={name:"Firefox"},o=i.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/electron/i],describe:function(t){var e={name:"Electron"},o=i.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MiuiBrowser/i],describe:function(t){var e={name:"Miui"},o=i.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/chromium/i],describe:function(t){var e={name:"Chromium"},o=i.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,t)||i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/chrome|crios|crmo/i],describe:function(t){var e={name:"Chrome"},o=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/GSA/i],describe:function(t){var e={name:"Google Search"},o=i.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e={name:"Android Browser"},o=i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/playstation 4/i],describe:function(t){var e={name:"PlayStation 4"},o=i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/safari|applewebkit/i],describe:function(t){var e={name:"Safari"},o=i.default.getFirstMatch(a,t);return o&&(e.version=o),e}},{test:[/.*/i],describe:function(t){var e=-1!==t.search("\\(")?/^(.*)\/(.*)[ \t]\((.*)/:/^(.*)\/(.*) /;return{name:i.default.getFirstMatch(e,t),version:i.default.getSecondMatch(e,t)}}}];e.default=r,t.exports=e.default},93:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=o(18),r=[{test:[/Roku\/DVP/],describe:function(t){var e=i.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,t);return{name:a.OS_MAP.Roku,version:e}}},{test:[/windows phone/i],describe:function(t){var e=i.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.WindowsPhone,version:e}}},{test:[/windows /i],describe:function(t){var e=i.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,t),o=i.default.getWindowsVersionName(e);return{name:a.OS_MAP.Windows,version:e,versionName:o}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(t){var e={name:a.OS_MAP.iOS},o=i.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,t);return o&&(e.version=o),e}},{test:[/macintosh/i],describe:function(t){var e=i.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,t).replace(/[_\s]/g,"."),o=i.default.getMacOSVersionName(e),n={name:a.OS_MAP.MacOS,version:e};return o&&(n.versionName=o),n}},{test:[/(ipod|iphone|ipad)/i],describe:function(t){var e=i.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,t).replace(/[_\s]/g,".");return{name:a.OS_MAP.iOS,version:e}}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e=i.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,t),o=i.default.getAndroidVersionName(e),n={name:a.OS_MAP.Android,version:e};return o&&(n.versionName=o),n}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e=i.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,t),o={name:a.OS_MAP.WebOS};return e&&e.length&&(o.version=e),o}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e=i.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,t)||i.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,t)||i.default.getFirstMatch(/\bbb(\d+)/i,t);return{name:a.OS_MAP.BlackBerry,version:e}}},{test:[/bada/i],describe:function(t){var e=i.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.Bada,version:e}}},{test:[/tizen/i],describe:function(t){var e=i.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.Tizen,version:e}}},{test:[/linux/i],describe:function(){return{name:a.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:a.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(t){var e=i.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,t);return{name:a.OS_MAP.PlayStation4,version:e}}}];e.default=r,t.exports=e.default},94:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=o(18),r=[{test:[/googlebot/i],describe:function(){return{type:"bot",vendor:"Google"}}},{test:[/huawei/i],describe:function(t){var e=i.default.getFirstMatch(/(can-l01)/i,t)&&"Nova",o={type:a.PLATFORMS_MAP.mobile,vendor:"Huawei"};return e&&(o.model=e),o}},{test:[/nexus\s*(?:7|8|9|10).*/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Nexus"}}},{test:[/ipad/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/kftt build/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Amazon",model:"Kindle Fire HD 7"}}},{test:[/silk/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet,vendor:"Amazon"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:a.PLATFORMS_MAP.tablet}}},{test:function(t){var e=t.test(/ipod|iphone/i),o=t.test(/like (ipod|iphone)/i);return e&&!o},describe:function(t){var e=i.default.getFirstMatch(/(ipod|iphone)/i,t);return{type:a.PLATFORMS_MAP.mobile,vendor:"Apple",model:e}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:"Nexus"}}},{test:[/[^-]mobi/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(t){return"blackberry"===t.getBrowserName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:"BlackBerry"}}},{test:function(t){return"bada"===t.getBrowserName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(t){return"windows phone"===t.getBrowserName()},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:"Microsoft"}}},{test:function(t){var e=Number(String(t.getOSVersion()).split(".")[0]);return"android"===t.getOSName(!0)&&e>=3},describe:function(){return{type:a.PLATFORMS_MAP.tablet}}},{test:function(t){return"android"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(t){return"macos"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.desktop,vendor:"Apple"}}},{test:function(t){return"windows"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(t){return"linux"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(t){return"playstation 4"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:function(t){return"roku"===t.getOSName(!0)},describe:function(){return{type:a.PLATFORMS_MAP.tv}}}];e.default=r,t.exports=e.default},95:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,i=(n=o(17))&&n.__esModule?n:{default:n},a=o(18),r=[{test:function(t){return"microsoft edge"===t.getBrowserName(!0)},describe:function(t){if(/\sedg\//i.test(t))return{name:a.ENGINE_MAP.Blink};var e=i.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,t);return{name:a.ENGINE_MAP.EdgeHTML,version:e}}},{test:[/trident/i],describe:function(t){var e={name:a.ENGINE_MAP.Trident},o=i.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){return t.test(/presto/i)},describe:function(t){var e={name:a.ENGINE_MAP.Presto},o=i.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=t.test(/gecko/i),o=t.test(/like gecko/i);return e&&!o},describe:function(t){var e={name:a.ENGINE_MAP.Gecko},o=i.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:a.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(t){var e={name:a.ENGINE_MAP.WebKit},o=i.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}}];e.default=r,t.exports=e.default}})},"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss":(t,e,o)=>{"use strict";o.d(e,{Z:()=>s});var n=o("./node_modules/css-loader/dist/runtime/noSourceMaps.js"),i=o.n(n),a=o("./node_modules/css-loader/dist/runtime/api.js"),r=o.n(a)()(i());r.push([t.id,'.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}',""]);const s=r},"./node_modules/css-loader/dist/runtime/api.js":t=>{"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var o="",n=void 0!==e[5];return e[4]&&(o+="@supports (".concat(e[4],") {")),e[2]&&(o+="@media ".concat(e[2]," {")),n&&(o+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),o+=t(e),n&&(o+="}"),e[2]&&(o+="}"),e[4]&&(o+="}"),o})).join("")},e.i=function(t,o,n,i,a){"string"==typeof t&&(t=[[null,t,void 0]]);var r={};if(n)for(var s=0;s0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=a),o&&(c[2]?(c[1]="@media ".concat(c[2]," {").concat(c[1],"}"),c[2]=o):c[2]=o),i&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=i):c[4]="".concat(i)),e.push(c))}},e}},"./node_modules/css-loader/dist/runtime/noSourceMaps.js":t=>{"use strict";t.exports=function(t){return t[1]}},"./node_modules/requestidlecallback-polyfill/index.js":()=>{window.requestIdleCallback=window.requestIdleCallback||function(t){var e=Date.now();return setTimeout((function(){t({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-e))}})}),1)},window.cancelIdleCallback=window.cancelIdleCallback||function(t){clearTimeout(t)}},"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":t=>{"use strict";var e=[];function o(t){for(var o=-1,n=0;n{"use strict";var e={};t.exports=function(t,o){var n=function(t){if(void 0===e[t]){var o=document.querySelector(t);if(window.HTMLIFrameElement&&o instanceof window.HTMLIFrameElement)try{o=o.contentDocument.head}catch(t){o=null}e[t]=o}return e[t]}(t);if(!n)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");n.appendChild(o)}},"./node_modules/style-loader/dist/runtime/insertStyleElement.js":t=>{"use strict";t.exports=function(t){var e=document.createElement("style");return t.setAttributes(e,t.attributes),t.insert(e,t.options),e}},"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js":(t,e,o)=>{"use strict";t.exports=function(t){var e=o.nc;e&&t.setAttribute("nonce",e)}},"./node_modules/style-loader/dist/runtime/styleDomAPI.js":t=>{"use strict";t.exports=function(t){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=t.insertStyleElement(t);return{update:function(o){!function(t,e,o){var n="";o.supports&&(n+="@supports (".concat(o.supports,") {")),o.media&&(n+="@media ".concat(o.media," {"));var i=void 0!==o.layer;i&&(n+="@layer".concat(o.layer.length>0?" ".concat(o.layer):""," {")),n+=o.css,i&&(n+="}"),o.media&&(n+="}"),o.supports&&(n+="}");var a=o.sourceMap;a&&"undefined"!=typeof btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),e.styleTagTransform(n,t,e.options)}(e,t,o)},remove:function(){!function(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t)}(e)}}}},"./node_modules/style-loader/dist/runtime/styleTagTransform.js":t=>{"use strict";t.exports=function(t,e){if(e.styleSheet)e.styleSheet.cssText=t;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(t))}}},"./src/config/config.js":(t,e,o)=>{"use strict";o.d(e,{EY:()=>u,I1:()=>s,Rr:()=>l,e6:()=>a,ez:()=>r,iF:()=>i,jm:()=>h,kF:()=>c,rm:()=>p,sN:()=>d});var n=o("./src/utils/utils.js");const i="api.browser.yandex.ru",a="m3u8proxy.toil-dump.workers.dev",r="uk"===n.KQ?"vot-new.toil-dump.workers.dev":"vot-worker.onrender.com",s="xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm",l="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36",d=.15,c="yandex",u="yandex",h={yandex:"https://translate.toil.cc/detect",rustServer:"https://rust-server-531j.onrender.com/detect"},p={yandex:"https://translate.toil.cc/translate"}},"./src/localization/localizationProvider.js":(t,e,o)=>{"use strict";o.d(e,{Z:()=>r,V:()=>s});const n=JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}');var i=o("./src/utils/debug.js"),a=o("./src/utils/storage.js");const r=["auto","en","ru","af","am","ar","az","bg","bn","bs","ca","cs","cy","da","de","el","es","et","eu","fa","fi","fr","gl","hi","hr","hu","hy","id","it","ja","jv","kk","km","kn","ko","lo","mk","ml","mn","ms","mt","my","ne","nl","pa","pl","pt","ro","si","sk","sl","sq","sr","su","sv","sw","tr","uk","ur","uz","vi","zh","zu"],s=new class{lang="en";locale={};gmValues=["locale-phrases","locale-lang","locale-version","locale-lang-override"];constructor(){const t=a.i.syncGet("locale-lang-override","auto");this.lang=t&&"auto"!==t?t:(navigator.language||navigator.userLanguage)?.substr(0,2)?.toLowerCase()??"en",this.setLocaleFromJsonString(a.i.syncGet("locale-phrases",""))}reset(){this.gmValues.forEach((t=>a.i.syncDelete(t)))}async update(t=!1){(t||2!==await a.i.get("locale-version",0,!0)||await a.i.get("locale-lang")!==this.lang)&&(i.Z.log("Updating locale..."),await fetch(`https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/src/localization/locales/${this.lang}.json`).then((t=>{if(200===t.status)return t.text();throw t.status})).then((async t=>{await a.i.set("locale-phrases",t),this.setLocaleFromJsonString(t);const e=this.getFromLocale(this.locale,"__version__");"number"==typeof e&&await a.i.set("locale-version",e),await a.i.set("locale-lang",this.lang)})).catch((async t=>{console.error("[VOT] [localizationProvider] failed get locale, cause:",t),this.setLocaleFromJsonString(await a.i.get("locale-phrases",""))})))}setLocaleFromJsonString(t){try{this.locale=JSON.parse(t)??{}}catch(t){console.error("[VOT] [localizationProvider]",t),this.locale={}}}getFromLocale(t,e){const o=e.split(".").reduce(((t,e)=>{if("object"==typeof t&&t)return t[e]}),t);return void 0===o&&console.warn("[VOT] [localizationProvider] locale",t,"doesn't contain key",e),o}getDefault(t){return this.getFromLocale(n,t)??t}get(t){return this.getFromLocale(this.locale,t)??this.getFromLocale(n,t)??t}}},"./src/utils/debug.js":(t,e,o)=>{"use strict";o.d(e,{Z:()=>n});const n={log:(...t)=>{}}},"./src/utils/storage.js":(t,e,o)=>{"use strict";o.d(e,{i:()=>i});var n=o("./src/utils/debug.js");const i=new class{constructor(){this.gmSupport="function"==typeof GM_getValue,n.Z.log(`GM Storage Status: ${this.gmSupport}`)}syncGet(t,e=void 0,o=!1){if(this.gmSupport)return GM_getValue(t,e);let n=window.localStorage.getItem(t);if("udemyData"===t&&"string"==typeof n)try{n=JSON.parse(n)}catch{n=e}return o?Number(n)??Number(e):n??e}async get(t,e=void 0,o=!1){return this.gmSupport?await GM_getValue(t,e):new Promise((n=>{n(this.syncGet(t,e,o))}))}syncSet(t,e){return this.gmSupport?GM_setValue(t,e):("udemyData"===t&&(e=JSON.stringify(e)),window.localStorage.setItem(t,e))}async set(t,e){return this.gmSupport?await GM_setValue(t,e):new Promise((o=>{o(this.syncSet(t,e))}))}syncDelete(t){return this.gmSupport?GM_deleteValue(t):window.localStorage.removeItem(t)}async delete(t){return this.gmSupport?await GM_deleteValue(t):new Promise((e=>{e(this.syncDelete(t))}))}syncList(){return this.gmSupport?GM_listValues():["autoTranslate","dontTranslateLanguage","dontTranslateYourLang","autoSetVolumeYandexStyle","showVideoSlider","syncVolume","subtitlesMaxLength","highlightWords","responseLanguage","defaultVolume","udemyData","audioProxy","showPiPButton","locale-version","locale-lang","locale-phrases"]}async list(){return this.gmSupport?await GM_listValues():new Promise((t=>{t(this.syncList())}))}}},"./src/utils/utils.js":(t,e,o)=>{"use strict";o.d(e,{KQ:()=>a,PG:()=>l,QZ:()=>u,_v:()=>r,eL:()=>d,gJ:()=>s,qq:()=>c});var n=o("./src/localization/localizationProvider.js");const i=navigator.language||navigator.userLanguage,a=i?.substr(0,2)?.toLowerCase()??"en";String.prototype.format||(String.prototype.format=function(){var t=arguments;return this.replace(/{(\d+)}/g,(function(e,o){return void 0!==t[o]?t[o]:e}))});const r=t=>new Promise((e=>setTimeout(e,t))),s=(t,e)=>{const o=new URL(window.location.href);switch(t){case"piped":case"invidious":case"youtube":return o.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1]||o.searchParams.get("v");case"vk":return o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)?o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1):o.searchParams.get("z")?o.searchParams.get("z").split("/")[0]:!(!o.searchParams.get("oid")||!o.searchParams.get("id"))&&`video-${Math.abs(o.searchParams.get("oid"))}_${o.searchParams.get("id")}`;case"nine_gag":case"9gag":case"gag":return o.pathname.match(/gag\/([^/]+)/)?.[1];case"twitch":if(/^m\.twitch\.tv$/.test(window.location.hostname)){const t=document.head.querySelector('link[rel="canonical"]');return t?.href.match(/videos\/([^/]+)/)?.[0]||o.pathname.slice(1)}if(/^player\.twitch\.tv$/.test(window.location.hostname))return`videos/${o.searchParams.get("video")}`;if(/^clips\.twitch\.tv$/.test(window.location.hostname)){const t=document.querySelector(".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']");return!!t&&`${t.href.replace("https://www.twitch.tv/","")}/clip/${o.searchParams.get("clip")}`}return o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)?o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]:o.pathname.match(/(?:videos)\/([^/]+)/)?.[0];case"proxytok":return o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];case"tiktok":{let t=o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];if(!t){const o=e.closest(".xgplayer-playing, .tiktok-web-player"),n=o?.closest('div[data-e2e="recommend-list-item-container"]'),i=n?.querySelector('a[data-e2e="video-author-avatar"]');if(o&&i){const e=o.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1),n=i.href?.match(/.*(@.*)$/)?.at(1);e&&n&&(t=`${n}/video/${e}`)}}return t}case"vimeo":return o.pathname.match(/[^/]+\/[^/]+$/)?.[0]||o.pathname.match(/[^/]+$/)?.[0];case"xvideos":return o.pathname.match(/[^/]+\/[^/]+$/)?.[0];case"pornhub":return o.searchParams.get("viewkey")||o.pathname.match(/embed\/([^/]+)/)?.[1];case"twitter":return o.pathname.match(/status\/([^/]+)/)?.[1];case"udemy":case"rumble":return o.pathname;case"facebook":return!!o.searchParams.get("v")&&o.searchParams.get("v");case"rutube":return o.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1];case"coub":return o.pathname.includes("/view")?o.pathname.match(/view\/([^/]+)/)?.[1]:o.pathname.includes("/embed")?o.pathname.match(/embed\/([^/]+)/)?.[1]:document.querySelector(".coub.active")?.dataset?.permalink;case"bilibili":{const t=o.searchParams.get("bvid");if(t)return t;{let t=o.pathname.match(/video\/([^/]+)/)?.[1];return t&&o.search&&null!==o.searchParams.get("p")&&(t+=`/?p=${o.searchParams.get("p")}`),t}}case"mail_ru":if(o.pathname.startsWith("/v/")||o.pathname.startsWith("/mail/"))return o.pathname;if(o.pathname.match(/video\/embed\/([^/]+)/)){const t=document.querySelector(".b-video-controls__mymail-link");return!!t&&t?.href.split("my.mail.ru")?.[1]}return!1;case"bitchute":return o.pathname.match(/video\/([^/]+)/)?.[1];case"coursera":return o.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0];case"eporner":return o.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0];case"peertube":return o.pathname.match(/\/w\/([^/]+)/)?.[0];case"dailymotion":{const t=Array.from(document.scripts).filter((t=>t.innerText.trim().includes("window.__PLAYER_CONFIG__ = {")));if(!t.length)return!1;try{let e=t[0].innerText.trim().replace("window.__PLAYER_CONFIG__ = ","");e.endsWith("};")&&(e=e.substring(0,e.length-1));const o=JSON.parse(e),n=o.context.embedder??o.context.http_referer;return console.log(n,o),n.match(/\/video\/([^/]+)/)?.[1]}catch(t){return console.error("[VOT]",t),!1}}case"trovo":{if(!o.pathname.startsWith("/s/"))return!1;const t=o.searchParams.get("vid");if(!t)return!1;const e=o.pathname.match(/([^/]+)\/([\d]+)/)?.[0];return!!e&&`${e}?vid=${t}`}case"yandexdisk":return o.pathname.match(/\/[i|s|d]\/([^/]+)/)?.[1];case"coursehunter":{const t=o.pathname.match(/\/course\/([^/]+)/)?.[1];return!!t&&t+o.search}default:return!1}};function l(t){const e=Math.floor(t/60),o=Math.floor(t%60);return e>=60?n.V.get("translationTakeMoreThanHour"):e>=10&&e%10?n.V.get("translationTakeApproximatelyMinutes").format(e):1==e||0==e&&o>0?n.V.get("translationTakeAboutMinute"):n.V.get("translationTakeApproximatelyMinute").format(e)}function d(t){return t.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]}function c(){return"pictureInPictureEnabled"in document&&document.pictureInPictureEnabled}function u(){return"undefined"!=typeof Hls&&Hls?.isSupported()?new Hls({debug:!1,lowLatencyMode:!0,backBufferLength:90}):void 0}},"./src/yandexRequest.js":(t,e,o)=>{"use strict";o.r(e),o.d(e,{default:()=>a});var n=o("./src/config/config.js"),i=o("./src/utils/debug.js");const a=async function(t,e,o,a){try{i.Z.log("yandexRequest:",t);const r={url:`https://${n.iF}${t}`,method:"POST",headers:{Accept:"application/x-protobuf","Accept-Language":"en","Content-Type":"application/x-protobuf","User-Agent":n.Rr,Pragma:"no-cache","Cache-Control":"no-cache","Sec-Fetch-Mode":"no-cors","sec-ch-ua":null,"sec-ch-ua-mobile":null,"sec-ch-ua-platform":null,...o},binary:!0,data:new Blob([e]),responseType:"arraybuffer"};GM_xmlhttpRequest({...r,onload:t=>{i.Z.log("yandexRequest:",t.status,t),a(200===t.status,t.response)},onerror:t=>{console.error("[VOT]",t),a(!1)}})}catch(t){console.error("[VOT]",t),a(!1)}}}},e={};function o(n){var i=e[n];if(void 0!==i)return i.exports;var a=e[n]={id:n,exports:{}};return t[n].call(a.exports,a,a.exports,o),a.exports}o.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return o.d(e,{a:e}),e},o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.nc=void 0,(()=>{"use strict";var t=o("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"),e=o.n(t),n=o("./node_modules/style-loader/dist/runtime/styleDomAPI.js"),i=o.n(n),a=o("./node_modules/style-loader/dist/runtime/insertBySelector.js"),r=o.n(a),s=o("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"),l=o.n(s),d=o("./node_modules/style-loader/dist/runtime/insertStyleElement.js"),c=o.n(d),u=o("./node_modules/style-loader/dist/runtime/styleTagTransform.js"),h=o.n(u),p=o("./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss"),g={};g.styleTagTransform=h(),g.setAttributes=l(),g.insert=r().bind(null,"head"),g.domAPI=i(),g.insertStyleElement=c(),e()(p.Z,g),p.Z&&p.Z.locals&&p.Z.locals;var v=o("./src/localization/localizationProvider.js");class m extends Error{constructor(t){super(v.V.getDefault(t)),this.name="VOTLocalizedError",this.unlocalizedMessage=t,this.localizedMessage=v.V.get(t)}}var b=o("./src/utils/debug.js");const f=["ru","en","zh","ko","lt","lv","ar","fr","it","es","de","ja"],y=["kk","bn","pt","cs","hi","mr","te","tr","ms","vi","ta","jv","ur","fa","gu","id","uk","da","fi","uz","pl","sv","az","sq","am","hy","af","eu","my","bg","bs","cy","hu","gl","el","zu","kn","ca","km","lo","mk","ml","mt","mn","ne","nl","pa","ro","sr","si","sk","sl","sw","su","hr","et"],w=["ru","en","kk"],x=["Violentmonkey","FireMonkey","Greasemonkey","AdGuard","OrangeMonkey"];var S=o("./src/utils/utils.js"),k=o("./src/config/config.js"),T=o("./src/utils/storage.js");async function V(t,e){const o=new AbortController,n=setTimeout((()=>o.abort()),3e3);try{return await fetch(t,{...e,signal:o.signal})}catch(t){return console.error("Fetch timed-out. Error:",t),t}finally{clearTimeout(n)}}const M={async translate(t,e){try{const o=await V(k.rm.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.text[0]}catch(e){return console.error("Error translating text:",e),t}},async detect(t,e){try{const o=await V(k.jm.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.lang??"en"}catch(t){return console.error("Error translating text:",t),"en"}}},L={async detect(t){try{const e=await fetch(k.jm.rustServer,{method:"POST",body:t});if(e instanceof Error)throw e;return await e.text()}catch(t){return console.error("Error getting lang from text:",t),"en"}}};async function O(t,e="",o="ru"){if("yandex"===await T.i.get("translationService",k.kF)){const n=e&&o?`${e}-${o}`:o;return await M.translate(t,n)}return t}const P=["yandex"],E=["yandex","rust-server"];function C(){return/^m\.youtube\.com$/.test(window.location.hostname)}function A(){return window.location.pathname.startsWith("/shorts/")?C()?document.querySelector("#movie_player"):document.querySelector("#shorts-player"):document.querySelector("#movie_player")}function B(){const t=A();return t?.getPlayerResponse?t?.getPlayerResponse?.call()??null:t?.data?.playerResponse??null}function _(){const t=A();return t?.getVideoData?t?.getVideoData?.call()??null:t?.data?.playerResponse?.videoDetails??null}const F=function(){const t=A();return t?.getVolume?t.getVolume.call()/100:1},q=function(){const t=B();let e=t?.captions?.playerCaptionsTracklistRenderer?.captionTracks??[];return e=e.reduce(((t,e)=>{if("languageCode"in e){const o=e?.languageCode?(0,S.eL)(e?.languageCode):void 0,n=e?.url||e?.baseUrl;o&&n&&t.push({source:"youtube",language:o,isAutoGenerated:"asr"===e?.kind,url:`${n.startsWith("http")?n:`${window.location.origin}/${n}`}&fmt=json3`})}return t}),[]),b.Z.log("youtube subtitles:",e),e},R=async function(){const t=A(),e=B(),o=_(),{author:n,title:i}=o??{},{shortDescription:a,isLive:r,isLiveContent:s,isUpcoming:l}=e?.videoDetails??{},d=!(!r&&!l||s);let c=await async function(t,e,o,n){if(!window.location.hostname.includes("m.youtube.com")&&t?.getAudioTrack){const e=t.getAudioTrack(),o=e?.getLanguageInfo();if("und"!==o?.id)return(0,S.eL)(o.id.split(".")[0])}const i=e?.captions?.playerCaptionsTracklistRenderer?.captionTracks;if(i?.length){const t=i.find((t=>"asr"===t.kind));if(t&&t.languageCode)return(0,S.eL)(t.languageCode)}if(!n||!o)return"en";const a=[/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g,/Auto-generated by YouTube/g,/Provided to YouTube by/g,/Released on/g,/Bitcoin/g,/USDT/g,/Paypal/g],r=[n.split("\n\n").filter((t=>!a.some((e=>e.test(t))))).join("\n\n").replace(/[^\p{L}\s]/gu," ").trim().replace(/\s+/g," ").slice(0,250),o].join(" ");return await async function(t){switch(await T.i.get("detectService",k.EY)){case"yandex":return await M.detect(t);case"rust-server":return await L.detect(t);default:return"en"}}(r)}(t,e,i,a);f.includes(c)||(c="en");const u={isLive:!!r,isPremiere:d,title:i,description:a,author:n,detectedLanguage:c};return b.Z.log("youtube video data:",u),console.log("[VOT] Detected language: ",u.detectedLanguage),u},z=function(t){const e=A();if(e?.setVolume)return e.setVolume(Math.round(100*t)),!0},D=function(t,e){b.Z.log("videoSeek",e);const o=(A()?.getProgressState()?.seekableEnd||t.currentTime)-e;t.currentTime=o},I=new protobuf.Type("VideoTranslationHelpObject").add(new protobuf.Field("target",1,"string")).add(new protobuf.Field("targetUrl",2,"string")),j=new protobuf.Type("VideoTranslationRequest").add(new protobuf.Field("url",3,"string")).add(new protobuf.Field("deviceId",4,"string")).add(new protobuf.Field("firstRequest",5,"bool")).add(new protobuf.Field("duration",6,"double")).add(new protobuf.Field("unknown2",7,"int32")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("unknown3",9,"int32")).add(new protobuf.Field("unknown4",10,"int32")).add(new protobuf.Field("translationHelp",11,"VideoTranslationHelpObject","repeated")).add(new protobuf.Field("responseLanguage",14,"string")).add(new protobuf.Field("unknown5",15,"int32")).add(new protobuf.Field("unknown6",16,"int32")).add(new protobuf.Field("unknown7",17,"int32")),N=new protobuf.Type("VideoSubtitlesRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")),H=new protobuf.Type("VideoStreamRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")).add(new protobuf.Field("responseLanguage",3,"string")),$=new protobuf.Type("VideoStreamPingRequest").add(new protobuf.Field("pingId",1,"int32")),Z=new protobuf.Type("VideoTranslationResponse").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("duration",2,"double")).add(new protobuf.Field("status",4,"int32")).add(new protobuf.Field("remainingTime",5,"int32")).add(new protobuf.Field("unknown0",6,"int32")).add(new protobuf.Field("unknown1",7,"string")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("message",9,"string")),U=new protobuf.Type("VideoSubtitlesObject").add(new protobuf.Field("language",1,"string")).add(new protobuf.Field("url",2,"string")).add(new protobuf.Field("unknown2",3,"int32")).add(new protobuf.Field("translatedLanguage",4,"string")).add(new protobuf.Field("translatedUrl",5,"string")).add(new protobuf.Field("unknown5",6,"int32")).add(new protobuf.Field("unknown6",7,"int32")),W=new protobuf.Type("VideoSubtitlesResponse").add(new protobuf.Field("unknown0",1,"int32")).add(new protobuf.Field("subtitles",2,"VideoSubtitlesObject","repeated")),G=new protobuf.Type("VideoStreamObject").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("timestamp",2,"int64")),Y=new protobuf.Type("VideoStreamResponse").add(new protobuf.Field("interval",1,"int32")).add(new protobuf.Field("translatedInfo",2,"VideoStreamObject")).add(new protobuf.Field("pingId",3,"int32")),K=(new protobuf.Root).define("yandex").add(I).add(j).add(Z).add(N).add(U).add(W).add($).add(H).add(G).add(Y),Q=(t,e,o,n,i)=>K.VideoTranslationRequest.encode({url:t,firstRequest:!0,duration:e,unknown2:1,language:o,unknown3:0,unknown4:0,translationHelp:i,responseLanguage:n,unknown5:0,unknown6:1,unknown7:0}).finish(),J=t=>K.VideoTranslationResponse.decode(new Uint8Array(t)),X=(t,e)=>K.VideoSubtitlesRequest.encode({url:t,language:e}).finish(),tt=t=>K.VideoSubtitlesResponse.decode(new Uint8Array(t)),et=t=>K.VideoStreamPingRequest.encode({pingId:t}).finish(),ot=(t,e,o)=>K.VideoStreamRequest.encode({url:t,language:e,responseLanguage:o}).finish(),nt=t=>K.VideoStreamResponse.decode(new Uint8Array(t)),it=["invidious.snopyta.org","yewtu.be","invidious.kavin.rocks","vid.puffyan.us","invidious.namazso.eu","inv.riverside.rocks","yt.artemislena.eu","invidious.flokinet.to","invidious.esmailelbob.xyz","y.com.sb","invidious.nerdvpn.de","inv.vern.cc","invidious.slipfox.xyz","invidio.xamh.de","invidious.dhusch.de"],at=["piped.video","piped.tokhmi.xyz","piped.moomoo.me","piped.syncpundit.io","piped.mha.fi","watch.whatever.social","piped.garudalinux.org","efy.piped.pages.dev","watch.leptons.xyz","piped.lunar.icu","yt.dc09.ru","piped.mint.lgbt","il.ax","piped.privacy.com.de","piped.esmailelbob.xyz","piped.projectsegfau.lt","piped.in.projectsegfau.lt","piped.us.projectsegfau.lt","piped.privacydev.net","piped.palveluntarjoaja.eu","piped.smnz.de","piped.adminforge.de","piped.qdi.fi","piped.hostux.net","piped.chauvet.pro","piped.jotoma.de","piped.pfcd.me","piped.frontendfriendly.xyz"];function rt(t){const e=document.createElement("vot-block");return e.classList.add("vot-icon-button"),e.innerHTML=t,e}function st(t){const e=parseFloat(t.value),o=""===t.min?0:parseFloat(t.min),n=(e-o)/((""===t.max?100:parseFloat(t.max))-o);t.parentElement.setAttribute("style",`--vot-progress: ${n}`)}function lt(t,e="",o=" ",n=!1){const i=document.createElement("vot-block");i.classList.add("vot-textfield");const a=document.createElement(n?"textarea":"input");a.placeholder=o,a.value=e;const r=document.createElement("span");return r.innerHTML=t,i.appendChild(a),i.appendChild(r),{container:i,input:a,label:r}}function dt(t){const e=document.createElement("vot-block");e.classList.add("vot-dialog-container"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-dialog-backdrop");const n=document.createElement("vot-block");n.classList.add("vot-dialog");const i=document.createElement("vot-block");i.classList.add("vot-dialog-content-wrapper");const a=document.createElement("vot-block");a.classList.add("vot-dialog-header-container");const r=document.createElement("vot-block");r.classList.add("vot-dialog-body-container");const s=document.createElement("vot-block");s.classList.add("vot-dialog-footer-container");const l=document.createElement("vot-block");l.classList.add("vot-dialog-title-container");const d=rt('');d.classList.add("vot-dialog-close-button"),o.onclick=d.onclick=()=>{e.hidden=!0};const c=document.createElement("vot-block");return c.classList.add("vot-dialog-title"),c.innerHTML=t,e.appendChild(o),e.appendChild(n),n.appendChild(i),i.appendChild(a),i.appendChild(r),i.appendChild(s),a.appendChild(l),a.appendChild(d),l.appendChild(c),{container:e,backdrop:o,dialog:n,contentWrapper:i,headerContainer:a,bodyContainer:r,footerContainer:s,titleContainer:l,closeButton:d,title:c}}function ct(t,e,o,n={}){const i=n.onSelectCb||function(){},a=n.labelElement||"";let r=[];const s=document.createElement("vot-block");s.classList.add("vot-select"),a&&s.appendChild(a);const l=document.createElement("vot-block");l.classList.add("vot-select-outer");const d=document.createElement("span");d.classList.add("vot-select-title"),d.innerText=t,void 0===t&&(d.innerText=o.find((t=>!0===t.selected))?.label);const c=document.createElement("vot-block");return c.classList.add("vot-select-arrow-icon"),c.innerHTML='',l.append(d,c),l.onclick=()=>{const t=dt(e);t.container.classList.add("vot-dialog-temp"),t.container.hidden=!1,document.documentElement.appendChild(t.container);const n=document.createElement("vot-block");n.classList.add("vot-select-content-list");for(const t of o){const e=document.createElement("vot-block");e.classList.add("vot-select-content-item"),e.innerText=t.label,e.dataset.votSelected=t.selected,e.dataset.votValue=t.value,t.disabled&&(e.inert=!0),e.onclick=async a=>{a.target.inert||(n.childNodes.forEach((t=>t.dataset.votSelected=!1)),o.forEach((e=>e.selected=e.value===t.value)),e.dataset.votSelected=!0,d.innerText=t.label,await i(a))},n.appendChild(e)}const a=lt(v.V.get("searchField"));a.input.oninput=t=>{const e=t.target.value.toLowerCase();Array.from(r).forEach((t=>t.hidden=!t.innerText.toLowerCase().includes(e)))},t.bodyContainer.append(a.container,n),r=n.childNodes,t.backdrop.onclick=t.closeButton.onclick=()=>{t.container.remove(),r=[]}},s.append(l),{container:s,title:d,arrowIcon:c,labelElement:a,setTitle:t=>{d.innerText=t},setSelected:t=>{Array.from(r).filter((t=>!t.inert)).forEach((e=>e.dataset.votSelected=e.dataset.votValue===t)),o.forEach((e=>e.selected=String(e.value)===t))},updateItems:t=>{o=t}}}const ut={createHeader:function(t,e=4){const o=document.createElement("vot-block");return o.classList.add("vot-header"),o.classList.add(`vot-header-level-${e}`),o.innerHTML=t,o},createInformation:function(t,e){const o=document.createElement("vot-block");o.classList.add("vot-info");const n=document.createElement("vot-block");n.innerHTML=t;const i=document.createElement("vot-block");return i.innerHTML=e,o.appendChild(n),o.appendChild(i),{container:o,header:n,value:i}},createButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-button"),e.innerHTML=t,e},createTextButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-text-button"),e.innerHTML=t,e},createOutlinedButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-outlined-button"),e.innerHTML=t,e},createIconButton:rt,createCheckbox:function(t,e=!1){const o=document.createElement("label");o.classList.add("vot-checkbox");const n=document.createElement("input");n.type="checkbox",n.checked=Boolean(e);const i=document.createElement("span");return i.innerHTML=t,o.appendChild(n),o.appendChild(i),{container:o,input:n,label:i}},createSlider:function(t,e=50,o=0,n=100){const i=document.createElement("vot-block");i.classList.add("vot-slider");const a=document.createElement("input");a.type="range",a.min=o,a.max=n,a.value=e;const r=document.createElement("span");return r.innerHTML=t,i.appendChild(a),i.appendChild(r),a.addEventListener("input",(t=>st(t.target))),st(a),{container:i,input:a,label:r}},createTextfield:lt,createDialog:dt,createVOTButton:function(t){const e=document.createElement("vot-block");e.classList.add("vot-segmented-button");const o=document.createElement("vot-block");o.classList.add("vot-segment"),o.classList.add("vot-translate-button"),o.innerHTML='';const n=document.createElement("vot-block");n.classList.add("vot-separator");const i=document.createElement("vot-block");i.classList.add("vot-segment-only-icon"),i.innerHTML='';const a=document.createElement("vot-block");a.classList.add("vot-separator");const r=document.createElement("vot-block");r.classList.add("vot-segment-only-icon"),r.innerHTML='';const s=document.createElement("span");return s.classList.add("vot-segment-label"),s.innerHTML=t,e.appendChild(o),e.appendChild(n),e.appendChild(i),e.appendChild(a),e.appendChild(r),o.appendChild(s),{container:e,translateButton:o,separator:n,pipButton:i,separator2:a,menuButton:r,label:s}},createVOTMenu:function(t){const e=document.createElement("vot-block");e.classList.add("vot-menu"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-menu-content-wrapper");const n=document.createElement("vot-block");n.classList.add("vot-menu-header-container");const i=document.createElement("vot-block");i.classList.add("vot-menu-body-container");const a=document.createElement("vot-block");a.classList.add("vot-menu-footer-container");const r=document.createElement("vot-block");r.classList.add("vot-menu-title-container");const s=document.createElement("vot-block");return s.classList.add("vot-menu-title"),s.innerHTML=t,e.appendChild(o),o.appendChild(n),o.appendChild(i),o.appendChild(a),n.appendChild(r),r.appendChild(s),{container:e,contentWrapper:o,headerContainer:n,bodyContainer:i,footerContainer:a,titleContainer:r,title:s}},createVOTSelectLabel:function(t){const e=document.createElement("span");return e.classList.add("vot-select-label"),e.innerText=t,e},createVOTSelect:ct,createVOTLanguageSelect:function(t){const e=t.fromTitle||"#UNDEFINED",o=t.fromDialogTitle||"#UNDEFINED",n=t.fromItems||[],i=t.fromOnSelectCB||function(){},a=t.toTitle||"#UNDEFINED",r=t.toDialogTitle||"#UNDEFINED",s=t.toItems||[],l=t.toOnSelectCB||function(){},d=document.createElement("vot-block");d.classList.add("vot-lang-select");const c=ct(e,o,n,{onSelectCb:i}),u=document.createElement("vot-block");u.classList.add("vot-lang-select-icon"),u.innerHTML='';const h=ct(a,r,s,{onSelectCb:l});return d.append(c.container,u,h.container),{container:d,fromSelect:c,icon:u,toSelect:h}},updateSlider:st};function ht(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}var pt=o("./node_modules/bowser/es5.js");function gt(t){const e=([1e7]+1e3+4e3+8e3+1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)));return t?e:e.toUpperCase()}async function vt(t){const e=new TextEncoder("utf-8"),o=await window.crypto.subtle.importKey("raw",e.encode(k.I1),{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign","verify"]),n=await window.crypto.subtle.sign("HMAC",o,t);return Array.from(new Uint8Array(n),(t=>t.toString(16).padStart(2,"0"))).join("")}function mt(t){const e=t.startMs+t.durationMs;return t.tokens.reduce(((o,n,i)=>{const a=t.tokens[i+1],r=o[o.length-1],s=r?.alignRange?.end??0,l=s+n.text.length;if(o.push(Object.assign(Object.assign({},n),{alignRange:{start:s,end:l}})),a){const t=n.startMs+n.durationMs,i=a.startMs?a.startMs-t:e-t;o.push({text:" ",startMs:t,durationMs:i,alignRange:{start:l,end:l+1}})}return o}),[])}function bt(t,e){const o=t.text.split(new RegExp("([\n \t])")).reduce(((t,o)=>{if(o.length){const n=t[t.length-1]??e,i=n?.alignRange?.end??0,a=i+o.length;t.push({text:o,alignRange:{start:i,end:a}})}return t}),[]),n=Math.floor(t.durationMs/o.length),i=t.startMs+t.durationMs;return o.map(((e,a)=>{const r=a===o.length-1,s=t.startMs+n*a,l=r?i-s:n;return Object.assign(Object.assign({},e),{startMs:s,durationMs:l})}))}class ft{dragging=!1;subtitlesContainerRect=null;containerRect=null;offsetX=null;offsetY=null;lastContent=null;highlightWords=!1;subtitles=null;maxLength=300;maxLengthRegexp=/.{1,300}(?:\s|$)/g;constructor(t,e,o){this.site=o,this.video=t,"youtube"===this.site.host&&"mobile"!==this.site.additionalData?this.container=e.parentElement:this.container=e,this.votSubtitlesContainer=document.createElement("vot-block"),this.votSubtitlesContainer.classList.add("vot-subtitles-widget"),this.container.appendChild(this.votSubtitlesContainer),this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onMouseMoveBound=this.onMouseMove.bind(this),this.onTimeUpdateBound=this.onTimeUpdate.bind(this),document.addEventListener("mousedown",this.onMouseDownBound),document.addEventListener("mouseup",this.onMouseUpBound),document.addEventListener("mousemove",this.onMouseMoveBound),this.video?.addEventListener("timeupdate",this.onTimeUpdateBound)}release(){this.video?.removeEventListener("timeupdate",this.onTimeUpdateBound),document.removeEventListener("mousedown",this.onMouseDownBound),document.removeEventListener("mouseup",this.onMouseUpBound),document.removeEventListener("mousemove",this.onMouseMoveBound),this.votSubtitlesContainer.remove()}onMouseDown(t){this.votSubtitlesContainer.contains(t.target)&&(this.subtitlesContainerRect=this.votSubtitlesContainer.getBoundingClientRect(),this.containerRect=this.container.getBoundingClientRect(),this.offsetX=t.clientX-this.subtitlesContainerRect.x,this.offsetY=t.clientY-this.subtitlesContainerRect.y,this.dragging=!0)}onMouseUp(){this.dragging=!1}onMouseMove(t){if(this.dragging){t.preventDefault();const e=t.clientX-this.offsetX,o=t.clientY-this.offsetY,n=o>=this.containerRect.top,i=o+this.subtitlesContainerRect.height<=this.containerRect.bottom,a=e>=this.containerRect.left,r=e+this.subtitlesContainerRect.width<=this.containerRect.right;this.votSubtitlesContainer.style.top=n&&i?o-this.containerRect.y+"px":n?this.containerRect.height-this.subtitlesContainerRect.height+"px":"0px",this.votSubtitlesContainer.style.left=a&&r?e-this.containerRect.x+"px":a?this.containerRect.width-this.subtitlesContainerRect.width+"px":"0px"}}onTimeUpdate(){this.update()}setContent(t){t&&this.video?(this.subtitles=t,this.update()):(this.subtitles=null,this.votSubtitlesContainer.innerHTML="")}setMaxLength(t){"number"==typeof t&&t&&(this.maxLength=t,this.maxLengthRegexp=new RegExp(`.{1,${t}}(?:\\s|$)`,"g"),this.update())}setHighlightWords(t){this.highlightWords!==!!t&&(this.highlightWords=!!t,this.update())}update(){if(!this.video)return;let t="",e=this.highlightWords&&this.subtitles?.containsTokens;const o=1e3*this.video.currentTime,n=this.subtitles?.subtitles?.findLast((t=>t.startMsthis.maxLength){let t=[],n=0,i=0,a=0;for(let o=0;othis.maxLength){let r=e.slice(n,i+1);r.at(0)&&" "===r.at(0).text&&(r=r.slice(1)),r.at(-1)&&" "===r.at(-1).text&&(r=r.slice(0,r.length-1)),t.push({startMs:e[n].startMs,durationMs:e[i].startMs+e[i].durationMs-e[n].startMs,tokens:r}),n=o,a=0}i=o}for(let n=0;ne||o>n.startMs-100&&e-o<275?'class="passed"':""}>${n.text}`}}else if(n.text.length>this.maxLength){let e=n.text.match(this.maxLengthRegexp),i=n.durationMs/e.length;for(let a=0;a${t.replace("\\n","
")}`:"")}}const yt=async function(){const t=window.course_id??document.querySelector('input[name="course_id"]')?.value,e=window.lessons??await async function(t){const e=await fetch(`https://coursehunter.net/api/v1/course/${t}/lessons`);return await e.json()}(t),o=parseInt(document.querySelector(".lessons-item_active")?.dataset?.index??1),n=e?.[o-1],{file:i,duration:a}=n;return b.Z.log("coursehunter course data:",e),{url:i,duration:a}};function wt(){return xt()?.player}function xt(){return document.querySelector(".vjs-v6")}const St=async function(t="en"){let e=null;const o=wt(),{duration:n}=o?.cache_||{},{courseId:i,tracks:a,sources:r}=o?.options_||{},s=function(t){const e=t?.find((t=>"video/mp4"===t.type));return e?.src}(r),l=await async function(t){const e=await fetch(`https://www.coursera.org/api/onDemandCourses.v1/${t}`),o=await e.json();return o?.elements?.[0]}(i);let d=l?.primaryLanguageCodes?.[0];d=d?(0,S.eL)(d):"en",f.includes(d)||(d="en");const c=function(t,e,o){let n=t?.find((t=>(0,S.eL)(t.srclang)===e));return n||(n=t?.find((t=>(0,S.eL)(t.srclang)===o))||t?.[0]),n?.src}(a,d,t);console.log(`videoURL: ${s}, subtitlesURL: ${c}`),c&&s?e=[{target:"video_file_url",targetUrl:s},{target:"subtitles_file_url",targetUrl:`https://www.coursera.org${c}`}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${s}, subtitlesURL: ${c}`);const u={duration:n,detectedLanguage:d,translationHelp:e};return b.Z.log("coursera video data:",u),console.log("[VOT] Detected language: ",u.detectedLanguage),u},kt="https://www.udemy.com/api-2.0";async function Tt(t){const e=await fetch(`${kt}/courses/${t}/?`+new URLSearchParams({"fields[course]":"locale",use_remote_version:"true",caching_intent:"true"}));return await e.json()}async function Vt(t,e,o){if(!(t.expires+2592e6>(new Date).getTime()&&t.accessToken))return void console.error(v.V.get("udemyAccessTokenExpired"));const n=`Bearer ${t.accessToken}`,i=await fetch(`${kt}/users/me/subscribed-courses/${e}/lectures/${o}/?`+new URLSearchParams({"fields[lecture]":"asset","fields[asset]":"length,media_sources,captions"}),{headers:{"x-udemy-authorization":n,authorization:n}});return await i.json()}function Mt(){return Ot()?.player}function Lt(){const t=document.querySelector(".ud-app-loader[data-module-id='course-taking']")?.dataset?.moduleArgs;return t?JSON.parse(t):(console.error(v.V.get("udemyModuleArgsNotFound")),{})}function Ot(){return document.querySelector(".vjs-v7")}const Pt=async function(t,e="en"){let o=null;const n=Mt();b.Z.log("udemyData",t);const i=Lt();b.Z.log("moduleData: ",i);const a=i.courseId,r=window.location.pathname.match(/learn\/lecture\/([^/]+)/)?.[1];b.Z.log(`CourseId: ${a}, lectureId: ${r}`);const s=await Tt(a);b.Z.log("courseLang Data:",s);const l=await Vt(t,a,r);console.log("lecture Data:",l);let d=s?.locale?.locale;d=d?(0,S.eL)(d):"en",f.includes(d)||(d="en");const c=l?.asset?.length||n?.cache_?.duration,u=function(t){const e=t?.find((t=>"video/webm"===t.type||"video/mp4"===t.type));return e?.src}(l?.asset?.media_sources)||function(){const t=Ot()?.querySelector("video")?.src;return!t?.startsWith("blob:")&&t}(),h=function(t,e,o){let n=t?.find((t=>(0,S.eL)(t.locale_id)===e));return n||(n=t?.find((t=>(0,S.eL)(t.locale_id)===o))||t?.[0]),n?.url}(l?.asset?.captions,d,e);console.log(`videoURL: ${u}, subtitlesURL: ${h}`),h&&u?o=[{target:"video_file_url",targetUrl:u},{target:"subtitles_file_url",targetUrl:h}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${u}, subtitlesURL: ${h}`);const p={duration:c,detectedLanguage:d,translationHelp:o};return b.Z.log("udemy video data:",p),console.log("[VOT] Detected language: ",p.detectedLanguage),p};o("./node_modules/requestidlecallback-polyfill/index.js");class Et{constructor(){this.listeners=new Set}hasListener(t){return this.listeners.has(t)}dispatchToListener(t,...e){try{t(...e)}catch(t){console.error("[VOT]",t)}}addListener(t){if(this.hasListener(t))throw new Error("[VOT] The listener has already been added.");this.listeners.add(t)}removeListener(t){if(!this.hasListener(t))throw new Error("[VOT] The listener has not been added yet.");this.listeners.delete(t)}dispatch(...t){for(const e of Array.from(this.listeners))this.dispatchToListener(e,...t)}}function Ct(t){return Array.from(t).map((t=>{const e=[];return t instanceof HTMLVideoElement&&e.push(t),t instanceof HTMLElement&&e.push(...Array.from(t.querySelectorAll("video"))),t?.shadowRoot?.querySelectorAll&&e.push(...Array.from(t.shadowRoot.querySelectorAll("video"))),e})).flat()}const At=[{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:"shorts-video #player"},{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:".player-container"},{host:"youtube",url:"https://youtu.be/",match:/^(www.)?youtube(-nocookie|kids)?.com$/,selector:".html5-video-container:not(#inline-player *)"},{host:"tiktok",url:"https://www.tiktok.com/",match:/^(www.)?tiktok.com$/,selector:null},{host:"proxytok",url:"https://www.tiktok.com/",match:["proxitok.pabloferreiro.es","proxitok.pussthecat.org","tok.habedieeh.re","proxitok.esmailelbob.xyz","proxitok.privacydev.net","tok.artemislena.eu","tok.adminforge.de","tik.hostux.net","tt.vern.cc","cringe.whatever.social","proxitok.lunar.icu","proxitok.privacy.com.de"],selector:".column.has-text-centered"},{additionalData:"mobile",host:"twitch",url:"https://twitch.tv/",match:/^m.twitch.tv$/,selector:"main > div > section > div > div > div"},{host:"twitch",url:"https://twitch.tv/",match:t=>t.host.includes("clips.twitch.tv")||t.host.includes("player.twitch.tv")&&null===t.searchParams.get("channel")||t.host.includes("twitch.tv")&&(t.pathname.startsWith("/videos")||t.pathname.startsWith("/embed")||t.pathname.includes("/clip")),selector:".video-ref"},{host:"xvideos",url:"https://www.xvideos.com/",match:/^www.xvideos.com$/,selector:".video-bg-pic"},{host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:/^[a-z]+.pornhub.com$/,selector:".mainPlayerDiv > .video-element-wrapper-js > div"},{additionalData:"embed",host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:t=>t.host.includes("pornhub.com")&&t.pathname.startsWith("/embed/"),selector:"#player"},{additionalData:"mobile",host:"vk",url:"https://vk.com/video?z=",match:/^m.vk.(com|ru)$/,selector:"vk-video-player",shadowRoot:!0},{host:"vk",url:"https://vk.com/video?z=",match:/^(www.|m.)?vk.(com|ru)$/,selector:".videoplayer_media"},{host:"vimeo",url:"https://vimeo.com/",match:/^(player.)?vimeo.com$/,selector:".player"},{host:"nine_gag",url:"https://9gag.com/gag/",match:/^9gag.com$/,selector:".video-post"},{host:"coub",url:"https://coub.com/view/",match:/^coub.com$/,selector:".viewer__player"},{host:"bitchute",url:"https://www.bitchute.com/video/",match:/^(www.)?bitchute.com$/,selector:".plyr__video-wrapper"},{host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:".video-player > div > div > div:nth-child(2)"},{additionalData:"embed",host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:"#app > div > div"},{host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m|player).bilibili.com$/,selector:".bpx-player-video-wrap"},{additionalData:"old",host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m).bilibili.com$/,selector:null},{host:"twitter",url:"https://twitter.com/i/status/",match:/^twitter.com$/,selector:'div[data-testid="videoComponent"] > div:nth-child(1) > div'},{host:"mail_ru",url:"https://my.mail.ru/",match:/^my.mail.ru$/,selector:"#b-video-wrapper"},{host:"coursera",url:"https://www.coursera.org/",match:/coursera.org$/,selector:".vjs-v6"},{host:"udemy",url:"https://www.udemy.com",match:/udemy.com$/,selector:'div[data-purpose="curriculum-item-viewer-content"] > section > div > div > div > div:nth-of-type(2)'},{host:"invidious",url:"https://youtu.be/",match:it,selector:"#player"},{host:"piped",url:"https://youtu.be/",match:at,selector:".shaka-video-container"},{host:"rumble",url:"https://rumble.com",match:/^rumble.com$/,selector:"#videoPlayer > .videoPlayer-Rumble-cls > div"},{host:"eporner",url:"https://www.eporner.com/",match:/^(www.)?eporner.com$/,selector:".vjs-v7"},{host:"peertube",url:"tube.shanti.cafe",match:["peertube.1312.media","tube.shanti.cafe","bee-tube.fr","video.sadmin.io","dalek.zone","review.peertube.biz","peervideo.club","tube.la-dina.net","peertube.tmp.rcp.tf"],selector:".vjs-v7"},{host:"dailymotion",url:"https://www.dailymotion.com/video/",match:/^geo.dailymotion.com$/,selector:".player"},{host:"trovo",url:"https://trovo.live/s/",match:/^trovo.live$/,selector:".player-video"},{host:"yandexdisk",url:"https://disk.yandex.ru/i/",match:/^disk.yandex.ru$/,selector:"yaplayertag > div:nth-of-type(1)"},{host:"coursehunter",url:"https://coursehunter.net/course/",match:/^coursehunter.net$/,selector:"#oframeplayer > pjsdiv:nth-of-type(1)"}],Bt=pt.getParser(window.navigator.userAgent).getResult(),_t=[...it,...at],Ft=["playing","ratechange","play","waiting","pause"];function qt(t,e,o=!1){return t.map((t=>({label:`${o&&!w.includes(t)?"❌ ":""}${v.V.get("langs")[t]??t.toUpperCase()}`,value:t,selected:e===t})))}class Rt{translateFromLang="en";translateToLang=S.KQ;timer;ytData="";videoData="";firstPlay=!0;audio=new Audio;hls=(0,S.QZ)();downloadTranslationUrl=null;downloadSubtitlesUrl=null;autoRetry;streamPing;volumeOnStart;tempOriginalVolume;tempVolume;subtitlesList=[];subtitlesListVideoId=null;videoLastSrcObject=null;constructor(t,e,o){b.Z.log("[VideoHandler] add video:",t,"container:",e,this),this.video=t,this.container=e,this.site=o,this.handleSrcChangedBound=this.handleSrcChanged.bind(this),this.srcObserver=new MutationObserver(this.handleSrcChangedBound),this.srcObserver.observe(this.video,{attributeFilter:["src","currentSrc"]}),this.srcObjectInterval=setInterval((async()=>{this.videoLastSrcObject!==this.video.srcObject&&(this.videoLastSrcObject=this.video.srcObject,await this.handleSrcChanged())}),100),this.stopTranslationBound=this.stopTranslation.bind(this),this.handleVideoEventBound=this.handleVideoEvent.bind(this),this.changeOpacityOnEventBound=this.changeOpacityOnEvent.bind(this),this.resetTimerBound=this.resetTimer.bind(this),this.init()}async init(){if(this.initialized)return;this.data={autoTranslate:await T.i.get("autoTranslate",0,!0),dontTranslateLanguage:await T.i.get("dontTranslateLanguage",S.KQ),dontTranslateYourLang:await T.i.get("dontTranslateYourLang",1,!0),autoSetVolumeYandexStyle:await T.i.get("autoSetVolumeYandexStyle",1,!0),autoVolume:await T.i.get("autoVolume",k.sN,!0)/100,showVideoSlider:await T.i.get("showVideoSlider",1,!0),syncVolume:await T.i.get("syncVolume",0,!0),subtitlesMaxLength:await T.i.get("subtitlesMaxLength",300,!0),highlightWords:await T.i.get("highlightWords",0,!0),responseLanguage:await T.i.get("responseLanguage",S.KQ),defaultVolume:await T.i.get("defaultVolume",100,!0),udemyData:await T.i.get("udemyData",{accessToken:"",expires:0}),audioProxy:await T.i.get("audioProxy",(S.KQ,0),!0),showPiPButton:await T.i.get("showPiPButton",0,!0),translateAPIErrors:await T.i.get("translateAPIErrors",1,!0),translationService:await T.i.get("translationService",k.kF),detectService:await T.i.get("detectService",k.EY),m3u8ProxyHost:await T.i.get("m3u8ProxyHost",k.e6),proxyWorkerHost:await T.i.get("proxyWorkerHost",k.ez)},this.videoData=await this.getVideoData(),console.log("[db] data from db: ",this.data),this.subtitlesWidget=new ft(this.video,this.container,this.site),this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength),this.subtitlesWidget.setHighlightWords(this.data.highlightWords),this.initUI(),this.initUIEvents();const t=!this.video.src&&!this.video.currentSrc&&!this.video.srcObject;this.votButton.container.hidden=t,t&&(this.votMenu.container.hidden=t),await this.updateSubtitles(),await this.changeSubtitlesLang("disabled"),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage??"ru"),this.translateToLang=this.data.responseLanguage??"ru",this.initExtraEvents(),this.initialized=!0}transformBtn(t="none",e){this.votButton.container.dataset.status=t,this.votButton.label.innerHTML=e}initUI(){this.votButton=ut.createVOTButton(v.V.get("translateVideo")),this.container.appendChild(this.votButton.container),this.votButton.pipButton.hidden=!(0,S.qq)()||!this.data?.showPiPButton,this.votButton.separator2.hidden=!(0,S.qq)()||!this.data?.showPiPButton,this.votButton.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votMenu=ut.createVOTMenu(v.V.get("VOTSettings")),this.container.appendChild(this.votMenu.container),this.votDownloadButton=ut.createIconButton(''),this.votDownloadButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadButton),this.votDownloadSubtitlesButton=ut.createIconButton(''),this.votDownloadSubtitlesButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadSubtitlesButton),this.votSettingsButton=ut.createIconButton(''),this.votMenu.headerContainer.appendChild(this.votSettingsButton),this.votTranslationLanguageSelect=ut.createVOTLanguageSelect({fromTitle:v.V.get("langs")[this.video.detectedLanguage],fromDialogTitle:v.V.get("videoLanguage"),fromItems:[{label:v.V.get("langs").auto,value:"auto",selected:""},...qt(f,this.videoData.detectedLanguage)],fromOnSelectCB:async t=>{b.Z.log("[fromOnSelectCB] select from language",t.target.dataset.votValue),this.videoData=await this.getVideoData(),this.setSelectMenuValues(t.target.dataset.votValue,this.videoData.responseLanguage)},toTitle:v.V.get("langs")[this.video.responseLanguage],toDialogTitle:v.V.get("translationLanguage"),toItems:[...qt(f,this.videoData.responseLanguage,!0),{label:"─────────",value:"separator",disabled:!0},...qt(y,this.videoData.responseLanguage,!0)],toOnSelectCB:async t=>{const e=t.target.dataset.votValue;b.Z.log("[toOnSelectCB] select to language",e),this.data.responseLanguage=this.translateToLang=e,await T.i.set("responseLanguage",this.data.responseLanguage),b.Z.log("Response Language value changed. New value: ",this.data.responseLanguage),this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage)}}),this.votMenu.bodyContainer.appendChild(this.votTranslationLanguageSelect.container),this.votSubtitlesSelect=ut.createVOTSelect(v.V.get("VOTSubtitlesDisabled"),v.V.get("VOTSubtitles"),[{label:v.V.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1}],{onSelectCb:async t=>{await this.changeSubtitlesLang(t.target.dataset.votValue)},labelElement:ut.createVOTSelectLabel(v.V.get("VOTSubtitles"))}),this.votMenu.bodyContainer.appendChild(this.votSubtitlesSelect.container),this.votVideoVolumeSlider=ut.createSlider(`${v.V.get("VOTVolume")}: ${100*this.getVideoVolume()}%`,100*this.getVideoVolume()),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoVolumeSlider.container),this.votVideoTranslationVolumeSlider=ut.createSlider(`${v.V.get("VOTVolumeTranslation")}: ${this.data?.defaultVolume??100}%`,this.data?.defaultVolume??100),this.votVideoTranslationVolumeSlider.container.hidden="success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoTranslationVolumeSlider.container),this.votMenu.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votSettingsDialog=ut.createDialog(v.V.get("VOTSettings")),document.documentElement.appendChild(this.votSettingsDialog.container),this.votTranslationHeader=ut.createHeader(v.V.get("translationSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationHeader),this.votAutoTranslateCheckbox=ut.createCheckbox(v.V.get("VOTAutoTranslate"),this.data?.autoTranslate??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoTranslateCheckbox.container),this.votDontTranslateYourLangSelect=ut.createVOTSelect(v.V.get("langs")[T.i.syncGet("dontTranslateLanguage",S.KQ)],v.V.get("VOTDontTranslateYourLang"),qt(f,T.i.syncGet("dontTranslateLanguage",S.KQ)),{onSelectCb:async t=>{this.data.dontTranslateLanguage=t.target.dataset.votValue,await T.i.set("dontTranslateLanguage",this.data.dontTranslateLanguage)},labelElement:ut.createCheckbox(v.V.get("VOTDontTranslateYourLang"),this.data?.dontTranslateYourLang??!0).container}),this.votSettingsDialog.bodyContainer.appendChild(this.votDontTranslateYourLangSelect.container),this.votAutoSetVolumeCheckbox=ut.createCheckbox(`${v.V.get("VOTAutoSetVolume")}`,this.data?.autoSetVolumeYandexStyle??!0),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeCheckbox.container),this.votAutoSetVolumeSlider=ut.createSlider(`${100*(this.data?.autoVolume??k.sN)}%`,100*(this.data?.autoVolume??k.sN),0,100),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeSlider.container),this.votShowVideoSliderCheckbox=ut.createCheckbox(v.V.get("VOTShowVideoSlider"),this.data?.showVideoSlider??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votShowVideoSliderCheckbox.container),this.votUdemyDataTextfield=ut.createTextfield(v.V.get("VOTUdemyData"),this.data?.udemyData?.accessToken??""),this.votUdemyDataTextfield.container.hidden="udemy"!==this.site.host,this.votSettingsDialog.bodyContainer.appendChild(this.votUdemyDataTextfield.container),this.votSyncVolumeCheckbox=ut.createCheckbox(v.V.get("VOTSyncVolume"),this.data?.syncVolume??!1),this.votSyncVolumeCheckbox.container.hidden="youtube"!==this.site.host||"mobile"===this.site.additionalData,this.votSettingsDialog.bodyContainer.appendChild(this.votSyncVolumeCheckbox.container),this.votTranslationServiceSelect=ut.createVOTSelect(T.i.syncGet("translationService",k.kF),v.V.get("VOTTranslationService"),qt(P,T.i.syncGet("translationService",k.kF)),{onSelectCb:async t=>{this.data.translationService=t.target.dataset.votValue,await T.i.set("translationService",this.data.translationService)},labelElement:ut.createCheckbox(v.V.get("VOTTranslateAPIErrors"),this.data.translateAPIErrors??!0).container}),this.votTranslationServiceSelect.container.hidden="ru"===v.V.lang,this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationServiceSelect.container),this.votDetectServiceSelect=ut.createVOTSelect(T.i.syncGet("detectService",k.EY),v.V.get("VOTDetectService"),qt(E,T.i.syncGet("detectService",k.EY)),{onSelectCb:async t=>{this.data.detectService=t.target.dataset.votValue,await T.i.set("detectService",this.data.detectService)},labelElement:ut.createVOTSelectLabel(v.V.get("VOTDetectService"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votDetectServiceSelect.container),this.votSubtitlesHeader=ut.createHeader(v.V.get("subtitlesSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader),this.votSubtitlesMaxLengthSlider=ut.createSlider(`${v.V.get("VOTSubtitlesMaxLength")}: ${this.data?.subtitlesMaxLength??300}`,this.data?.subtitlesMaxLength??300,50,300),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesMaxLengthSlider.container),this.votSubtitlesHighlightWordsCheckbox=ut.createCheckbox(v.V.get("VOTHighlightWords"),this.data?.highlightWords??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHighlightWordsCheckbox.container),this.votProxyHeader=ut.createHeader(v.V.get("proxySettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader),this.votM3u8ProxyHostTextfield=ut.createTextfield(v.V.get("VOTM3u8ProxyHost"),this.data?.m3u8ProxyHost,k.e6),this.votSettingsDialog.bodyContainer.appendChild(this.votM3u8ProxyHostTextfield.container),this.votProxyWorkerHostTextfield=ut.createTextfield(v.V.get("VOTProxyWorkerHost"),this.data?.proxyWorkerHost,k.ez),this.votProxyWorkerHostTextfield.container.hidden=!0,this.votSettingsDialog.bodyContainer.appendChild(this.votProxyWorkerHostTextfield.container),this.votAudioProxyCheckbox=ut.createCheckbox(v.V.get("VOTAudioProxy"),this.data?.audioProxy??!1),this.votAudioProxyCheckbox.container.hidden=!0,this.votSettingsDialog.bodyContainer.appendChild(this.votAudioProxyCheckbox.container),this.votAboutHeader=ut.createHeader(v.V.get("about")),this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader),this.votLanguageSelect=ut.createVOTSelect(v.V.get("langs")[T.i.syncGet("locale-lang-override","auto")],v.V.get("VOTMenuLanguage"),qt(v.Z,T.i.syncGet("locale-lang-override","auto")),{onSelectCb:async t=>{await T.i.set("locale-lang-override",t.target.dataset.votValue)},labelElement:ut.createVOTSelectLabel(v.V.get("VOTMenuLanguage"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votLanguageSelect.container),this.votShowPiPButtonCheckbox=ut.createCheckbox(v.V.get("VOTShowPiPButton"),this.data?.showPiPButton??!1),this.votShowPiPButtonCheckbox.container.hidden=!(0,S.qq)(),this.votSettingsDialog.bodyContainer.appendChild(this.votShowPiPButtonCheckbox.container),this.votVersionInfo=ut.createInformation(`${v.V.get("VOTVersion")}:`,GM_info.script.version),this.votSettingsDialog.bodyContainer.appendChild(this.votVersionInfo.container),this.votAuthorsInfo=ut.createInformation(`${v.V.get("VOTAuthors")}:`,GM_info.script.author),this.votSettingsDialog.bodyContainer.appendChild(this.votAuthorsInfo.container),this.votLoaderInfo=ut.createInformation(`${v.V.get("VOTLoader")}:`,`${GM_info.scriptHandler} v${GM_info.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votLoaderInfo.container),this.votBrowserInfo=ut.createInformation(`${v.V.get("VOTBrowser")}:`,`${Bt.browser.name} ${Bt.browser.version} (${Bt.os.name} ${Bt.os.version})`),this.votSettingsDialog.bodyContainer.appendChild(this.votBrowserInfo.container),this.votResetSettingsButton=ut.createButton(v.V.get("resetSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votResetSettingsButton)}initUIEvents(){this.votButton.translateButton.addEventListener("click",(async()=>{if(this.audio.src)return b.Z.log("[click translationBtn] audio.src is not empty"),void this.stopTraslate();try{b.Z.log("[click translationBtn] trying execute translation");const t=(0,S.gJ)(this.site.host,this.video);if(!t)throw new m("VOTNoVideoIDFound");await this.translateExecutor(t)}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.votDownloadButton.addEventListener("click",(()=>{this.downloadTranslationUrl&&window.open(this.downloadTranslationUrl,"_blank").focus()})),this.votDownloadSubtitlesButton.addEventListener("click",(()=>{console.log(this.downloadSubtitlesUrl),this.downloadSubtitlesUrl&&window.open(this.downloadSubtitlesUrl,"_blank").focus()})),this.votSettingsButton.addEventListener("click",(()=>{this.votSettingsDialog.container.hidden=!this.votSettingsDialog.container.hidden,(void 0===document.fullscreen||document.fullscreen)&&(document.webkitExitFullscreen&&document.webkitExitFullscreen(),document.mozCancelFullscreen&&document.mozCancelFullscreen(),document.exitFullscreen&&document.exitFullscreen())})),this.votVideoVolumeSlider.input.addEventListener("input",(t=>{const e=Number(t.target.value);if(this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`,this.setVideoVolume(e/100),1===this.data.syncVolume){const t=Number(this.votVideoTranslationVolumeSlider.input.value),o=ht(this.audio,e,t,this.tempOriginalVolume);this.votVideoTranslationVolumeSlider.input.value=o,this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,ut.updateSlider(this.votVideoTranslationVolumeSlider.input),this.tempVolume=o,this.tempOriginalVolume=e}})),this.votVideoTranslationVolumeSlider.input.addEventListener("input",(async t=>{this.data.defaultVolume=Number(t.target.value),await T.i.set("defaultVolume",this.data.defaultVolume),this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${this.data.defaultVolume}%`,this.audio.volume=this.data.defaultVolume/100,1===this.data.syncVolume&&this.syncTranslationWithVideo(this.data.defaultVolume)})),this.votAutoTranslateCheckbox.input.addEventListener("change",(async t=>{this.data.autoTranslate=Number(t.target.checked),await T.i.set("autoTranslate",this.data.autoTranslate),b.Z.log("autoTranslate value changed. New value: ",this.data.autoTranslate)})),this.votDontTranslateYourLangSelect.labelElement.addEventListener("change",(async t=>{this.data.dontTranslateYourLang=Number(t.target.checked),await T.i.set("dontTranslateYourLang",this.data.dontTranslateYourLang),b.Z.log("dontTranslateYourLang value changed. New value: ",this.data.dontTranslateYourLang)})),this.votAutoSetVolumeCheckbox.input.addEventListener("change",(async t=>{this.data.autoSetVolumeYandexStyle=Number(t.target.checked),await T.i.set("autoSetVolumeYandexStyle",this.data.autoSetVolumeYandexStyle),b.Z.log("autoSetVolumeYandexStyle value changed. New value: ",this.data.autoSetVolumeYandexStyle)})),this.votAutoSetVolumeSlider.input.addEventListener("input",(async t=>{const e=Number(t.target.value);this.data.autoVolume=e/100,await T.i.set("autoVolume",e),this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`})),this.votShowVideoSliderCheckbox.input.addEventListener("change",(async t=>{this.data.showVideoSlider=Number(t.target.checked),await T.i.set("showVideoSlider",this.data.showVideoSlider),b.Z.log("showVideoSlider value changed. New value: ",this.data.showVideoSlider),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status})),this.votUdemyDataTextfield.input.addEventListener("change",(async t=>{this.data.udemyData={accessToken:t.target.value,expires:(new Date).getTime()},await T.i.set("udemyData",this.data.udemyData),b.Z.log("udemyData value changed. New value: ",this.data.udemyData),window.location.reload()})),this.votSyncVolumeCheckbox.input.addEventListener("change",(async t=>{this.data.syncVolume=Number(t.target.checked),await T.i.set("syncVolume",this.data.syncVolume),b.Z.log("syncVolume value changed. New value: ",this.data.syncVolume)})),this.votTranslationServiceSelect.labelElement.addEventListener("change",(async t=>{this.data.translateAPIErrors=Number(t.target.checked),await T.i.set("translateAPIErrors",this.data.translateAPIErrors),b.Z.log("translateAPIErrors value changed. New value: ",this.data.translateAPIErrors)})),this.votSubtitlesMaxLengthSlider.input.addEventListener("input",(async t=>{this.data.subtitlesMaxLength=Number(t.target.value),await T.i.set("subtitlesMaxLength",this.data.subtitlesMaxLength),this.votSubtitlesMaxLengthSlider.label.querySelector("strong").innerHTML=`${this.data.subtitlesMaxLength}`,this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength)})),this.votSubtitlesHighlightWordsCheckbox.input.addEventListener("change",(async t=>{this.data.highlightWords=Number(t.target.checked),await T.i.set("highlightWords",this.data.highlightWords),b.Z.log("highlightWords value changed. New value: ",this.data.highlightWords),this.subtitlesWidget.setHighlightWords(this.data.highlightWords)})),this.votShowPiPButtonCheckbox.input.addEventListener("change",(async t=>{this.data.showPiPButton=Number(t.target.checked),await T.i.set("showPiPButton",this.data.showPiPButton),b.Z.log("showPiPButton value changed. New value: ",this.data.showPiPButton),this.votButton.pipButton.hidden=!(0,S.qq)()||!this.data.showPiPButton,this.votButton.separator2.hidden=!(0,S.qq)()||!this.data.showPiPButton})),this.votM3u8ProxyHostTextfield.input.addEventListener("change",(async t=>{this.data.m3u8ProxyHost=t.target.value||k.e6,await T.i.set("m3u8ProxyHost",this.data.m3u8ProxyHost),b.Z.log("m3u8ProxyHost value changed. New value: ",this.data.m3u8ProxyHost)})),this.votProxyWorkerHostTextfield.input.addEventListener("change",(async t=>{this.data.proxyWorkerHost=t.target.value||k.ez,await T.i.set("proxyWorkerHost",this.data.proxyWorkerHost),b.Z.log("proxyWorkerHost value changed. New value: ",this.data.proxyWorkerHost),window.location.reload()})),this.votAudioProxyCheckbox.input.addEventListener("change",(async t=>{this.data.audioProxy=Number(t.target.checked),await T.i.set("audioProxy",this.data.audioProxy),b.Z.log("audioProxy value changed. New value: ",this.data.audioProxy)})),this.votResetSettingsButton.addEventListener("click",(async()=>{v.V.reset(),(await T.i.list()).filter((t=>!v.V.gmValues.includes(t))).forEach((t=>T.i.syncDelete(t))),window.location.reload()}))}releaseExtraEvents(){clearInterval(this.resizeInterval),this.resizeObserver?.disconnect(),"youtube"===this.site.host&&"mobile"!==this.site.additionalData&&this.syncVolumeObserver?.disconnect(),this.extraEvents?.forEach((t=>{t.element.removeEventListener(t.event,t.handler)}))}initExtraEvents(){this.extraEvents=[];const t=(t,e,o)=>{this.extraEvents.push({element:t,event:e,handler:o}),t.addEventListener(e,o)},e=(e,o,n)=>{o.forEach((o=>{t(e,o,n)}))};if(this.resizeObserver=new ResizeObserver((t=>{t.forEach((t=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${t.contentRect.height}px`)}))})),this.resizeObserver.observe(this.video),this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`),this.resizeInterval=setInterval((()=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`)}),500),"youtube"===this.site.host&&"mobile"!==this.site.additionalData){this.syncVolumeObserver=new MutationObserver((t=>{t.forEach((t=>{"attributes"===t.type&&"aria-valuenow"===t.attributeName&&this.syncVideoVolumeSlider()}))}));const t=document.querySelector(".ytp-volume-panel");t&&this.syncVolumeObserver.observe(t,{attributes:!0,childList:!1,subtree:!0,attributeOldValue:!0})}let o;document.addEventListener("click",(t=>{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),c=a.contains(e),u=r?.contains(e)??!1;b.Z.log(`[document click] ${s} ${l} ${d} ${c} ${u}`),s||l||c||u||(d||this.logout(0),this.votMenu.container.hidden=!0)})),o="pornhub"===this.site.host?"embed"===this.site.additionalData?document.querySelector("#player"):this.container.querySelector(".video-element-wrapper-js > div"):"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),t(this.video,"abort",(()=>{b.Z.log("lipsync mode is abort"),this.stopTranslation(),this.videoData=""})),t(this.video,"progress",(async()=>{if(!this.firstPlay||1!==this.data.autoTranslate)return;const t=(0,S.gJ)(this.site.host,this.video);if(!t)throw new m("VOTNoVideoIDFound");try{await this.translateExecutor(t),this.firstPlay=!1}catch(t){console.error("[VOT]",t),"VOTLocalizedError"===t?.name?this.transformBtn("error",t.localizedMessage):this.transformBtn("error",t),this.firstPlay=!1}}))}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)}),2e3)}changeOpacityOnEvent(t){clearTimeout(this.timer),this.logout(1),t.stopPropagation()}async changeSubtitlesLang(t){if(b.Z.log("[onchange] subtitles",t),this.votSubtitlesSelect.setSelected(t),"disabled"===t)this.votSubtitlesSelect.setTitle(v.V.get("VOTSubtitlesDisabled")),this.subtitlesWidget.setContent(null),this.votDownloadSubtitlesButton.hidden=!0,this.downloadSubtitlesUrl=null;else{const e=await async function(t){let e=!1,o=await Promise.race([new Promise((async t=>{await(0,S._v)(5e3),e||console.error("[VOT] Failed to fetch subtitles. Reason: timeout"),e=!0,t([])})),new Promise((async o=>{b.Z.log("Fetching subtitles:",t),await fetch(t.url).then((t=>t.json())).then((t=>{e=!0,o(t)})).catch((t=>{console.error("[VOT] Failed to fetch subtitles. Reason:",t),e=!0,o({containsTokens:!1,subtitles:[]})}))}))]);return"youtube"===t.source&&(o=function(t){const e={containsTokens:!1,subtitles:[]};if("object"!=typeof t||!("events"in t)||!Array.isArray(t.events))return console.error("[VOT] Failed to format youtube subtitles",t),e;for(let o=0;ot.utf8.replace(/^ +| +$/g,""))).join(" ");let i=t.events[o].dDurationMs;t.events[o+1]&&t.events[o].tStartMs+t.events[o].dDurationMs>t.events[o+1].tStartMs&&(i=t.events[o+1].tStartMs-t.events[o].tStartMs),"\n"!==n&&e.subtitles.push({text:n,startMs:t.events[o].tStartMs,durationMs:i})}return e}(o)),o.subtitles=function(t,e){const o=[];let n;for(const i of t.subtitles){let a;if(i?.tokens?.length){if("yandex"!==e)return console.warn("[VOT] Unsupported subtitles tokens type: ",e),t.containsTokens=!1,null;a=mt(i)}else a=bt(i,n);n=a[a.length-1],o.push(Object.assign(Object.assign({},i),{tokens:a}))}return t.containsTokens=!0,o}(o,t.source),console.log("[VOT] subtitles:",o),o}(this.subtitlesList.at(parseInt(t)));this.subtitlesWidget.setContent(e),this.votDownloadSubtitlesButton.hidden=!1,this.downloadSubtitlesUrl=this.subtitlesList.at(parseInt(t))?.url}}async updateSubtitlesLangSelect(){const t=[{label:v.V.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1},...this.subtitlesList.map(((t,e)=>({label:(v.V.get("langs")[t.language]??t.language.toUpperCase())+(t.translatedFromLanguage?` ${v.V.get("VOTTranslatedFrom")} ${v.V.get("langs")[t.translatedFromLanguage]??t.translatedFromLanguage.toUpperCase()}`:"")+("yandex"!==t.source?` ${t.source}`:"")+(t.isAutoGenerated?` (${v.V.get("VOTAutogenerated")})`:""),value:e,selected:!1,disabled:!1})))];this.votSubtitlesSelect.updateItems(t),await this.changeSubtitlesLang(t[0].value)}async updateSubtitles(){await this.changeSubtitlesLang("disabled");const t=(0,S.gJ)(this.site.host,this.video);if(!t)return console.error(`[VOT] ${v.V.getDefault("VOTNoVideoIDFound")}`),this.subtitlesList=[],this.subtitlesListVideoId=null,void await this.updateSubtitlesLangSelect();this.subtitlesListVideoId!==t&&(this.videoData.detectedLanguage||(this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage)),this.subtitlesList=await async function(t,e,n){const i="youtube"===t.host?q():[];let a=!1;const r=[...await Promise.race([new Promise((async t=>{await(0,S._v)(5e3),a||console.error("[VOT] Failed get yandex subtitles. Reason: timeout"),a=!0,t([])})),new Promise((i=>{!async function(t,e,n){try{b.Z.log("requestVideoSubtitles");const i=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;b.Z.log("Inited yandexRequest...");const a=X(t,e);await i("/video-subtitles/get-subtitles",a,{"Vsubs-Signature":await vt(a),"Sec-Vsubs-Token":gt(!1)},n)}catch(t){console.error("[VOT]",t),n(!1)}}(`${t.url}${e}`,n,((t,e)=>{b.Z.log("[exec callback] Requesting video subtitles"),t||(console.error("[VOT] Failed get yandex subtitles"),a=!0,i([]));const o=tt(e);console.log("[VOT] Subtitles response: ",o);let n=o.subtitles??[];n=n.reduce(((t,e)=>(e.language&&!t.find((t=>{if("yandex"===t.source&&t.language===e.language&&!t.translatedFromLanguage)return t}))&&t.push({source:"yandex",language:e.language,url:e.url}),e.translatedLanguage&&t.push({source:"yandex",language:e.translatedLanguage,translatedFromLanguage:e.language,url:e.translatedUrl}),t)),[]),a=!0,i(n)}))}))]),...i].sort(((t,e)=>{if(t.source!==e.source)return"yandex"===t.source?-1:1;if(t.language!==e.language&&(t.language===S.KQ||e.language===S.KQ))return t.language===S.KQ?-1:1;if("yandex"===t.source){if(t.translatedFromLanguage!==e.translatedFromLanguage)return t.translatedFromLanguage&&e.translatedFromLanguage?t.translatedFromLanguage===n?-1:1:t.language===e.language?t.translatedFromLanguage?1:-1:t.translatedFromLanguage?-1:1;if(!t.translatedFromLanguage)return t.language===n?-1:1}return"youtube"===t.source&&t.isAutoGenerated!==e.isAutoGenerated?t.isAutoGenerated?1:-1:0}));return console.log("[VOT] subtitles list",r),r}(this.site,t,this.videoData.detectedLanguage),this.subtitlesList?this.subtitlesListVideoId=t:await this.changeSubtitlesLang("disabled"),await this.updateSubtitlesLangSelect())}getVideoVolume(){let t=this.video?.volume;return"youtube"===this.site.host&&(t=F()||t),t}setVideoVolume(t){"youtube"===this.site.host&&z(t)||(this.video.volume=t)}syncVideoVolumeSlider(){const t=Math.round(100*this.getVideoVolume());this.votVideoVolumeSlider.input.value=t,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${t}%`,ut.updateSlider(this.votVideoVolumeSlider.input),1===this.data.syncVolume&&(this.tempOriginalVolume=Number(t))}setSelectMenuValues(t,e){this.votTranslationLanguageSelect.fromSelect.setTitle(v.V.get("langs")[t]),this.votTranslationLanguageSelect.toSelect.setTitle(v.V.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}syncTranslationWithVideo(t){const e=Number(this.votVideoVolumeSlider.input.value),o=ht(this.video,t,e,this.tempVolume);this.votVideoVolumeSlider.input.value=o,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,ut.updateSlider(this.votVideoVolumeSlider.input),this.tempOriginalVolume=o,this.tempVolume=t}async getVideoData(){const t={translationHelp:null,isStream:!1};if(t.duration=this.video?.duration||343,t.videoId=(0,S.gJ)(this.site.host,this.video),t.detectedLanguage=this.translateFromLang,t.responseLanguage=this.translateToLang,!t.videoId)return this.ytData={},t;if(window.location.hostname.includes("youtube.com"))this.ytData=await R(),t.isStream=this.ytData.isLive,""!==this.ytData.author&&(t.detectedLanguage=this.ytData.detectedLanguage,t.responseLanguage=this.translateToLang);else if(window.location.hostname.includes("rutube")||window.location.hostname.includes("my.mail.ru"))t.detectedLanguage="ru";else if(window.location.hostname.includes("bilibili.com"))t.detectedLanguage="zh";else if(window.location.hostname.includes("coursera.org")){const e=await St(this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else if(window.location.hostname.includes("coursehunter.net")){const e=await yt();t.translationHelp={url:e.url},t.duration=e.duration||t.duration}else if(window.location.hostname.includes("udemy.com")){const e=await Pt(this.data.udemyData,this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else"vk"!==this.site.host&&"piped"!==this.site.host&&"invidious"!==this.site.host&&"bitchute"!==this.site.host&&"rumble"!==this.site.host&&"peertube"!==this.site.host&&"dailymotion"!==this.site.host&&"trovo"!==this.site.host&&"yandexdisk"!==this.site.host&&"coursehunter"!==this.site.host||(t.detectedLanguage="auto");return t}videoValidator(){if("youtube"===this.site.host){if(b.Z.log("VideoValidator videoData: ",this.videoData),1===this.data.dontTranslateYourLang&&this.videoData.detectedLanguage===this.data.dontTranslateLanguage&&this.videoData.responseLanguage===this.data.dontTranslateLanguage)throw new m("VOTDisableFromYourLang");if(this.videoData.duration>14400)throw new m("VOTVideoIsTooLong")}return!0}lipSync(t=!1){if(b.Z.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"===t&&(b.Z.log("lipsync mode is pause"),this.audio.pause()),"stop"===t&&(b.Z.log("lipsync mode is stop"),this.audio.pause()),"waiting"===t&&(b.Z.log("lipsync mode is waiting"),this.audio.pause()),"playing"===t&&(b.Z.log("lipsync mode is playing"),this.audio.play());else{b.Z.log("lipsync mode is play");const t=this.audio.play();void 0!==t&&t.catch((t=>{if(console.error("[VOT]",t),"NotAllowedError"===t.name)throw this.transformBtn("error",v.V.get("grantPermissionToAutoPlay")),new m("grantPermissionToAutoPlay");if("NotSupportedError"===t.name)throw this.transformBtn("error",_t.includes(window.location.hostname)?v.V.get("neededAdditionalExtension"):v.V.get("audioFormatNotSupported")),_t.includes(window.location.hostname)?new m("neededAdditionalExtension"):new m("audioFormatNotSupported")}))}else b.Z.log("lipsync mode is not set")}handleVideoEvent(t){b.Z.log(`video ${t.type}`),this.lipSync(t.type)}stopTraslate(){Ft.forEach((t=>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",v.V.get("translateVideo")),this.volumeOnStart&&(b.Z.log(`Volume on start: ${this.volumeOnStart}`),"youtube"===this.site.host?z(this.volumeOnStart):this.video.volume=this.volumeOnStart),clearInterval(this.streamPing),this.hls?.destroy(),this.hls=(0,S.QZ)()}async translateExecutor(t){this.videoData.detectedLanguage||(this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage)),b.Z.log("Run videoValidator"),this.videoValidator(),b.Z.log("Run translateFunc"),this.translateFunc(t,this.videoData.isStream,this.videoData.detectedLanguage,this.videoData.responseLanguage,this.videoData.translationHelp)}translateFunc(t,e,n,i,a){console.log("[VOT] Video Data: ",this.videoData);const r=a?.url?a.url:`${this.site.url}${t}`;if(this.videoValidator(),e)return b.Z.log("Executed stream translation"),void function(t,e,n,i){b.Z.log(`Translate stream (url: ${t}, requestLang: ${e}, responseLang: ${n})`),async function(t,e,n,i){try{b.Z.log("requestStreamTranslation");const a=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;b.Z.log("Inited yandexRequest...");const r=ot(t,e,n);await a("/stream-translation/translate-stream",r,{"Vtrans-Signature":await vt(r),"Sec-Vtrans-Token":gt(!1)},i)}catch(t){console.error("[VOT]",t),i(!1)}}(t,e,n,((t,e)=>{if(b.Z.log("[exec callback] Requesting stream translation"),!t)return void i(!1,v.V.get("requestTranslationFailed"));const o=nt(e);switch(console.log("[VOT] Stream Translation response: ",o),o.interval){case 10:i(!1,o.interval,v.V.get("translationTakeFewMinutes"));break;case 20:i(!0,o.interval,o||v.V.get("audioNotReceived"));break;case 0:i(!1,o.interval,v.V.get("streamNoConnectionToServer"))}}))}(r,n,i,(async(r,s,l)=>{if(b.Z.log("[exec callback] translateStream callback"),(0,S.gJ)(this.site.host,this.video)!==t)return;if(!r||!l.translatedInfo)return"VOTLocalizedError"===l?.name?this.transformBtn("error",l.localizedMessage):1===this.data.translateAPIErrors&&"ru"!==v.V.lang?(this.transformBtn("error",`${v.V.get("VOTTranslatingError")}...`),this.transformBtn("error",await O(l,"ru",v.V.lang))):this.transformBtn("error",l),void(10===s&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,n,i,a)),1e3*s)));this.transformBtn("success",v.V.get("disableTranslate")),console.log(l);const d=l.pingId;b.Z.log(`Stream pingId: ${d}`),this.streamPing=setInterval((async()=>await async function(t,e){try{b.Z.log("requestStreamPing");const n=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;b.Z.log("Inited yandexRequest...");const i=et(t);await n("/stream-translation/ping-stream",i,{"Vtrans-Signature":await vt(i),"Sec-Vtrans-Token":gt(!1)},e)}catch(t){console.error("[VOT]",t),e(!1)}}(d,(t=>b.Z.log("Stream ping result: ",t)))),1e3*s),b.Z.log(l.translatedInfo.url);const c=`https://${this.data.m3u8ProxyHost}/?all=yes&origin=${encodeURIComponent("https://strm.yandex.ru")}&referer=${encodeURIComponent("https://strm.yandex.ru")}&url=${encodeURIComponent(l.translatedInfo.url)}`;if(b.Z.log(c),this.hls)this.hls.on(Hls.Events.MEDIA_ATTACHED,(function(){b.Z.log("audio and hls.js are now bound together !")})),this.hls.on(Hls.Events.MANIFEST_PARSED,(function(t,e){b.Z.log("manifest loaded, found "+e.levels.length+" quality level")})),this.hls.loadSource(c),this.hls.attachMedia(this.audio),this.hls.on(Hls.Events.ERROR,(function(t,e){if(e.fatal)switch(e.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",e);break;default:this.hls.destroy()}})),b.Z.log(this.hls);else{if(!this.audio.canPlayType("application/vnd.apple.mpegurl"))throw new m("audioFormatNotSupported");this.audio.src=c}D(this.video,10),this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),this.video.src||this.video.currentSrc||this.video.srcObject?(this.video&&!this.video.paused&&this.lipSync("play"),Ft.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),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").innerHTML=100*this.data.autoVolume+"%",ut.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=c):this.stopTranslation()}));if(["udemy","coursera"].includes(this.site.host)&&!a)throw new m("VOTTranslationHelpNull");!function(t,e,n,i,a,r){b.Z.log(`Translate video (url: ${t}, duration: ${e}, requestLang: ${n}, responseLang: ${i})`),b.Z.log("translationHelp:",a),async function(t,e,n,i,a,r){try{b.Z.log("requestVideoTranslation");const s=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;b.Z.log("Inited yandexRequest...");const l=Q(t,e,n,i,a);await s("/video-translation/translate",l,{"Vtrans-Signature":await vt(l),"Sec-Vtrans-Token":gt(!1)},r)}catch(t){console.error("[VOT]",t),r(!1)}}(t,e,n,i,a,((t,e)=>{if(b.Z.log("[exec callback] Requesting video translation"),!t)return void r(!1,v.V.get("requestTranslationFailed"));const o=J(e);switch(console.log("[VOT] Translation response: ",o),o.status){case 0:r(!1,o.message);break;case 1:r(!!o.url,o.url||v.V.get("audioNotReceived"));break;case 2:r(!1,o.remainingTime?(0,S.PG)(o.remainingTime):v.V.get("translationTakeFewMinutes"));break;case 3:case 6:r(!1,v.V.get("videoBeingTranslated"))}}))}(r,this.videoData.duration,n,i,a,(async(o,r)=>{if(b.Z.log("[exec callback] translateVideo callback"),(0,S.gJ)(this.site.host,this.video)!==t)return;if(!o)return"VOTLocalizedError"===r?.name?this.transformBtn("error",r.localizedMessage):1!==this.data.translateAPIErrors||r.includes(v.V.get("translationTake"))||"ru"===v.V.lang?this.transformBtn("error",r):(this.transformBtn("error",v.V.get("VOTTranslatingError")),this.transformBtn("error",await O(r,"ru",v.V.lang))),r.includes(v.V.get("translationTake"))&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,n,i,a)),6e4)),void console.error("[VOT]",r);if(this.audio.src=r,this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),"twitter"===this.site.host&&document.querySelector('div[data-testid="app-bar-back"][role="button"]').addEventListener("click",this.stopTranslationBound),!this.video.src&&!this.video.currentSrc&&!this.video.srcObject)return void this.stopTranslation();const s=["twitch","vimeo","facebook","rutube","twitter","bilibili","mail_ru","rumble","eporner"];for(let t=0;t{t.forEach((t=>{"attributes"===t.type&&"src"===t.attributeName&&t.target===this.video&&""!==t.target.src&&(this.stopTranslation(),this.firstPlay=!0)}))})).observe(this.container,{attributes:!0,childList:!1,subtree:!0,attributeOldValue:!0});break}this.video&&!this.video.paused&&this.lipSync("play"),Ft.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),this.transformBtn("success",v.V.get("disableTranslate")),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").innerHTML=100*this.data.autoVolume+"%",ut.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=r}))}stopTranslation(){this.stopTraslate(),this.syncVideoVolumeSlider()}async waitInitialization(){let t=!1;return await Promise.race([new Promise((async e=>{await(0,S._v)(1e3),t||console.error("[VOT] Initialization timeout"),t=!0,e(!1)})),new Promise((async e=>{for(;!this.initialized;)await(0,S._v)(100);t=!0,e(!0)}))])}async handleSrcChanged(){if(b.Z.log("[VideoHandler] src changed",this),!await this.waitInitialization())return;this.stopTranslation(),this.videoData=await this.getVideoData(),this.firstPlay=!0;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.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage??"ru"),this.translateToLang=this.data.responseLanguage??"ru"}async release(){b.Z.log("[VideoHandler] release"),await this.waitInitialization()&&(this.initialized=!1,this.stopTranslation(),this.releaseExtraEvents(),this.subtitlesWidget.release(),this.srcObserver.disconnect(),clearInterval(this.srcObjectInterval),this.votButton.container.remove(),this.votMenu.container.remove())}}const zt=new class{constructor(){this.onVideoAdded=new Et,this.onVideoRemoved=new Et,this.handleVideoAddedBound=this.handleVideoAdded.bind(this),this.handleVideoRemovedBound=this.handleVideoRemoved.bind(this),this.observer=new MutationObserver((t=>{window.requestIdleCallback((()=>{t.forEach((t=>{"childList"===t.type&&(Ct(t.addedNodes).forEach(this.handleVideoAddedBound),Ct(t.removedNodes).forEach(this.handleVideoRemovedBound))}))}),{timeout:1e3})}))}enable(){this.observer.observe(document,{childList:!0,subtree:!0}),document.querySelectorAll("video").forEach(this.handleVideoAddedBound)}disable(){this.observer.disconnect()}handleVideoAdded(t){this.onVideoAdded.dispatch(t)}handleVideoRemoved(t){document.contains(t)||this.onVideoRemoved.dispatch(t)}},Dt=new WeakMap;(async function(){if(b.Z.log("Loading extension..."),await v.V.update(),b.Z.log(`Selected menu language: ${v.V.lang}`),GM_info?.scriptHandler&&x.includes(GM_info.scriptHandler))return console.error(`[VOT] ${v.V.getDefault("unSupportedExtensionError").format(GM_info.scriptHandler)}`),alert(`[VOT] ${v.V.get("unSupportedExtensionError").format(GM_info.scriptHandler)}`);b.Z.log("Extension compatibility passed..."),zt.onVideoAdded.addListener((t=>{for(const e of At.filter((t=>{const e=t=>t instanceof RegExp&&t.test(window.location.hostname)||"string"==typeof t&&window.location.hostname.includes(t)||"function"==typeof t&&t(new URL(window.location));return!!(e(t.match)||t.match instanceof Array&&t.match.some((t=>e(t))))&&t.host&&t.url}))){if(!e)continue;let o;if(e.shadowRoot)o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.shadowRoot.contains(t))):t.parentElement,o=o&&o.shadowRoot?o.parentElement:o;else{const n=Bt.browser.version.split(".")?.[0];if(e.selector?.includes(":not")&&e.selector?.includes("*")&&n&&("Chrome"===Bt.browser.name&&Number(n)<88||"Firefox"===Bt.browser.name&&Number(n)<84)){const n=e.selector?.split(" *")?.[0];o=n?Object.values(document.querySelectorAll(n)).find((e=>e.contains(t))):t.parentElement}else o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.contains(t))):t.parentElement}if(o&&!("rumble"===e.host&&o.querySelector("vot-block")||("peertube"===e.host&&(e.url=window.location.origin),Dt.has(t)))){Dt.set(t,new Rt(t,o,e));break}}})),zt.onVideoRemoved.addListener((async t=>{Dt.has(t)&&(await Dt.get(t).release(),Dt.delete(t))})),zt.enable()})().catch((t=>{console.error("[VOT]",t)}))})()})(); \ No newline at end of file +(()=>{var t={"./node_modules/bowser/es5.js":function(t){t.exports=function(t){var e={};function o(n){if(e[n])return e[n].exports;var a=e[n]={i:n,l:!1,exports:{}};return t[n].call(a.exports,a,a.exports,o),a.l=!0,a.exports}return o.m=t,o.c=e,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)o.d(n,a,function(e){return t[e]}.bind(null,a));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=90)}({17:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n=o(18),a=function(){function t(){}return t.getFirstMatch=function(t,e){var o=e.match(t);return o&&o.length>0&&o[1]||""},t.getSecondMatch=function(t,e){var o=e.match(t);return o&&o.length>1&&o[2]||""},t.matchAndReturnConst=function(t,e,o){if(t.test(e))return o},t.getWindowsVersionName=function(t){switch(t){case"NT":return"NT";case"XP":case"NT 5.1":return"XP";case"NT 5.0":return"2000";case"NT 5.2":return"2003";case"NT 6.0":return"Vista";case"NT 6.1":return"7";case"NT 6.2":return"8";case"NT 6.3":return"8.1";case"NT 10.0":return"10";default:return}},t.getMacOSVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),10===e[0])switch(e[1]){case 5:return"Leopard";case 6:return"Snow Leopard";case 7:return"Lion";case 8:return"Mountain Lion";case 9:return"Mavericks";case 10:return"Yosemite";case 11:return"El Capitan";case 12:return"Sierra";case 13:return"High Sierra";case 14:return"Mojave";case 15:return"Catalina";default:return}},t.getAndroidVersionName=function(t){var e=t.split(".").splice(0,2).map((function(t){return parseInt(t,10)||0}));if(e.push(0),!(1===e[0]&&e[1]<5))return 1===e[0]&&e[1]<6?"Cupcake":1===e[0]&&e[1]>=6?"Donut":2===e[0]&&e[1]<2?"Eclair":2===e[0]&&2===e[1]?"Froyo":2===e[0]&&e[1]>2?"Gingerbread":3===e[0]?"Honeycomb":4===e[0]&&e[1]<1?"Ice Cream Sandwich":4===e[0]&&e[1]<4?"Jelly Bean":4===e[0]&&e[1]>=4?"KitKat":5===e[0]?"Lollipop":6===e[0]?"Marshmallow":7===e[0]?"Nougat":8===e[0]?"Oreo":9===e[0]?"Pie":void 0},t.getVersionPrecision=function(t){return t.split(".").length},t.compareVersions=function(e,o,n){void 0===n&&(n=!1);var a=t.getVersionPrecision(e),i=t.getVersionPrecision(o),r=Math.max(a,i),s=0,l=t.map([e,o],(function(e){var o=r-t.getVersionPrecision(e),n=e+new Array(o+1).join(".0");return t.map(n.split("."),(function(t){return new Array(20-t.length).join("0")+t})).reverse()}));for(n&&(s=r-Math.min(a,i)),r-=1;r>=s;){if(l[0][r]>l[1][r])return 1;if(l[0][r]===l[1][r]){if(r===s)return 0;r-=1}else if(l[0][r]1?a-1:0),r=1;r0){var r=Object.keys(o),l=s.default.find(r,(function(t){return e.isOS(t)}));if(l){var d=this.satisfies(o[l]);if(void 0!==d)return d}var c=s.default.find(r,(function(t){return e.isPlatform(t)}));if(c){var u=this.satisfies(o[c]);if(void 0!==u)return u}}if(i>0){var h=Object.keys(a),p=s.default.find(h,(function(t){return e.isBrowser(t,!0)}));if(void 0!==p)return this.compareVersion(a[p])}},e.isBrowser=function(t,e){void 0===e&&(e=!1);var o=this.getBrowserName().toLowerCase(),n=t.toLowerCase(),a=s.default.getBrowserTypeByAlias(n);return e&&a&&(n=a.toLowerCase()),n===o},e.compareVersion=function(t){var e=[0],o=t,n=!1,a=this.getBrowserVersion();if("string"==typeof a)return">"===t[0]||"<"===t[0]?(o=t.substr(1),"="===t[1]?(n=!0,o=t.substr(2)):e=[],">"===t[0]?e.push(1):e.push(-1)):"="===t[0]?o=t.substr(1):"~"===t[0]&&(n=!0,o=t.substr(1)),e.indexOf(s.default.compareVersions(a,o,n))>-1},e.isOS=function(t){return this.getOSName(!0)===String(t).toLowerCase()},e.isPlatform=function(t){return this.getPlatformType(!0)===String(t).toLowerCase()},e.isEngine=function(t){return this.getEngineName(!0)===String(t).toLowerCase()},e.is=function(t,e){return void 0===e&&(e=!1),this.isBrowser(t,e)||this.isOS(t)||this.isPlatform(t)},e.some=function(t){var e=this;return void 0===t&&(t=[]),t.some((function(t){return e.is(t)}))},t}();e.default=d,t.exports=e.default},92:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=/version\/(\d+(\.?_?\d+)+)/i,r=[{test:[/googlebot/i],describe:function(t){var e={name:"Googlebot"},o=a.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/opera/i],describe:function(t){var e={name:"Opera"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opr\/|opios/i],describe:function(t){var e={name:"Opera"},o=a.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/SamsungBrowser/i],describe:function(t){var e={name:"Samsung Internet for Android"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Whale/i],describe:function(t){var e={name:"NAVER Whale Browser"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MZBrowser/i],describe:function(t){var e={name:"MZ Browser"},o=a.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/focus/i],describe:function(t){var e={name:"Focus"},o=a.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/swing/i],describe:function(t){var e={name:"Swing"},o=a.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/coast/i],describe:function(t){var e={name:"Opera Coast"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(t){var e={name:"Opera Touch"},o=a.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/yabrowser/i],describe:function(t){var e={name:"Yandex Browser"},o=a.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/ucbrowser/i],describe:function(t){var e={name:"UC Browser"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/Maxthon|mxios/i],describe:function(t){var e={name:"Maxthon"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/epiphany/i],describe:function(t){var e={name:"Epiphany"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/puffin/i],describe:function(t){var e={name:"Puffin"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sleipnir/i],describe:function(t){var e={name:"Sleipnir"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/k-meleon/i],describe:function(t){var e={name:"K-Meleon"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/micromessenger/i],describe:function(t){var e={name:"WeChat"},o=a.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/qqbrowser/i],describe:function(t){var e={name:/qqbrowserlite/i.test(t)?"QQ Browser Lite":"QQ Browser"},o=a.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/msie|trident/i],describe:function(t){var e={name:"Internet Explorer"},o=a.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/\sedg\//i],describe:function(t){var e={name:"Microsoft Edge"},o=a.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/edg([ea]|ios)/i],describe:function(t){var e={name:"Microsoft Edge"},o=a.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/vivaldi/i],describe:function(t){var e={name:"Vivaldi"},o=a.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/seamonkey/i],describe:function(t){var e={name:"SeaMonkey"},o=a.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/sailfish/i],describe:function(t){var e={name:"Sailfish"},o=a.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,t);return o&&(e.version=o),e}},{test:[/silk/i],describe:function(t){var e={name:"Amazon Silk"},o=a.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/phantom/i],describe:function(t){var e={name:"PhantomJS"},o=a.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/slimerjs/i],describe:function(t){var e={name:"SlimerJS"},o=a.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e={name:"BlackBerry"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e={name:"WebOS Browser"},o=a.default.getFirstMatch(i,t)||a.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/bada/i],describe:function(t){var e={name:"Bada"},o=a.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/tizen/i],describe:function(t){var e={name:"Tizen"},o=a.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/qupzilla/i],describe:function(t){var e={name:"QupZilla"},o=a.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/firefox|iceweasel|fxios/i],describe:function(t){var e={name:"Firefox"},o=a.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/electron/i],describe:function(t){var e={name:"Electron"},o=a.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/MiuiBrowser/i],describe:function(t){var e={name:"Miui"},o=a.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/chromium/i],describe:function(t){var e={name:"Chromium"},o=a.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,t)||a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/chrome|crios|crmo/i],describe:function(t){var e={name:"Chrome"},o=a.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/GSA/i],describe:function(t){var e={name:"Google Search"},o=a.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e={name:"Android Browser"},o=a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/playstation 4/i],describe:function(t){var e={name:"PlayStation 4"},o=a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/safari|applewebkit/i],describe:function(t){var e={name:"Safari"},o=a.default.getFirstMatch(i,t);return o&&(e.version=o),e}},{test:[/.*/i],describe:function(t){var e=-1!==t.search("\\(")?/^(.*)\/(.*)[ \t]\((.*)/:/^(.*)\/(.*) /;return{name:a.default.getFirstMatch(e,t),version:a.default.getSecondMatch(e,t)}}}];e.default=r,t.exports=e.default},93:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=o(18),r=[{test:[/Roku\/DVP/],describe:function(t){var e=a.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,t);return{name:i.OS_MAP.Roku,version:e}}},{test:[/windows phone/i],describe:function(t){var e=a.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.WindowsPhone,version:e}}},{test:[/windows /i],describe:function(t){var e=a.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,t),o=a.default.getWindowsVersionName(e);return{name:i.OS_MAP.Windows,version:e,versionName:o}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(t){var e={name:i.OS_MAP.iOS},o=a.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,t);return o&&(e.version=o),e}},{test:[/macintosh/i],describe:function(t){var e=a.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,t).replace(/[_\s]/g,"."),o=a.default.getMacOSVersionName(e),n={name:i.OS_MAP.MacOS,version:e};return o&&(n.versionName=o),n}},{test:[/(ipod|iphone|ipad)/i],describe:function(t){var e=a.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,t).replace(/[_\s]/g,".");return{name:i.OS_MAP.iOS,version:e}}},{test:function(t){var e=!t.test(/like android/i),o=t.test(/android/i);return e&&o},describe:function(t){var e=a.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,t),o=a.default.getAndroidVersionName(e),n={name:i.OS_MAP.Android,version:e};return o&&(n.versionName=o),n}},{test:[/(web|hpw)[o0]s/i],describe:function(t){var e=a.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,t),o={name:i.OS_MAP.WebOS};return e&&e.length&&(o.version=e),o}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(t){var e=a.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,t)||a.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,t)||a.default.getFirstMatch(/\bbb(\d+)/i,t);return{name:i.OS_MAP.BlackBerry,version:e}}},{test:[/bada/i],describe:function(t){var e=a.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.Bada,version:e}}},{test:[/tizen/i],describe:function(t){var e=a.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.Tizen,version:e}}},{test:[/linux/i],describe:function(){return{name:i.OS_MAP.Linux}}},{test:[/CrOS/],describe:function(){return{name:i.OS_MAP.ChromeOS}}},{test:[/PlayStation 4/],describe:function(t){var e=a.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,t);return{name:i.OS_MAP.PlayStation4,version:e}}}];e.default=r,t.exports=e.default},94:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=o(18),r=[{test:[/googlebot/i],describe:function(){return{type:"bot",vendor:"Google"}}},{test:[/huawei/i],describe:function(t){var e=a.default.getFirstMatch(/(can-l01)/i,t)&&"Nova",o={type:i.PLATFORMS_MAP.mobile,vendor:"Huawei"};return e&&(o.model=e),o}},{test:[/nexus\s*(?:7|8|9|10).*/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Nexus"}}},{test:[/ipad/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Apple",model:"iPad"}}},{test:[/kftt build/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Amazon",model:"Kindle Fire HD 7"}}},{test:[/silk/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet,vendor:"Amazon"}}},{test:[/tablet(?! pc)/i],describe:function(){return{type:i.PLATFORMS_MAP.tablet}}},{test:function(t){var e=t.test(/ipod|iphone/i),o=t.test(/like (ipod|iphone)/i);return e&&!o},describe:function(t){var e=a.default.getFirstMatch(/(ipod|iphone)/i,t);return{type:i.PLATFORMS_MAP.mobile,vendor:"Apple",model:e}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:i.PLATFORMS_MAP.mobile,vendor:"Nexus"}}},{test:[/[^-]mobi/i],describe:function(){return{type:i.PLATFORMS_MAP.mobile}}},{test:function(t){return"blackberry"===t.getBrowserName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.mobile,vendor:"BlackBerry"}}},{test:function(t){return"bada"===t.getBrowserName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.mobile}}},{test:function(t){return"windows phone"===t.getBrowserName()},describe:function(){return{type:i.PLATFORMS_MAP.mobile,vendor:"Microsoft"}}},{test:function(t){var e=Number(String(t.getOSVersion()).split(".")[0]);return"android"===t.getOSName(!0)&&e>=3},describe:function(){return{type:i.PLATFORMS_MAP.tablet}}},{test:function(t){return"android"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.mobile}}},{test:function(t){return"macos"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.desktop,vendor:"Apple"}}},{test:function(t){return"windows"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.desktop}}},{test:function(t){return"linux"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.desktop}}},{test:function(t){return"playstation 4"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.tv}}},{test:function(t){return"roku"===t.getOSName(!0)},describe:function(){return{type:i.PLATFORMS_MAP.tv}}}];e.default=r,t.exports=e.default},95:function(t,e,o){"use strict";e.__esModule=!0,e.default=void 0;var n,a=(n=o(17))&&n.__esModule?n:{default:n},i=o(18),r=[{test:function(t){return"microsoft edge"===t.getBrowserName(!0)},describe:function(t){if(/\sedg\//i.test(t))return{name:i.ENGINE_MAP.Blink};var e=a.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,t);return{name:i.ENGINE_MAP.EdgeHTML,version:e}}},{test:[/trident/i],describe:function(t){var e={name:i.ENGINE_MAP.Trident},o=a.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){return t.test(/presto/i)},describe:function(t){var e={name:i.ENGINE_MAP.Presto},o=a.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:function(t){var e=t.test(/gecko/i),o=t.test(/like gecko/i);return e&&!o},describe:function(t){var e={name:i.ENGINE_MAP.Gecko},o=a.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:i.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(t){var e={name:i.ENGINE_MAP.WebKit},o=a.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,t);return o&&(e.version=o),e}}];e.default=r,t.exports=e.default}})},"./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss":(t,e,o)=>{"use strict";o.d(e,{A:()=>s});var n=o("./node_modules/css-loader/dist/runtime/noSourceMaps.js"),a=o.n(n),i=o("./node_modules/css-loader/dist/runtime/api.js"),r=o.n(i)()(a());r.push([t.id,'.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}',""]);const s=r},"./node_modules/css-loader/dist/runtime/api.js":t=>{"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var o="",n=void 0!==e[5];return e[4]&&(o+="@supports (".concat(e[4],") {")),e[2]&&(o+="@media ".concat(e[2]," {")),n&&(o+="@layer".concat(e[5].length>0?" ".concat(e[5]):""," {")),o+=t(e),n&&(o+="}"),e[2]&&(o+="}"),e[4]&&(o+="}"),o})).join("")},e.i=function(t,o,n,a,i){"string"==typeof t&&(t=[[null,t,void 0]]);var r={};if(n)for(var s=0;s0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=i),o&&(c[2]?(c[1]="@media ".concat(c[2]," {").concat(c[1],"}"),c[2]=o):c[2]=o),a&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=a):c[4]="".concat(a)),e.push(c))}},e}},"./node_modules/css-loader/dist/runtime/noSourceMaps.js":t=>{"use strict";t.exports=function(t){return t[1]}},"./node_modules/requestidlecallback-polyfill/index.js":()=>{window.requestIdleCallback=window.requestIdleCallback||function(t){var e=Date.now();return setTimeout((function(){t({didTimeout:!1,timeRemaining:function(){return Math.max(0,50-(Date.now()-e))}})}),1)},window.cancelIdleCallback=window.cancelIdleCallback||function(t){clearTimeout(t)}},"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":t=>{"use strict";var e=[];function o(t){for(var o=-1,n=0;n{"use strict";var e={};t.exports=function(t,o){var n=function(t){if(void 0===e[t]){var o=document.querySelector(t);if(window.HTMLIFrameElement&&o instanceof window.HTMLIFrameElement)try{o=o.contentDocument.head}catch(t){o=null}e[t]=o}return e[t]}(t);if(!n)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");n.appendChild(o)}},"./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js":(t,e,o)=>{"use strict";t.exports=function(t){var e=o.nc;e&&t.setAttribute("nonce",e)}},"./node_modules/style-loader/dist/runtime/styleDomAPI.js":t=>{"use strict";t.exports=function(t){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var e=t.insertStyleElement(t);return{update:function(o){!function(t,e,o){var n="";o.supports&&(n+="@supports (".concat(o.supports,") {")),o.media&&(n+="@media ".concat(o.media," {"));var a=void 0!==o.layer;a&&(n+="@layer".concat(o.layer.length>0?" ".concat(o.layer):""," {")),n+=o.css,a&&(n+="}"),o.media&&(n+="}"),o.supports&&(n+="}");var i=o.sourceMap;i&&"undefined"!=typeof btoa&&(n+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),e.styleTagTransform(n,t,e.options)}(e,t,o)},remove:function(){!function(t){if(null===t.parentNode)return!1;t.parentNode.removeChild(t)}(e)}}}},"./node_modules/style-loader/dist/runtime/styleTagTransform.js":t=>{"use strict";t.exports=function(t,e){if(e.styleSheet)e.styleSheet.cssText=t;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(t))}}},"./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js":t=>{t.exports=function(){return function(t){return t.styleTagTransform=function(t,e){e?.remove(),GM_addStyle(t)},document.createElement("style")}.apply(null,arguments)}},"./src/config/config.js":(t,e,o)=>{"use strict";o.d(e,{Cc:()=>s,JD:()=>l,K2:()=>c,Pm:()=>i,QL:()=>u,S7:()=>r,mE:()=>d,rl:()=>n,rw:()=>h,se:()=>a});const n="api.browser.yandex.ru",a="m3u8-proxy.toil.cc",i="vot.toil.cc",r="xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm",s="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36",l=.15,d="yandex",c="yandex",u={yandex:"https://translate.toil.cc/detect",rustServer:"https://rust-server-531j.onrender.com/detect"},h={yandex:"https://translate.toil.cc/translate"}},"./src/utils/debug.js":(t,e,o)=>{"use strict";o.d(e,{A:()=>a});const n={log:(...t)=>{}},a=n},"./src/yandexRequest.js":(t,e,o)=>{"use strict";o.r(e),o.d(e,{default:()=>i});var n=o("./src/config/config.js"),a=o("./src/utils/debug.js");const i=async function(t,e,o,i){try{a.A.log("yandexRequest:",t);const r={url:`https://${n.rl}${t}`,method:"POST",headers:{Accept:"application/x-protobuf","Accept-Language":"en","Content-Type":"application/x-protobuf","User-Agent":n.Cc,Pragma:"no-cache","Cache-Control":"no-cache","Sec-Fetch-Mode":"no-cors","sec-ch-ua":null,"sec-ch-ua-mobile":null,"sec-ch-ua-platform":null,...o},binary:!0,data:new Blob([e]),responseType:"arraybuffer"};GM_xmlhttpRequest({...r,onload:t=>{a.A.log("yandexRequest:",t.status,t),i(200===t.status,t.response)},onerror:t=>{console.error("[VOT]",t),i(!1)}})}catch(t){console.error("[VOT]",t),i(!1)}}}},e={};function o(n){var a=e[n];if(void 0!==a)return a.exports;var i=e[n]={id:n,exports:{}};return t[n].call(i.exports,i,i.exports,o),i.exports}o.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return o.d(e,{a:e}),e},o.d=(t,e)=>{for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.nc=void 0,(()=>{"use strict";const t=["invidious.snopyta.org","yewtu.be","invidious.kavin.rocks","vid.puffyan.us","invidious.namazso.eu","inv.riverside.rocks","yt.artemislena.eu","invidious.flokinet.to","invidious.esmailelbob.xyz","y.com.sb","invidious.nerdvpn.de","inv.vern.cc","invidious.slipfox.xyz","invidio.xamh.de","invidious.dhusch.de"],e=["piped.video","piped.tokhmi.xyz","piped.moomoo.me","piped.syncpundit.io","piped.mha.fi","watch.whatever.social","piped.garudalinux.org","efy.piped.pages.dev","watch.leptons.xyz","piped.lunar.icu","yt.dc09.ru","piped.mint.lgbt","il.ax","piped.privacy.com.de","piped.esmailelbob.xyz","piped.projectsegfau.lt","piped.in.projectsegfau.lt","piped.us.projectsegfau.lt","piped.privacydev.net","piped.palveluntarjoaja.eu","piped.smnz.de","piped.adminforge.de","piped.qdi.fi","piped.hostux.net","piped.chauvet.pro","piped.jotoma.de","piped.pfcd.me","piped.frontendfriendly.xyz"],n=["proxitok.pabloferreiro.es","proxitok.pussthecat.org","tok.habedieeh.re","proxitok.esmailelbob.xyz","proxitok.privacydev.net","tok.artemislena.eu","tok.adminforge.de","tik.hostux.net","tt.vern.cc","cringe.whatever.social","proxitok.lunar.icu","proxitok.privacy.com.de"],a=["peertube.1312.media","tube.shanti.cafe","bee-tube.fr","video.sadmin.io","dalek.zone","review.peertube.biz","peervideo.club","tube.la-dina.net","peertube.tmp.rcp.tf"];var i=o("./src/config/config.js");const r=["ru","en","zh","ko","lt","lv","ar","fr","it","es","de","ja"],s=["kk","bn","pt","cs","hi","mr","te","tr","ms","vi","ta","jv","ur","fa","gu","id","uk","da","fi","uz","pl","sv","az","sq","am","hy","af","eu","my","bg","bs","cy","hu","gl","el","zu","kn","ca","km","lo","mk","ml","mt","mn","ne","nl","pa","ro","sr","si","sk","sl","sw","su","hr","et"],l=["ru","en","kk"],d=["Violentmonkey","FireMonkey","Greasemonkey","AdGuard","OrangeMonkey"],c=JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}');var u=o("./src/utils/debug.js");const h=new class{constructor(){this.gmSupport="function"==typeof GM_getValue,u.A.log(`GM Storage Status: ${this.gmSupport}`)}syncGet(t,e=void 0,o=!1){if(this.gmSupport)return GM_getValue(t,e);let n=window.localStorage.getItem(t);if("udemyData"===t&&"string"==typeof n)try{n=JSON.parse(n)}catch{n=e}return o?Number(n)??Number(e):n??e}async get(t,e=void 0,o=!1){return this.gmSupport?await GM_getValue(t,e):Promise.resolve(this.syncGet(t,e,o))}syncSet(t,e){return this.gmSupport?GM_setValue(t,e):("udemyData"===t&&(e=JSON.stringify(e)),window.localStorage.setItem(t,e))}async set(t,e){return this.gmSupport?await GM_setValue(t,e):Promise.resolve(this.syncSet(t,e))}syncDelete(t){return this.gmSupport?GM_deleteValue(t):window.localStorage.removeItem(t)}async delete(t){return this.gmSupport?await GM_deleteValue(t):Promise.resolve(this.syncDelete(t))}syncList(){return this.gmSupport?GM_listValues():["autoTranslate","dontTranslateLanguage","dontTranslateYourLang","autoSetVolumeYandexStyle","showVideoSlider","syncVolume","subtitlesMaxLength","highlightWords","responseLanguage","defaultVolume","udemyData","audioProxy","showPiPButton","locale-version","locale-lang","locale-phrases"]}async list(){return this.gmSupport?await GM_listValues():Promise.resolve(this.syncList())}},p=["auto","en","ru","af","am","ar","az","bg","bn","bs","ca","cs","cy","da","de","el","es","et","eu","fa","fi","fr","gl","hi","hr","hu","hy","id","it","ja","jv","kk","km","kn","ko","lo","mk","ml","mn","ms","mt","my","ne","nl","pa","pl","pt","ro","si","sk","sl","sq","sr","su","sv","sw","tr","uk","ur","uz","vi","zh","zu"],g=new class{lang="en";locale={};gmValues=["locale-phrases","locale-lang","locale-version","locale-lang-override"];constructor(){const t=h.syncGet("locale-lang-override","auto");this.lang=t&&"auto"!==t?t:(navigator.language||navigator.userLanguage)?.substr(0,2)?.toLowerCase()??"en",this.setLocaleFromJsonString(h.syncGet("locale-phrases",""))}reset(){this.gmValues.forEach((t=>h.syncDelete(t)))}async update(t=!1){(t||2!==await h.get("locale-version",0,!0)||await h.get("locale-lang")!==this.lang)&&(u.A.log("Updating locale..."),await fetch(`https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/src/localization/locales/${this.lang}.json`).then((t=>{if(200===t.status)return t.text();throw t.status})).then((async t=>{await h.set("locale-phrases",t),this.setLocaleFromJsonString(t);const e=this.getFromLocale(this.locale,"__version__");"number"==typeof e&&await h.set("locale-version",e),await h.set("locale-lang",this.lang)})).catch((async t=>{console.error("[VOT] [localizationProvider] failed get locale, cause:",t),this.setLocaleFromJsonString(await h.get("locale-phrases",""))})))}setLocaleFromJsonString(t){try{this.locale=JSON.parse(t)??{}}catch(t){console.error("[VOT] [localizationProvider]",t),this.locale={}}}getFromLocale(t,e){const o=e.split(".").reduce(((t,e)=>{if("object"==typeof t&&t)return t[e]}),t);return void 0===o&&console.warn("[VOT] [localizationProvider] locale",t,"doesn't contain key",e),o}getDefault(t){return this.getFromLocale(c,t)??t}get(t){return this.getFromLocale(this.locale,t)??this.getFromLocale(c,t)??t}};var m=o("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"),v=o.n(m),b=o("./node_modules/style-loader/dist/runtime/styleDomAPI.js"),f=o.n(b),y=o("./node_modules/style-loader/dist/runtime/insertBySelector.js"),w=o.n(y),x=o("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"),S=o.n(x),k=o("./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js"),T=o.n(k),V=o("./node_modules/style-loader/dist/runtime/styleTagTransform.js"),M=o.n(V),L=o("./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss"),A={};A.styleTagTransform=M(),A.setAttributes=S(),A.insert=w().bind(null,"head"),A.domAPI=f(),A.insertStyleElement=T();v()(L.A,A);L.A&&L.A.locals&&L.A.locals;function P(t){const e=document.createElement("vot-block");return e.classList.add("vot-icon-button"),e.innerHTML=t,e}function E(t){const e=parseFloat(t.value),o=""===t.min?0:parseFloat(t.min),n=(e-o)/((""===t.max?100:parseFloat(t.max))-o);t.parentElement.setAttribute("style",`--vot-progress: ${n}`)}function O(t,e="",o=" ",n=!1){const a=document.createElement("vot-block");a.classList.add("vot-textfield");const i=document.createElement(n?"textarea":"input");i.placeholder=o,i.value=e;const r=document.createElement("span");return r.innerHTML=t,a.appendChild(i),a.appendChild(r),{container:a,input:i,label:r}}function C(t){const e=document.createElement("vot-block");e.classList.add("vot-dialog-container"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-dialog-backdrop");const n=document.createElement("vot-block");n.classList.add("vot-dialog");const a=document.createElement("vot-block");a.classList.add("vot-dialog-content-wrapper");const i=document.createElement("vot-block");i.classList.add("vot-dialog-header-container");const r=document.createElement("vot-block");r.classList.add("vot-dialog-body-container");const s=document.createElement("vot-block");s.classList.add("vot-dialog-footer-container");const l=document.createElement("vot-block");l.classList.add("vot-dialog-title-container");const d=P('');d.classList.add("vot-dialog-close-button"),o.onclick=d.onclick=()=>{e.hidden=!0};const c=document.createElement("vot-block");return c.classList.add("vot-dialog-title"),c.innerHTML=t,e.appendChild(o),e.appendChild(n),n.appendChild(a),a.appendChild(i),a.appendChild(r),a.appendChild(s),i.appendChild(l),i.appendChild(d),l.appendChild(c),{container:e,backdrop:o,dialog:n,contentWrapper:a,headerContainer:i,bodyContainer:r,footerContainer:s,titleContainer:l,closeButton:d,title:c}}function B(t,e,o,n={}){const a=n.onSelectCb||function(){},i=n.labelElement||"";let r=[];const s=document.createElement("vot-block");s.classList.add("vot-select"),i&&s.appendChild(i);const l=document.createElement("vot-block");l.classList.add("vot-select-outer");const d=document.createElement("span");d.classList.add("vot-select-title"),d.innerText=t,void 0===t&&(d.innerText=o.find((t=>!0===t.selected))?.label);const c=document.createElement("vot-block");c.classList.add("vot-select-arrow-icon"),c.innerHTML='',l.append(d,c),l.onclick=()=>{const t=C(e);t.container.classList.add("vot-dialog-temp"),t.container.hidden=!1,document.documentElement.appendChild(t.container);const n=document.createElement("vot-block");n.classList.add("vot-select-content-list");for(const t of o){const e=document.createElement("vot-block");e.classList.add("vot-select-content-item"),e.innerText=t.label,e.dataset.votSelected=t.selected,e.dataset.votValue=t.value,t.disabled&&(e.inert=!0),e.onclick=async i=>{if(i.target.inert)return;n.childNodes.forEach((t=>t.dataset.votSelected=!1)),o.forEach((e=>e.selected=e.value===t.value)),e.dataset.votSelected=!0,d.innerText=t.label,await a(i)},n.appendChild(e)}const i=O(g.get("searchField"));i.input.oninput=t=>{const e=t.target.value.toLowerCase();Array.from(r).forEach((t=>t.hidden=!t.innerText.toLowerCase().includes(e)))},t.bodyContainer.append(i.container,n),r=n.childNodes,t.backdrop.onclick=t.closeButton.onclick=()=>{t.container.remove(),r=[]}},s.append(l);return{container:s,title:d,arrowIcon:c,labelElement:i,setTitle:t=>{d.innerText=t},setSelected:t=>{Array.from(r).filter((t=>!t.inert)).forEach((e=>e.dataset.votSelected=e.dataset.votValue===t)),o.forEach((e=>e.selected=String(e.value)===t))},updateItems:t=>{o=t}}}const F={createHeader:function(t,e=4){const o=document.createElement("vot-block");return o.classList.add("vot-header"),o.classList.add(`vot-header-level-${e}`),o.innerHTML=t,o},createInformation:function(t,e){const o=document.createElement("vot-block");o.classList.add("vot-info");const n=document.createElement("vot-block");n.innerHTML=t;const a=document.createElement("vot-block");return a.innerHTML=e,o.appendChild(n),o.appendChild(a),{container:o,header:n,value:a}},createButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-button"),e.innerHTML=t,e},createTextButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-text-button"),e.innerHTML=t,e},createOutlinedButton:function(t){const e=document.createElement("vot-block");return e.classList.add("vot-outlined-button"),e.innerHTML=t,e},createIconButton:P,createCheckbox:function(t,e=!1){const o=document.createElement("label");o.classList.add("vot-checkbox");const n=document.createElement("input");n.type="checkbox",n.checked=Boolean(e);const a=document.createElement("span");return a.innerHTML=t,o.appendChild(n),o.appendChild(a),{container:o,input:n,label:a}},createSlider:function(t,e=50,o=0,n=100){const a=document.createElement("vot-block");a.classList.add("vot-slider");const i=document.createElement("input");i.type="range",i.min=o,i.max=n,i.value=e;const r=document.createElement("span");return r.innerHTML=t,a.appendChild(i),a.appendChild(r),i.addEventListener("input",(t=>E(t.target))),E(i),{container:a,input:i,label:r}},createTextfield:O,createDialog:C,createVOTButton:function(t){const e=document.createElement("vot-block");e.classList.add("vot-segmented-button");const o=document.createElement("vot-block");o.classList.add("vot-segment"),o.classList.add("vot-translate-button"),o.innerHTML='';const n=document.createElement("vot-block");n.classList.add("vot-separator");const a=document.createElement("vot-block");a.classList.add("vot-segment-only-icon"),a.innerHTML='';const i=document.createElement("vot-block");i.classList.add("vot-separator");const r=document.createElement("vot-block");r.classList.add("vot-segment-only-icon"),r.innerHTML='';const s=document.createElement("span");return s.classList.add("vot-segment-label"),s.innerHTML=t,e.appendChild(o),e.appendChild(n),e.appendChild(a),e.appendChild(i),e.appendChild(r),o.appendChild(s),{container:e,translateButton:o,separator:n,pipButton:a,separator2:i,menuButton:r,label:s}},createVOTMenu:function(t){const e=document.createElement("vot-block");e.classList.add("vot-menu"),e.hidden=!0;const o=document.createElement("vot-block");o.classList.add("vot-menu-content-wrapper");const n=document.createElement("vot-block");n.classList.add("vot-menu-header-container");const a=document.createElement("vot-block");a.classList.add("vot-menu-body-container");const i=document.createElement("vot-block");i.classList.add("vot-menu-footer-container");const r=document.createElement("vot-block");r.classList.add("vot-menu-title-container");const s=document.createElement("vot-block");return s.classList.add("vot-menu-title"),s.innerHTML=t,e.appendChild(o),o.appendChild(n),o.appendChild(a),o.appendChild(i),n.appendChild(r),r.appendChild(s),{container:e,contentWrapper:o,headerContainer:n,bodyContainer:a,footerContainer:i,titleContainer:r,title:s}},createVOTSelectLabel:function(t){const e=document.createElement("span");return e.classList.add("vot-select-label"),e.innerText=t,e},createVOTSelect:B,createVOTLanguageSelect:function(t){const e=t.fromTitle||"#UNDEFINED",o=t.fromDialogTitle||"#UNDEFINED",n=t.fromItems||[],a=t.fromOnSelectCB||function(){},i=t.toTitle||"#UNDEFINED",r=t.toDialogTitle||"#UNDEFINED",s=t.toItems||[],l=t.toOnSelectCB||function(){},d=document.createElement("vot-block");d.classList.add("vot-lang-select");const c=B(e,o,n,{onSelectCb:a}),u=document.createElement("vot-block");u.classList.add("vot-lang-select-icon"),u.innerHTML='';const h=B(i,r,s,{onSelectCb:l});return d.append(c.container,u,h.container),{container:d,fromSelect:c,icon:u,toSelect:h}},updateSlider:E};class _ extends Error{constructor(t){super(g.getDefault(t)),this.name="VOTLocalizedError",this.unlocalizedMessage=t,this.localizedMessage=g.get(t)}}async function R(t,e){const o=new AbortController,n=setTimeout((()=>o.abort()),3e3);try{return await fetch(t,{...e,signal:o.signal})}catch(t){return console.error("Fetch timed-out. Error:",t),t}finally{clearTimeout(n)}}const q={async translate(t,e){try{const o=await R(i.rw.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.text[0]}catch(e){return console.error("Error translating text:",e),t}},async detect(t,e){try{const o=await R(i.QL.yandex,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({text:t,lang:e})});if(o instanceof Error)throw o;const n=await o.json();if(200!==n.code)throw n.message;return n.lang??"en"}catch(t){return console.error("Error translating text:",t),"en"}}},D={async detect(t){try{const e=await fetch(i.QL.rustServer,{method:"POST",body:t});if(e instanceof Error)throw e;return await e.text()}catch(t){return console.error("Error getting lang from text:",t),"en"}}};const z=["yandex"],I=["yandex","rust-server"];async function $(t,e,o,n){if(!window.location.hostname.includes("m.youtube.com")&&t?.getAudioTrack){const e=t.getAudioTrack(),o=e?.getLanguageInfo();if("und"!==o?.id)return K(o.id.split(".")[0])}const a=e?.captions?.playerCaptionsTracklistRenderer?.captionTracks;if(a?.length){const t=a.find((t=>"asr"===t.kind));if(t&&t.languageCode)return K(t.languageCode)}const r=[/(?:https?|ftp):\/\/[\S]+/g,/https?:\/\/\S+|www\.\S+/gm,/\b\S+\.\S+/gm,/#[^\s#]+/g,/Auto-generated by YouTube/g,/Provided to YouTube by/g,/Released on/g,/Bitcoin/g,/USDT/g,/Paypal/g],s=[o,n.split("\n\n").filter((t=>!r.some((e=>e.test(t))))).join("\n\n")].join(" ").replace(/[^\p{L}\s]/gu," ").trim().replace(/\s+/g," ").slice(0,1e3);return await async function(t){switch(await h.get("detectService",i.K2)){case"yandex":return await q.detect(t);case"rust-server":return await D.detect(t);default:return"en"}}(s)}function N(){return/^m\.youtube\.com$/.test(window.location.hostname)}function H(){return window.location.pathname.startsWith("/shorts/")?N()?document.querySelector("#movie_player"):document.querySelector("#shorts-player"):document.querySelector("#movie_player")}function j(){const t=H();return t?.getPlayerResponse?t?.getPlayerResponse?.call()??null:t?.data?.playerResponse??null}function U(){const t=H();return t?.getVideoData?t?.getVideoData?.call()??null:t?.data?.playerResponse?.videoDetails??null}const W={isMobile:N,getPlayer:H,getPlayerResponse:j,getPlayerData:U,getVideoVolume:function(){const t=H();return t?.getVolume?t.getVolume.call()/100:1},getSubtitles:function(){const t=j();let e=t?.captions?.playerCaptionsTracklistRenderer?.captionTracks??[];return e=e.reduce(((t,e)=>{if("languageCode"in e){const o=e?.languageCode?K(e?.languageCode):void 0,n=e?.url||e?.baseUrl;o&&n&&t.push({source:"youtube",language:o,isAutoGenerated:"asr"===e?.kind,url:`${n.startsWith("http")?n:`${window.location.origin}/${n}`}&fmt=json3`})}return t}),[]),u.A.log("youtube subtitles:",e),e},getVideoData:async function(){const t=H(),e=j(),o=U(),{title:n}=o??{},{shortDescription:a,isLive:i,isLiveContent:s,isUpcoming:l}=e?.videoDetails??{},d=!(!i&&!l||s);let c=await $(t,e,n,a);r.includes(c)||(c="en");const h={isLive:!!i,isPremiere:d,title:n,description:a,detectedLanguage:c};return u.A.log("youtube video data:",h),console.log("[VOT] Detected language: ",h.detectedLanguage),h},setVideoVolume:function(t){const e=H();if(e?.setVolume)return e.setVolume(Math.round(100*t)),!0},videoSeek:function(t,e){u.A.log("videoSeek",e);const o=(H()?.getProgressState()?.seekableEnd||t.currentTime)-e;t.currentTime=o}},G=navigator.language||navigator.userLanguage,Y=G?.substr(0,2)?.toLowerCase()??"en",Z=(t,e)=>{let o=new URL(window.location.href);switch(t){case"piped":case"invidious":case"youtube":if(o.searchParams.has("enablejsapi")){const t=W.getPlayer().getVideoUrl();o=new URL(t)}return o.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1]||o.searchParams.get("v");case"vk":return o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)?o.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1):o.searchParams.get("z")?o.searchParams.get("z").split("/")[0]:!(!o.searchParams.get("oid")||!o.searchParams.get("id"))&&`video-${Math.abs(o.searchParams.get("oid"))}_${o.searchParams.get("id")}`;case"nine_gag":case"9gag":case"gag":return o.pathname.match(/gag\/([^/]+)/)?.[1];case"twitch":if(/^m\.twitch\.tv$/.test(window.location.hostname)){const t=document.head.querySelector('link[rel="canonical"]');return t?.href.match(/videos\/([^/]+)/)?.[0]||o.pathname.slice(1)}if(/^player\.twitch\.tv$/.test(window.location.hostname))return`videos/${o.searchParams.get("video")}`;if(/^clips\.twitch\.tv$/.test(window.location.hostname)){const t=document.querySelector(".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']");if(!t)return!1;return`${t.href.replace("https://www.twitch.tv/","")}/clip/${o.searchParams.get("clip")}`}return o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)?o.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]:o.pathname.match(/(?:videos)\/([^/]+)/)?.[0];case"proxytok":return o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];case"tiktok":{let t=o.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0];if(!t){const o=e.closest(".xgplayer-playing, .tiktok-web-player"),n=o?.closest('div[data-e2e="recommend-list-item-container"]'),a=n?.querySelector('a[data-e2e="video-author-avatar"]');if(o&&a){const e=o.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1),n=a.href?.match(/.*(@.*)$/)?.at(1);e&&n&&(t=`${n}/video/${e}`)}}return t}case"vimeo":{const t=o.searchParams.get("app_id"),e=o.pathname.match(/[^/]+\/[^/]+$/)?.[0]||o.pathname.match(/[^/]+$/)?.[0];return t?`${e}?app_id=${t}`:e}case"xvideos":return o.pathname.match(/[^/]+\/[^/]+$/)?.[0];case"pornhub":return o.searchParams.get("viewkey")||o.pathname.match(/embed\/([^/]+)/)?.[1];case"twitter":return o.pathname.match(/status\/([^/]+)/)?.[1];case"udemy":case"rumble":case"facebook":return o.pathname;case"rutube":return o.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1];case"coub":return o.pathname.includes("/view")?o.pathname.match(/view\/([^/]+)/)?.[1]:o.pathname.includes("/embed")?o.pathname.match(/embed\/([^/]+)/)?.[1]:document.querySelector(".coub.active")?.dataset?.permalink;case"bilibili":{const t=o.searchParams.get("bvid");if(t)return t;{let t=o.pathname.match(/video\/([^/]+)/)?.[1];return t&&o.search&&null!==o.searchParams.get("p")&&(t+=`/?p=${o.searchParams.get("p")}`),t}}case"mail_ru":if(o.pathname.startsWith("/v/")||o.pathname.startsWith("/mail/"))return o.pathname;if(o.pathname.match(/video\/embed\/([^/]+)/)){const t=document.querySelector(".b-video-controls__mymail-link");return!!t&&t?.href.split("my.mail.ru")?.[1]}return!1;case"bitchute":return o.pathname.match(/video\/([^/]+)/)?.[1];case"coursera":return o.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0];case"eporner":return o.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0];case"peertube":return o.pathname.match(/\/w\/([^/]+)/)?.[0];case"dailymotion":{const t=Array.from(document.querySelectorAll("*")).filter((t=>t.innerHTML.trim().includes(".m3u8")));try{let e=t[1].lastChild.src;return e.match(/\/video\/(\w+)\.m3u8/)?.[1]}catch(t){return console.error("[VOT]",t),!1}}case"trovo":{if(!o.pathname.startsWith("/s/"))return!1;const t=o.searchParams.get("vid");if(!t)return!1;const e=o.pathname.match(/([^/]+)\/([\d]+)/)?.[0];return!!e&&`${e}?vid=${t}`}case"yandexdisk":return o.pathname.match(/\/i\/([^/]+)/)?.[1];case"coursehunter":{const t=o.pathname.match(/\/course\/([^/]+)/)?.[1];return!!t&&t+o.search}case"ok.ru":return o.pathname.match(/\/video\/(\d+)/)?.[0];case"googledrive":return o.searchParams.get("docid");case"bannedvideo":return o.searchParams.get("id");case"weverse":return o.pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[0];case"newgrounds":return o.pathname.match(/([^/]+)\/(view)\/([^/]+)/)?.[0];case"egghead":return o.pathname;case"youku":return o.pathname.match(/v_show\/id_[\w=]+/)?.[0];default:return!1}};function K(t){return t.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]}function J(){return"pictureInPictureEnabled"in document&&document.pictureInPictureEnabled}function Q(){return"undefined"!=typeof Hls&&Hls?.isSupported()?new Hls({debug:!1,lowLatencyMode:!0,backBufferLength:90}):void 0}function X(t,e,o,n){let a=e;return e>n?(a=o+(e-n),a=a>100?100:Math.max(a,0),t.volume=a/100):e100?100:Math.max(a,0),t.volume=a/100),a}const tt=new protobuf.Type("VideoTranslationHelpObject").add(new protobuf.Field("target",1,"string")).add(new protobuf.Field("targetUrl",2,"string")),et=new protobuf.Type("VideoTranslationRequest").add(new protobuf.Field("url",3,"string")).add(new protobuf.Field("deviceId",4,"string")).add(new protobuf.Field("firstRequest",5,"bool")).add(new protobuf.Field("duration",6,"double")).add(new protobuf.Field("unknown2",7,"int32")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("unknown3",9,"int32")).add(new protobuf.Field("unknown4",10,"int32")).add(new protobuf.Field("translationHelp",11,"VideoTranslationHelpObject","repeated")).add(new protobuf.Field("responseLanguage",14,"string")).add(new protobuf.Field("unknown5",15,"int32")).add(new protobuf.Field("unknown6",16,"int32")).add(new protobuf.Field("unknown7",17,"int32")),ot=new protobuf.Type("VideoSubtitlesRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")),nt=new protobuf.Type("VideoStreamRequest").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("language",2,"string")).add(new protobuf.Field("responseLanguage",3,"string")),at=new protobuf.Type("VideoStreamPingRequest").add(new protobuf.Field("pingId",1,"int32")),it=new protobuf.Type("VideoTranslationResponse").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("duration",2,"double")).add(new protobuf.Field("status",4,"int32")).add(new protobuf.Field("remainingTime",5,"int32")).add(new protobuf.Field("unknown0",6,"int32")).add(new protobuf.Field("unknown1",7,"string")).add(new protobuf.Field("language",8,"string")).add(new protobuf.Field("message",9,"string")),rt=new protobuf.Type("VideoSubtitlesObject").add(new protobuf.Field("language",1,"string")).add(new protobuf.Field("url",2,"string")).add(new protobuf.Field("unknown2",3,"int32")).add(new protobuf.Field("translatedLanguage",4,"string")).add(new protobuf.Field("translatedUrl",5,"string")).add(new protobuf.Field("unknown5",6,"int32")).add(new protobuf.Field("unknown6",7,"int32")),st=new protobuf.Type("VideoSubtitlesResponse").add(new protobuf.Field("unknown0",1,"int32")).add(new protobuf.Field("subtitles",2,"VideoSubtitlesObject","repeated")),lt=new protobuf.Type("VideoStreamObject").add(new protobuf.Field("url",1,"string")).add(new protobuf.Field("timestamp",2,"int64")),dt=new protobuf.Type("VideoStreamResponse").add(new protobuf.Field("interval",1,"int32")).add(new protobuf.Field("translatedInfo",2,"VideoStreamObject")).add(new protobuf.Field("pingId",3,"int32")),ct=(new protobuf.Root).define("yandex").add(tt).add(et).add(it).add(ot).add(rt).add(st).add(at).add(nt).add(lt).add(dt),ut={encodeTranslationRequest:(t,e,o,n,a)=>ct.VideoTranslationRequest.encode({url:t,firstRequest:!0,duration:e,unknown2:1,language:o,unknown3:0,unknown4:0,translationHelp:a,responseLanguage:n,unknown5:0,unknown6:1,unknown7:0}).finish(),decodeTranslationResponse:t=>ct.VideoTranslationResponse.decode(new Uint8Array(t)),encodeSubtitlesRequest:(t,e)=>ct.VideoSubtitlesRequest.encode({url:t,language:e}).finish(),decodeSubtitlesResponse:t=>ct.VideoSubtitlesResponse.decode(new Uint8Array(t)),encodeStreamPingRequest:t=>ct.VideoStreamPingRequest.encode({pingId:t}).finish(),encodeStreamRequest:(t,e,o)=>ct.VideoStreamRequest.encode({url:t,language:e,responseLanguage:o}).finish(),decodeStreamResponse:t=>ct.VideoStreamResponse.decode(new Uint8Array(t))};var ht=o("./node_modules/bowser/es5.js");function pt(t){const e=([1e7]+1e3+4e3+8e3+1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16)));return t?e:e.toUpperCase()}async function gt(t){const e=new TextEncoder("utf-8"),o=await window.crypto.subtle.importKey("raw",e.encode(i.S7),{name:"HMAC",hash:{name:"SHA-256"}},!1,["sign","verify"]),n=await window.crypto.subtle.sign("HMAC",o,t);return Array.from(new Uint8Array(n),(t=>t.toString(16).padStart(2,"0"))).join("")}const mt=async function(t,e){try{u.A.log("requestStreamPing");const n=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;u.A.log("Inited yandexRequest...");const a=ut.encodeStreamPingRequest(t);await n("/stream-translation/ping-stream",a,{"Vtrans-Signature":await gt(a),"Sec-Vtrans-Token":pt(!1)},e)}catch(t){console.error("[VOT]",t),e(!1)}};const vt=async function(t,e,n,a){try{u.A.log("requestStreamTranslation");const i=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;u.A.log("Inited yandexRequest...");const r=ut.encodeStreamRequest(t,e,n);await i("/stream-translation/translate-stream",r,{"Vtrans-Signature":await gt(r),"Sec-Vtrans-Token":pt(!1)},a)}catch(t){console.error("[VOT]",t),a(!1)}};const bt=async function(t,e,n,a,i,r){try{u.A.log("requestVideoTranslation");const s=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;u.A.log("Inited yandexRequest...");const l=ut.encodeTranslationRequest(t,e,n,a,i);await s("/video-translation/translate",l,{"Vtrans-Signature":await gt(l),"Sec-Vtrans-Token":pt(!1)},r)}catch(t){console.error("[VOT]",t),r(!1)}};const ft=async function(t,e,n){try{u.A.log("requestVideoSubtitles");const a=(await Promise.resolve().then(o.bind(o,"./src/yandexRequest.js"))).default;u.A.log("Inited yandexRequest...");const i=ut.encodeSubtitlesRequest(t,e);await a("/video-subtitles/get-subtitles",i,{"Vsubs-Signature":await gt(i),"Sec-Vsubs-Token":pt(!1)},n)}catch(t){console.error("[VOT]",t),n(!1)}};function yt(t){const e=t.startMs+t.durationMs;return t.tokens.reduce(((o,n,a)=>{const i=t.tokens[a+1];let r;o.length>0&&(r=o[o.length-1]);const s=r?.alignRange?.end??0,l=s+n.text.length;if(n.alignRange={start:s,end:l},o.push(n),i){const t=n.startMs+n.durationMs,a=i.startMs?i.startMs-t:e-t;o.push({text:" ",startMs:t,durationMs:a,alignRange:{start:l,end:l+1}})}return o}),[])}function wt(t,e){const o=t.text.split(/([\n \t])/).reduce(((t,o)=>{if(o.length){const n=t[t.length-1]??e,a=n?.alignRange?.end??0,i=a+o.length;t.push({text:o,alignRange:{start:a,end:i}})}return t}),[]),n=Math.floor(t.durationMs/o.length),a=t.startMs+t.durationMs;return o.map(((e,i)=>{const r=i===o.length-1,s=t.startMs+n*i;return{...e,startMs:s,durationMs:r?a-s:n}}))}async function xt(t){let e=!1,o=await Promise.race([new Promise((t=>{setTimeout((()=>{e||(console.error("[VOT] Failed to fetch subtitles. Reason: timeout"),t([]))}),5e3)})),new Promise((o=>{u.A.log("Fetching subtitles:",t),fetch(t.url).then((t=>t.json())).then((t=>{e=!0,o(t)})).catch((t=>{console.error("[VOT] Failed to fetch subtitles. Reason:",t),e=!0,o({containsTokens:!1,subtitles:[]})}))}))]);return"youtube"===t.source&&(o=function(t){const e={containsTokens:!1,subtitles:[]};if("object"!=typeof t||!("events"in t)||!Array.isArray(t.events))return console.error("[VOT] Failed to format youtube subtitles",t),e;for(let o=0;ot.utf8.replace(/^ +| +$/g,""))).join(" ");let a=t.events[o].dDurationMs;t.events[o+1]&&t.events[o].tStartMs+t.events[o].dDurationMs>t.events[o+1].tStartMs&&(a=t.events[o+1].tStartMs-t.events[o].tStartMs),"\n"!==n&&e.subtitles.push({text:n,startMs:t.events[o].tStartMs,durationMs:a})}return e}(o)),o.subtitles=function(t,e){const o=[];let n;for(const a of t.subtitles){let i;if(a?.tokens?.length){if("yandex"!==e)return console.warn("[VOT] Unsupported subtitles tokens type: ",e),t.containsTokens=!1,null;i=yt(a)}else i=wt(a,n);n=i[i.length-1],o.push({...a,tokens:i})}return t.containsTokens=!0,o}(o,t.source),console.log("[VOT] subtitles:",o),o}class St{dragging=!1;subtitlesContainerRect=null;containerRect=null;offsetX=null;offsetY=null;lastContent=null;highlightWords=!1;subtitles=null;maxLength=300;maxLengthRegexp=/.{1,300}(?:\s|$)/g;constructor(t,e,o){this.site=o,this.video=t,"youtube"===this.site.host&&"mobile"!==this.site.additionalData?this.container=e.parentElement:this.container=e,this.votSubtitlesContainer=document.createElement("vot-block"),this.votSubtitlesContainer.classList.add("vot-subtitles-widget"),this.container.appendChild(this.votSubtitlesContainer),this.onMouseDownBound=this.onMouseDown.bind(this),this.onMouseUpBound=this.onMouseUp.bind(this),this.onMouseMoveBound=this.onMouseMove.bind(this),this.onTimeUpdateBound=this.onTimeUpdate.bind(this),document.addEventListener("mousedown",this.onMouseDownBound),document.addEventListener("mouseup",this.onMouseUpBound),document.addEventListener("mousemove",this.onMouseMoveBound),this.video?.addEventListener("timeupdate",this.onTimeUpdateBound)}release(){this.video?.removeEventListener("timeupdate",this.onTimeUpdateBound),document.removeEventListener("mousedown",this.onMouseDownBound),document.removeEventListener("mouseup",this.onMouseUpBound),document.removeEventListener("mousemove",this.onMouseMoveBound),this.votSubtitlesContainer.remove()}onMouseDown(t){this.votSubtitlesContainer.contains(t.target)&&(this.subtitlesContainerRect=this.votSubtitlesContainer.getBoundingClientRect(),this.containerRect=this.container.getBoundingClientRect(),this.offsetX=t.clientX-this.subtitlesContainerRect.x,this.offsetY=t.clientY-this.subtitlesContainerRect.y,this.dragging=!0)}onMouseUp(){this.dragging=!1}onMouseMove(t){if(this.dragging){t.preventDefault();const e=t.clientX-this.offsetX,o=t.clientY-this.offsetY,n=o>=this.containerRect.top,a=o+this.subtitlesContainerRect.height<=this.containerRect.bottom,i=e>=this.containerRect.left,r=e+this.subtitlesContainerRect.width<=this.containerRect.right;this.votSubtitlesContainer.style.top=n&&a?o-this.containerRect.y+"px":n?this.containerRect.height-this.subtitlesContainerRect.height+"px":"0px",this.votSubtitlesContainer.style.left=i&&r?e-this.containerRect.x+"px":i?this.containerRect.width-this.subtitlesContainerRect.width+"px":"0px"}}onTimeUpdate(){this.update()}setContent(t){t&&this.video?(this.subtitles=t,this.update()):(this.subtitles=null,this.votSubtitlesContainer.innerHTML="")}setMaxLength(t){"number"==typeof t&&t&&(this.maxLength=t,this.maxLengthRegexp=new RegExp(`.{1,${t}}(?:\\s|$)`,"g"),this.update())}setHighlightWords(t){this.highlightWords!==!!t&&(this.highlightWords=!!t,this.update())}update(){if(!this.video)return;let t="",e=this.highlightWords&&this.subtitles?.containsTokens;const o=1e3*this.video.currentTime,n=this.subtitles?.subtitles?.findLast((t=>t.startMsthis.maxLength){let t=[],n=0,a=0,i=0;for(let o=0;othis.maxLength){let r=e.slice(n,a+1);r.at(0)&&" "===r.at(0).text&&(r=r.slice(1)),r.at(-1)&&" "===r.at(-1).text&&(r=r.slice(0,r.length-1)),t.push({startMs:e[n].startMs,durationMs:e[a].startMs+e[a].durationMs-e[n].startMs,tokens:r}),n=o,i=0}a=o}for(const n of t)if(n.startMse||o>n.startMs-100&&e-o<275?'class="passed"':""}>${n.text}`}}else if(n.text.length>this.maxLength){let e=n.text.match(this.maxLengthRegexp),a=n.durationMs/e.length;for(let i=0;i${t.replace("\\n","
")}`:"")}}const kt={getVideoData:async function(){const t=window.course_id??document.querySelector('input[name="course_id"]')?.value,e=window.lessons??await async function(t){const e=await fetch(`https://coursehunter.net/api/v1/course/${t}/lessons`);return await e.json()}(t),o=parseInt(document.querySelector(".lessons-item_active")?.dataset?.index??1),n=e?.[o-1],{file:a,duration:i}=n;return u.A.log("coursehunter course data:",e),{url:a,duration:i}}};function Tt(){return Vt()?.player}function Vt(){return document.querySelector(".vjs-v6")}const Mt={getPlayer:Vt,getPlayerData:Tt,getVideoData:async function(t="en"){let e=null;const o=Tt(),{duration:n}=o?.cache_||{},{courseId:a,tracks:i,sources:s}=o?.options_||{},l=function(t){const e=t?.find((t=>"video/mp4"===t.type));return e?.src}(s),d=await async function(t){const e=await fetch(`https://www.coursera.org/api/onDemandCourses.v1/${t}`),o=await e.json();return o?.elements?.[0]}(a);let c=d?.primaryLanguageCodes?.[0];c=c?K(c):"en",r.includes(c)||(c="en");const h=function(t,e,o){let n=t?.find((t=>K(t.srclang)===e));return n||(n=t?.find((t=>K(t.srclang)===o))||t?.[0]),n?.src}(i,c,t);console.log(`videoURL: ${l}, subtitlesURL: ${h}`),h&&l?e=[{target:"video_file_url",targetUrl:l},{target:"subtitles_file_url",targetUrl:`https://www.coursera.org${h}`}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${l}, subtitlesURL: ${h}`);const p={duration:n,detectedLanguage:c,translationHelp:e};return u.A.log("coursera video data:",p),console.log("[VOT] Detected language: ",p.detectedLanguage),p}},Lt="https://www.udemy.com/api-2.0",At=2592e6;async function Pt(t){const e=await fetch(`${Lt}/courses/${t}/?`+new URLSearchParams({"fields[course]":"locale",use_remote_version:"true",caching_intent:"true"}));return await e.json()}async function Et(t,e,o){if(!(n=t.expires,n+At>(new Date).getTime()&&t.accessToken))return void console.error(g.get("udemyAccessTokenExpired"));var n;const a=`Bearer ${t.accessToken}`,i=await fetch(`${Lt}/users/me/subscribed-courses/${e}/lectures/${o}/?`+new URLSearchParams({"fields[lecture]":"asset","fields[asset]":"length,media_sources,captions"}),{headers:{"x-udemy-authorization":a,authorization:a}});return await i.json()}function Ot(){return Bt()?.player}function Ct(){const t=document.querySelector(".ud-app-loader[data-module-id='course-taking']")?.dataset?.moduleArgs;return t?JSON.parse(t):(console.error(g.get("udemyModuleArgsNotFound")),{})}function Bt(){return document.querySelector(".vjs-v7")}const Ft={getPlayer:Bt,getPlayerData:Ot,getVideoData:async function(t,e="en"){let o=null;const n=Ot();u.A.log("udemyData",t);const a=Ct();u.A.log("moduleData: ",a);const i=a.courseId,s=window.location.pathname.match(/learn\/lecture\/([^/]+)/)?.[1];u.A.log(`CourseId: ${i}, lectureId: ${s}`);const l=await Pt(i);u.A.log("courseLang Data:",l);const d=await Et(t,i,s);console.log("lecture Data:",d);let c=l?.locale?.locale;c=c?K(c):"en",r.includes(c)||(c="en");const h=d?.asset?.length||n?.cache_?.duration,p=function(t){const e=t?.find((t=>"video/webm"===t.type||"video/mp4"===t.type));return e?.src}(d?.asset?.media_sources)||function(){const t=Bt()?.querySelector("video")?.src;return!t?.startsWith("blob:")&&t}(),g=function(t,e,o){let n=t?.find((t=>K(t.locale_id)===e));return n||(n=t?.find((t=>K(t.locale_id)===o))||t?.[0]),n?.url}(d?.asset?.captions,c,e);console.log(`videoURL: ${p}, subtitlesURL: ${g}`),g&&p?o=[{target:"video_file_url",targetUrl:p},{target:"subtitles_file_url",targetUrl:g}]:console.error(`Failed to find subtitlesURL or videoURL. videoURL: ${p}, subtitlesURL: ${g}`);const m={duration:h,detectedLanguage:c,translationHelp:o};return u.A.log("udemy video data:",m),console.log("[VOT] Detected language: ",m.detectedLanguage),m},getModuleData:Ct,getCourseLang:Pt,getLectureData:Et};const _t={getVideoData:async function(t){const e=await async function(t){return await fetch("https://api.banned.video/graphql",{method:"POST",body:JSON.stringify({operationName:"GetVideo",query:"query GetVideo($id: String!) {\n getVideo(id: $id) {\n ...DisplayVideoFields\n videoUrl: directUrl\n live\n }\n }\n\n fragment DisplayVideoFields on Video {\n title\n description: summary\n duration: videoDuration\n }",variables:{id:t}}),headers:{"User-Agent":"bannedVideoFrontEnd","apollographql-client-name":"banned-web","apollographql-client-version":"1.3","content-type":"application/json"}}).then((t=>t.json())).catch((t=>(console.error(t),{data:{getVideo:{}}})))}(t);u.A.log("banned.video video data:",e);const{videoUrl:o,duration:n,live:a,description:i,title:r}=e.data.getVideo;return{url:o,duration:n,live:a,title:r,description:i}}};const Rt="https://global.apis.naver.com/weverse/wevweb",qt="be4d79eb8fc7bd008ee82c8ec4ff6fd4",Dt="1b9cb6378d959b45714bec49971ade22e6e24e42";async function zt(t){const e=Date.now();let o=t.substring(0,Math.min(255,t.length))+e;const n=await async function(t,e){const o=new TextEncoder("utf-8");return e=o.encode(e),window.crypto.subtle.importKey("raw",o.encode(t),{name:"HMAC",hash:{name:"SHA-1"}},!1,["sign","verify"]).then((t=>window.crypto.subtle.sign("HMAC",t,e))).then((t=>btoa(String.fromCharCode(...new Uint8Array(t))))).catch((t=>(console.error(t),!1)))}(Dt,o);return{wmsgpad:e,wmd:n}}function It(){return{appId:qt,language:"en",os:"WEB",platform:"WEB",wpf:"pc"}}const $t={getVideoData:async function(){const t=new URL(window.location).pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[3],e=await async function(t){const e=`/post/v1.0/post-${t}/preview?`+new URLSearchParams({fieldSet:"postForPreview",...It()}),o=await zt(e);return await fetch(Rt+e+"&"+new URLSearchParams(o)).then((t=>t.json())).catch((t=>(console.error(t),{extension:{video:{}}})))}(t);u.A.log("weverse video preview data:",e);const{videoId:o,serviceId:n,infraVideoId:a}=e.extension.video;if(!(o&&n&&a))return!1;const{inKey:i}=await async function(t){const e=`/video/v1.1/vod/${t}/inKey?`+new URLSearchParams({gcc:"RU",...It()}),o=await zt(e);return await fetch(Rt+e+"&"+new URLSearchParams(o),{method:"POST"}).then((t=>t.json())).catch((t=>(console.error(t),{})))}(o);if(u.A.log("weverse video inKey data:",e),!i)return!1;const r=await async function(t,e,o){const n=Date.now();return await fetch(`https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${t}?`+new URLSearchParams({key:e,sid:o,nonce:n,devt:"html5_pc",prv:"N",aup:"N",stpb:"N",cpl:"en",env:"prod",lc:"en",adi:[{adSystem:null}],adu:"/"})).then((t=>t.json())).catch((t=>(console.error(t),{videos:{list:[]}})))}(a,i,n);u.A.log("weverse video data:",r);const s=r.videos.list.find((t=>!1===t.useP2P&&t.source.includes(".mp4")));if(!s)return!1;const{source:l,duration:d}=s;return{url:l,duration:d}}},Nt=[{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:"shorts-video #player"},{additionalData:"mobile",host:"youtube",url:"https://youtu.be/",match:/^m.youtube(-nocookie)?.com$/,selector:".player-container"},{host:"youtube",url:"https://youtu.be/",match:/^(www.)?youtube(-nocookie|kids)?.com$/,selector:".html5-video-container:not(#inline-player *)"},{host:"tiktok",url:"https://www.tiktok.com/",match:/^(www.)?tiktok.com$/,selector:null},{host:"proxytok",url:"https://www.tiktok.com/",match:n,selector:".column.has-text-centered"},{additionalData:"mobile",host:"twitch",url:"https://twitch.tv/",match:/^m.twitch.tv$/,selector:"main > div > section > div > div > div"},{host:"twitch",url:"https://twitch.tv/",match:t=>t.host.includes("clips.twitch.tv")||t.host.includes("player.twitch.tv")&&null===t.searchParams.get("channel")||t.host.includes("twitch.tv")&&(t.pathname.startsWith("/videos")||t.pathname.startsWith("/embed")||t.pathname.includes("/clip")),selector:".video-ref"},{host:"xvideos",url:"https://www.xvideos.com/",match:/^www.xvideos.com$/,selector:".video-bg-pic"},{host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:/^[a-z]+.pornhub.com$/,selector:".mainPlayerDiv > .video-element-wrapper-js > div"},{additionalData:"embed",host:"pornhub",url:"https://rt.pornhub.com/view_video.php?viewkey=",match:t=>t.host.includes("pornhub.com")&&t.pathname.startsWith("/embed/"),selector:"#player"},{additionalData:"mobile",host:"vk",url:"https://vk.com/video?z=",match:/^m.vk.(com|ru)$/,selector:"vk-video-player",shadowRoot:!0},{host:"vk",url:"https://vk.com/video?z=",match:/^(www.|m.)?vk.(com|ru)$/,selector:".videoplayer_media"},{host:"vimeo",url:"https://vimeo.com/",match:/^vimeo.com$/,selector:".player"},{additionalData:"embed",host:"vimeo",url:"https://player.vimeo.com/",match:/^player.vimeo.com$/,selector:".player"},{host:"ok.ru",url:"https://ok.ru/",match:/^ok.ru$/,selector:".html5-vpl_vid"},{host:"nine_gag",url:"https://9gag.com/gag/",match:/^9gag.com$/,selector:".video-post"},{host:"coub",url:"https://coub.com/view/",match:/^coub.com$/,selector:".viewer__player"},{host:"bitchute",url:"https://www.bitchute.com/video/",match:/^(www.)?bitchute.com$/,selector:"#player"},{host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:".video-player > div > div > div:nth-child(2)"},{additionalData:"embed",host:"rutube",url:"https://rutube.ru/video/",match:/^rutube.ru$/,selector:"#app > div > div"},{host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m|player).bilibili.com$/,selector:".bpx-player-video-wrap"},{additionalData:"old",host:"bilibili",url:"https://www.bilibili.com/video/",match:/^(www|m).bilibili.com$/,selector:null},{host:"twitter",url:"https://twitter.com/i/status/",match:/^twitter.com$/,selector:'div[data-testid="videoComponent"] > div:nth-child(1) > div'},{host:"mail_ru",url:"https://my.mail.ru/",match:/^my.mail.ru$/,selector:"#b-video-wrapper"},{host:"coursera",url:"https://www.coursera.org/",match:/coursera.org$/,selector:".vjs-v6"},{host:"udemy",url:"https://www.udemy.com",match:/udemy.com$/,selector:'div[data-purpose="curriculum-item-viewer-content"] > section > div > div > div > div:nth-of-type(2)'},{host:"invidious",url:"https://youtu.be/",match:t,selector:"#player"},{host:"piped",url:"https://youtu.be/",match:e,selector:".shaka-video-container"},{host:"rumble",url:"https://rumble.com",match:/^rumble.com$/,selector:"#videoPlayer > .videoPlayer-Rumble-cls > div"},{host:"eporner",url:"https://www.eporner.com/",match:/^(www.)?eporner.com$/,selector:".vjs-v7"},{host:"peertube",url:"tube.shanti.cafe",match:a,selector:".vjs-v7"},{host:"dailymotion",url:"https://www.dailymotion.com/video/",match:/^geo.dailymotion.com$/,selector:".player"},{host:"trovo",url:"https://trovo.live/s/",match:/^trovo.live$/,selector:".player-video"},{host:"yandexdisk",url:"https://disk.yandex.ru/i/",match:/^disk.yandex.ru$/,selector:"yaplayertag > div:nth-of-type(1)"},{host:"coursehunter",url:"https://coursehunter.net/course/",match:/^coursehunter.net$/,selector:"#oframeplayer > pjsdiv:nth-of-type(1)"},{host:"googledrive",url:"https://drive.google.com/file/d/",match:/^youtube.googleapis.com$/,selector:".html5-video-container"},{host:"bannedvideo",url:"https://banned.video/watch?id=",match:/^(www.)?banned.video$/,selector:".vjs-v7"},{host:"facebook",url:"https://facebook.com",match:t=>t.host.includes("facebook.com")&&t.pathname.includes("/videos/"),selector:'div[data-pagelet="WatchPermalinkVideo"]'},{additionalData:"reels",host:"facebook",url:"https://facebook.com",match:t=>t.host.includes("facebook.com")&&t.pathname.includes("/reel/"),selector:'div[role="main"]'},{host:"weverse",url:"https://weverse.io/",match:/^weverse.io$/,selector:".webplayer-internal-source-wrapper"},{host:"newgrounds",url:"https://www.newgrounds.com/",match:/^www.newgrounds.com$/,selector:".ng-video-player"},{host:"egghead",url:"https://egghead.io",match:/^egghead.io$/,selector:".cueplayer-react-video-holder"},{host:"youku",url:"https://v.youku.com/",match:/^v.youku.com$/,selector:"#ykPlayer"}];o("./node_modules/requestidlecallback-polyfill/index.js");class Ht{constructor(){this.listeners=new Set}hasListener(t){return this.listeners.has(t)}dispatchToListener(t,...e){try{t(...e)}catch(t){console.error("[VOT]",t)}}addListener(t){if(this.hasListener(t))throw new Error("[VOT] The listener has already been added.");this.listeners.add(t)}removeListener(t){if(!this.hasListener(t))throw new Error("[VOT] The listener has not been added yet.");this.listeners.delete(t)}dispatch(...t){for(const e of Array.from(this.listeners))this.dispatchToListener(e,...t)}}function jt(t){return Array.from(t).flatMap((t=>t instanceof HTMLVideoElement?[t]:t instanceof HTMLElement?Array.from(t.querySelectorAll("video")):t.shadowRoot?Array.from(t.shadowRoot.querySelectorAll("video")):[]))}const Ut=ht.getParser(window.navigator.userAgent).getResult(),Wt=[...t,...e],Gt=["playing","ratechange","play","waiting","pause"];function Yt(t,e,o=!1){return t.map((t=>({label:`${o&&!l.includes(t)?"❌ ":""}${g.get("langs")[t]??t.toUpperCase()}`,value:t,selected:e===t})))}function Zt(t,e,o,n,a,i){u.A.log(`Translate video (url: ${t}, duration: ${e}, requestLang: ${o}, responseLang: ${n})`),u.A.log("translationHelp:",a),!0,bt(t,e,o,n,a,((t,e)=>{if(!1,u.A.log("[exec callback] Requesting video translation"),!t)return void i(!1,g.get("requestTranslationFailed"));const o=ut.decodeTranslationResponse(e);switch(console.log("[VOT] Translation response: ",o),o.status){case 0:i(!1,o.message);break;case 1:i(!!o.url,o.url||g.get("audioNotReceived"));break;case 2:i(!1,o.remainingTime?function(t){const e=Math.floor(t/60),o=Math.floor(t%60);return e>=60?g.get("translationTakeMoreThanHour"):e>=10&&e%10?g.get("translationTakeApproximatelyMinutes").replace("{0}",e):1==e||0==e&&o>0?g.get("translationTakeAboutMinute"):g.get("translationTakeApproximatelyMinute").replace("{0}",e)}(o.remainingTime):g.get("translationTakeFewMinutes"));break;case 3:case 6:i(!1,g.get("videoBeingTranslated"))}}))}class Kt{translateFromLang="en";translateToLang=Y;timer;ytData="";videoData="";firstPlay=!0;audio=new Audio;hls=Q();videoTranslations=[];videoTranslationTTL=7200;downloadTranslationUrl=null;downloadSubtitlesUrl=null;autoRetry;streamPing;volumeOnStart;tempOriginalVolume;tempVolume;subtitlesList=[];subtitlesListVideoId=null;videoLastSrcObject=null;constructor(t,e,o){u.A.log("[VideoHandler] add video:",t,"container:",e,this),this.video=t,this.container=e,this.site=o,this.handleSrcChangedBound=this.handleSrcChanged.bind(this),this.video.addEventListener("loadedmetadata",this.handleSrcChangedBound),this.stopTranslationBound=this.stopTranslation.bind(this),this.handleVideoEventBound=this.handleVideoEvent.bind(this),this.changeOpacityOnEventBound=this.changeOpacityOnEvent.bind(this),this.resetTimerBound=this.resetTimer.bind(this),this.init()}async init(){if(this.initialized)return;const t={autoTranslate:h.get("autoTranslate",0,!0),dontTranslateLanguage:h.get("dontTranslateLanguage",Y),dontTranslateYourLang:h.get("dontTranslateYourLang",1,!0),autoSetVolumeYandexStyle:h.get("autoSetVolumeYandexStyle",1,!0),autoVolume:h.get("autoVolume",i.JD,!0),showVideoSlider:h.get("showVideoSlider",1,!0),syncVolume:h.get("syncVolume",0,!0),subtitlesMaxLength:h.get("subtitlesMaxLength",300,!0),highlightWords:h.get("highlightWords",0,!0),responseLanguage:h.get("responseLanguage",Y),defaultVolume:h.get("defaultVolume",100,!0),udemyData:h.get("udemyData",{accessToken:"",expires:0}),audioProxy:h.get("audioProxy",0,!0),showPiPButton:h.get("showPiPButton",0,!0),translateAPIErrors:h.get("translateAPIErrors",1,!0),translationService:h.get("translationService",i.mE),detectService:h.get("detectService",i.K2),m3u8ProxyHost:h.get("m3u8ProxyHost",i.se),proxyWorkerHost:h.get("proxyWorkerHost",i.Pm)},e=await Promise.all(Object.entries(t).map((async([t,e])=>[t,await e])));this.data=Object.fromEntries(e),this.videoData=await this.getVideoData(),console.log("[db] data from db: ",this.data),this.subtitlesWidget=new St(this.video,this.container,this.site),this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength),this.subtitlesWidget.setHighlightWords(this.data.highlightWords),this.initUI(),this.initUIEvents();const o=!this.video.src&&!this.video.currentSrc&&!this.video.srcObject;this.votButton.container.hidden=o,o&&(this.votMenu.container.hidden=!0),await this.updateSubtitles(),await this.changeSubtitlesLang("disabled"),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage??"ru"),this.translateToLang=this.data.responseLanguage??"ru",this.initExtraEvents(),this.initialized=!0}transformBtn(t="none",e){this.votButton.container.dataset.status=t,this.votButton.label.innerHTML=e}initUI(){this.votButton=F.createVOTButton(g.get("translateVideo")),this.container.appendChild(this.votButton.container),this.votButton.pipButton.hidden=!J()||!this.data?.showPiPButton,this.votButton.separator2.hidden=!J()||!this.data?.showPiPButton,this.votButton.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votMenu=F.createVOTMenu(g.get("VOTSettings")),this.container.appendChild(this.votMenu.container),this.votDownloadButton=F.createIconButton(''),this.votDownloadButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadButton),this.votDownloadSubtitlesButton=F.createIconButton(''),this.votDownloadSubtitlesButton.hidden=!0,this.votMenu.headerContainer.appendChild(this.votDownloadSubtitlesButton),this.votSettingsButton=F.createIconButton(''),this.votMenu.headerContainer.appendChild(this.votSettingsButton),this.votTranslationLanguageSelect=F.createVOTLanguageSelect({fromTitle:g.get("langs")[this.video.detectedLanguage],fromDialogTitle:g.get("videoLanguage"),fromItems:[{label:g.get("langs").auto,value:"auto",selected:""},...Yt(r,this.videoData.detectedLanguage)],fromOnSelectCB:async t=>{u.A.log("[fromOnSelectCB] select from language",t.target.dataset.votValue),this.videoData=await this.getVideoData(),this.setSelectMenuValues(t.target.dataset.votValue,this.videoData.responseLanguage)},toTitle:g.get("langs")[this.video.responseLanguage],toDialogTitle:g.get("translationLanguage"),toItems:[...Yt(r,this.videoData.responseLanguage,!0),{label:"─────────",value:"separator",disabled:!0},...Yt(s,this.videoData.responseLanguage,!0)],toOnSelectCB:async t=>{const e=t.target.dataset.votValue;u.A.log("[toOnSelectCB] select to language",e),this.data.responseLanguage=this.translateToLang=e,await h.set("responseLanguage",this.data.responseLanguage),u.A.log("Response Language value changed. New value: ",this.data.responseLanguage),this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.data.responseLanguage)}}),this.votMenu.bodyContainer.appendChild(this.votTranslationLanguageSelect.container),this.votSubtitlesSelect=F.createVOTSelect(g.get("VOTSubtitlesDisabled"),g.get("VOTSubtitles"),[{label:g.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1}],{onSelectCb:async t=>{await this.changeSubtitlesLang(t.target.dataset.votValue)},labelElement:F.createVOTSelectLabel(g.get("VOTSubtitles"))}),this.votMenu.bodyContainer.appendChild(this.votSubtitlesSelect.container),this.votVideoVolumeSlider=F.createSlider(`${g.get("VOTVolume")}: ${100*this.getVideoVolume()}%`,100*this.getVideoVolume()),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoVolumeSlider.container),this.votVideoTranslationVolumeSlider=F.createSlider(`${g.get("VOTVolumeTranslation")}: ${this.data?.defaultVolume??100}%`,this.data?.defaultVolume??100),this.votVideoTranslationVolumeSlider.container.hidden="success"!==this.votButton.container.dataset.status,this.votMenu.bodyContainer.appendChild(this.votVideoTranslationVolumeSlider.container),this.votMenu.container.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation()})),this.votSettingsDialog=F.createDialog(g.get("VOTSettings")),document.documentElement.appendChild(this.votSettingsDialog.container),this.votTranslationHeader=F.createHeader(g.get("translationSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationHeader),this.votAutoTranslateCheckbox=F.createCheckbox(g.get("VOTAutoTranslate"),this.data?.autoTranslate??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoTranslateCheckbox.container),this.votDontTranslateYourLangSelect=F.createVOTSelect(g.get("langs")[h.syncGet("dontTranslateLanguage",Y)],g.get("VOTDontTranslateYourLang"),Yt(r,h.syncGet("dontTranslateLanguage",Y)),{onSelectCb:async t=>{this.data.dontTranslateLanguage=t.target.dataset.votValue,await h.set("dontTranslateLanguage",this.data.dontTranslateLanguage)},labelElement:F.createCheckbox(g.get("VOTDontTranslateYourLang"),this.data?.dontTranslateYourLang??!0).container}),this.votSettingsDialog.bodyContainer.appendChild(this.votDontTranslateYourLangSelect.container),this.votAutoSetVolumeCheckbox=F.createCheckbox(`${g.get("VOTAutoSetVolume")}`,this.data?.autoSetVolumeYandexStyle??!0),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeCheckbox.container),this.votAutoSetVolumeSlider=F.createSlider(`${100*(this.data?.autoVolume??i.JD)}%`,100*(this.data?.autoVolume??i.JD),0,100),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeSlider.container),this.votShowVideoSliderCheckbox=F.createCheckbox(g.get("VOTShowVideoSlider"),this.data?.showVideoSlider??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votShowVideoSliderCheckbox.container),this.votUdemyDataTextfield=F.createTextfield(g.get("VOTUdemyData"),this.data?.udemyData?.accessToken??""),this.votUdemyDataTextfield.container.hidden="udemy"!==this.site.host,this.votSettingsDialog.bodyContainer.appendChild(this.votUdemyDataTextfield.container),this.votSyncVolumeCheckbox=F.createCheckbox(g.get("VOTSyncVolume"),this.data?.syncVolume??!1),this.votSyncVolumeCheckbox.container.hidden=!["youtube","googledrive"].includes(this.site.host)||"mobile"===this.site.additionalData,this.votSettingsDialog.bodyContainer.appendChild(this.votSyncVolumeCheckbox.container),this.votTranslationServiceSelect=F.createVOTSelect(h.syncGet("translationService",i.mE),g.get("VOTTranslationService"),Yt(z,h.syncGet("translationService",i.mE)),{onSelectCb:async t=>{this.data.translationService=t.target.dataset.votValue,await h.set("translationService",this.data.translationService)},labelElement:F.createCheckbox(g.get("VOTTranslateAPIErrors"),this.data.translateAPIErrors??!0).container}),this.votTranslationServiceSelect.container.hidden="ru"===g.lang,this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationServiceSelect.container),this.votDetectServiceSelect=F.createVOTSelect(h.syncGet("detectService",i.K2),g.get("VOTDetectService"),Yt(I,h.syncGet("detectService",i.K2)),{onSelectCb:async t=>{this.data.detectService=t.target.dataset.votValue,await h.set("detectService",this.data.detectService)},labelElement:F.createVOTSelectLabel(g.get("VOTDetectService"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votDetectServiceSelect.container),this.votSubtitlesHeader=F.createHeader(g.get("subtitlesSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader),this.votSubtitlesMaxLengthSlider=F.createSlider(`${g.get("VOTSubtitlesMaxLength")}: ${this.data?.subtitlesMaxLength??300}`,this.data?.subtitlesMaxLength??300,50,300),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesMaxLengthSlider.container),this.votSubtitlesHighlightWordsCheckbox=F.createCheckbox(g.get("VOTHighlightWords"),this.data?.highlightWords??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHighlightWordsCheckbox.container),this.votProxyHeader=F.createHeader(g.get("proxySettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader),this.votM3u8ProxyHostTextfield=F.createTextfield(g.get("VOTM3u8ProxyHost"),this.data?.m3u8ProxyHost,i.se),this.votSettingsDialog.bodyContainer.appendChild(this.votM3u8ProxyHostTextfield.container),this.votProxyWorkerHostTextfield=F.createTextfield(g.get("VOTProxyWorkerHost"),this.data?.proxyWorkerHost,i.Pm),this.votProxyWorkerHostTextfield.container.hidden=!0,this.votSettingsDialog.bodyContainer.appendChild(this.votProxyWorkerHostTextfield.container),this.votAudioProxyCheckbox=F.createCheckbox(g.get("VOTAudioProxy"),this.data?.audioProxy??!1),this.votAudioProxyCheckbox.container.hidden=!0,this.votSettingsDialog.bodyContainer.appendChild(this.votAudioProxyCheckbox.container),this.votAboutHeader=F.createHeader(g.get("about")),this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader),this.votLanguageSelect=F.createVOTSelect(g.get("langs")[h.syncGet("locale-lang-override","auto")],g.get("VOTMenuLanguage"),Yt(p,h.syncGet("locale-lang-override","auto")),{onSelectCb:async t=>{await h.set("locale-lang-override",t.target.dataset.votValue)},labelElement:F.createVOTSelectLabel(g.get("VOTMenuLanguage"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votLanguageSelect.container),this.votShowPiPButtonCheckbox=F.createCheckbox(g.get("VOTShowPiPButton"),this.data?.showPiPButton??!1),this.votShowPiPButtonCheckbox.container.hidden=!J(),this.votSettingsDialog.bodyContainer.appendChild(this.votShowPiPButtonCheckbox.container),this.votVersionInfo=F.createInformation(`${g.get("VOTVersion")}:`,GM_info.script.version),this.votSettingsDialog.bodyContainer.appendChild(this.votVersionInfo.container),this.votAuthorsInfo=F.createInformation(`${g.get("VOTAuthors")}:`,GM_info.script.author),this.votSettingsDialog.bodyContainer.appendChild(this.votAuthorsInfo.container),this.votLoaderInfo=F.createInformation(`${g.get("VOTLoader")}:`,`${GM_info.scriptHandler} v${GM_info.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votLoaderInfo.container),this.votBrowserInfo=F.createInformation(`${g.get("VOTBrowser")}:`,`${Ut.browser.name} ${Ut.browser.version} (${Ut.os.name} ${Ut.os.version})`),this.votSettingsDialog.bodyContainer.appendChild(this.votBrowserInfo.container),this.votResetSettingsButton=F.createButton(g.get("resetSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votResetSettingsButton)}initUIEvents(){this.votButton.translateButton.addEventListener("click",(()=>{(async()=>{if(this.audio.src)return u.A.log("[click translationBtn] audio.src is not empty"),void this.stopTranslate();if(this.hls.url)return u.A.log("[click translationBtn] hls is not empty"),void this.stopTranslate();try{if(u.A.log("[click translationBtn] trying execute translation"),!this.videoData.videoId)throw new _("VOTNoVideoIDFound");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.votDownloadButton.addEventListener("click",(()=>{this.downloadTranslationUrl&&window.open(this.downloadTranslationUrl,"_blank").focus()})),this.votDownloadSubtitlesButton.addEventListener("click",(()=>{console.log(this.downloadSubtitlesUrl),this.downloadSubtitlesUrl&&window.open(this.downloadSubtitlesUrl,"_blank").focus()})),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);if(this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`,this.setVideoVolume(e/100),1===this.data.syncVolume){const t=Number(this.votVideoTranslationVolumeSlider.input.value),o=X(this.audio,e,t,this.tempOriginalVolume);this.votVideoTranslationVolumeSlider.input.value=o,this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,F.updateSlider(this.votVideoTranslationVolumeSlider.input),this.tempVolume=o,this.tempOriginalVolume=e}})),this.votVideoTranslationVolumeSlider.input.addEventListener("input",(t=>{(async()=>{this.data.defaultVolume=Number(t.target.value),await h.set("defaultVolume",this.data.defaultVolume),this.votVideoTranslationVolumeSlider.label.querySelector("strong").innerHTML=`${this.data.defaultVolume}%`,this.audio.volume=this.data.defaultVolume/100,1===this.data.syncVolume&&this.syncTranslationWithVideo(this.data.defaultVolume)})()})),this.votAutoTranslateCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.autoTranslate=Number(t.target.checked),await h.set("autoTranslate",this.data.autoTranslate),u.A.log("autoTranslate value changed. New value: ",this.data.autoTranslate)})()})),this.votDontTranslateYourLangSelect.labelElement.addEventListener("change",(t=>{(async()=>{this.data.dontTranslateYourLang=Number(t.target.checked),await h.set("dontTranslateYourLang",this.data.dontTranslateYourLang),u.A.log("dontTranslateYourLang value changed. New value: ",this.data.dontTranslateYourLang)})()})),this.votAutoSetVolumeCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.autoSetVolumeYandexStyle=Number(t.target.checked),await h.set("autoSetVolumeYandexStyle",this.data.autoSetVolumeYandexStyle),u.A.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 h.set("autoVolume",this.data.autoVolume),this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML=`${e}%`})()})),this.votShowVideoSliderCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showVideoSlider=Number(t.target.checked),await h.set("showVideoSlider",this.data.showVideoSlider),u.A.log("showVideoSlider value changed. New value: ",this.data.showVideoSlider),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status})()})),this.votUdemyDataTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.udemyData={accessToken:t.target.value,expires:(new Date).getTime()},await h.set("udemyData",this.data.udemyData),u.A.log("udemyData value changed. New value: ",this.data.udemyData),window.location.reload()})()})),this.votSyncVolumeCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.syncVolume=Number(t.target.checked),await h.set("syncVolume",this.data.syncVolume),u.A.log("syncVolume value changed. New value: ",this.data.syncVolume)})()})),this.votTranslationServiceSelect.labelElement.addEventListener("change",(t=>{(async()=>{this.data.translateAPIErrors=Number(t.target.checked),await h.set("translateAPIErrors",this.data.translateAPIErrors),u.A.log("translateAPIErrors value changed. New value: ",this.data.translateAPIErrors)})()})),this.votSubtitlesMaxLengthSlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesMaxLength=Number(t.target.value),await h.set("subtitlesMaxLength",this.data.subtitlesMaxLength),this.votSubtitlesMaxLengthSlider.label.querySelector("strong").innerHTML=`${this.data.subtitlesMaxLength}`,this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength)})()})),this.votSubtitlesHighlightWordsCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.highlightWords=Number(t.target.checked),await h.set("highlightWords",this.data.highlightWords),u.A.log("highlightWords value changed. New value: ",this.data.highlightWords),this.subtitlesWidget.setHighlightWords(this.data.highlightWords)})()})),this.votShowPiPButtonCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showPiPButton=Number(t.target.checked),await h.set("showPiPButton",this.data.showPiPButton),u.A.log("showPiPButton value changed. New value: ",this.data.showPiPButton),this.votButton.pipButton.hidden=!J()||!this.data.showPiPButton,this.votButton.separator2.hidden=!J()||!this.data.showPiPButton})()})),this.votM3u8ProxyHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.m3u8ProxyHost=t.target.value||i.se,await h.set("m3u8ProxyHost",this.data.m3u8ProxyHost),u.A.log("m3u8ProxyHost value changed. New value: ",this.data.m3u8ProxyHost)})()})),this.votProxyWorkerHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.proxyWorkerHost=t.target.value||i.Pm,await h.set("proxyWorkerHost",this.data.proxyWorkerHost),u.A.log("proxyWorkerHost value changed. New value: ",this.data.proxyWorkerHost),window.location.reload()})()})),this.votAudioProxyCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.audioProxy=Number(t.target.checked),await h.set("audioProxy",this.data.audioProxy),u.A.log("audioProxy value changed. New value: ",this.data.audioProxy)})()})),this.votResetSettingsButton.addEventListener("click",(()=>{(async()=>{g.reset();(await h.list()).filter((t=>!g.gmValues.includes(t))).forEach((t=>h.syncDelete(t))),window.location.reload()})()}))}releaseExtraEvents(){clearInterval(this.resizeInterval),this.resizeObserver?.disconnect(),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData&&this.syncVolumeObserver?.disconnect(),this.extraEvents?.forEach((t=>{t.element.removeEventListener(t.event,t.handler)}))}initExtraEvents(){this.extraEvents=[];const t=(t,e,o)=>{this.extraEvents.push({element:t,event:e,handler:o}),t.addEventListener(e,o)},e=(e,o,n)=>{o.forEach((o=>{t(e,o,n)}))};if(this.resizeObserver=new ResizeObserver((t=>{t.forEach((t=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${t.contentRect.height}px`)}))})),this.resizeObserver.observe(this.video),this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`),this.resizeInterval=setInterval((()=>{this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`)}),500),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData){this.syncVolumeObserver=new MutationObserver((t=>{t.forEach((t=>{"attributes"===t.type&&"aria-valuenow"===t.attributeName&&this.syncVideoVolumeSlider()}))}));const t=document.querySelector(".ytp-volume-panel");t&&this.syncVolumeObserver.observe(t,{attributes:!0,childList:!1,subtree:!0,attributeOldValue:!0})}let o;document.addEventListener("click",(t=>{const e=t.target,o=this.votButton.container,n=this.votMenu.container,a=this.container,i=this.votSettingsDialog.container,r=document.querySelector(".vot-dialog-temp"),s=o.contains(e),l=n.contains(e),d=a.contains(e),c=i.contains(e),h=r?.contains(e)??!1;u.A.log(`[document click] ${s} ${l} ${d} ${c} ${h}`),s||l||c||h||(d||this.logout(0),this.votMenu.container.hidden=!0)})),o="pornhub"===this.site.host?"embed"===this.site.additionalData?document.querySelector("#player"):this.container.querySelector(".video-element-wrapper-js > div"):"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),t(this.video,"emptied",(()=>{u.A.log("lipsync mode is emptied"),this.stopTranslation()})),t(this.video,"progress",(async()=>{if(this.firstPlay&&1===this.data.autoTranslate&&Z(this.site.host,this.video)===this.videoData.videoId){if(!this.videoData.videoId)throw new _("VOTNoVideoIDFound");try{this.firstPlay=!1,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.firstPlay=!1}}}))}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(u.A.log("[onchange] subtitles",t),this.votSubtitlesSelect.setSelected(t),"disabled"===t)this.votSubtitlesSelect.setTitle(g.get("VOTSubtitlesDisabled")),this.subtitlesWidget.setContent(null),this.votDownloadSubtitlesButton.hidden=!0,this.downloadSubtitlesUrl=null;else{const e=await xt(this.subtitlesList.at(parseInt(t)));this.subtitlesWidget.setContent(e),this.votDownloadSubtitlesButton.hidden=!1,this.downloadSubtitlesUrl=this.subtitlesList.at(parseInt(t))?.url}}async updateSubtitlesLangSelect(){const t=[{label:g.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1},...this.subtitlesList.map(((t,e)=>({label:(g.get("langs")[t.language]??t.language.toUpperCase())+(t.translatedFromLanguage?` ${g.get("VOTTranslatedFrom")} ${g.get("langs")[t.translatedFromLanguage]??t.translatedFromLanguage.toUpperCase()}`:"")+("yandex"!==t.source?` ${t.source}`:"")+(t.isAutoGenerated?` (${g.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] ${g.getDefault("VOTNoVideoIDFound")}`),this.subtitlesList=[],this.subtitlesListVideoId=null,void await this.updateSubtitlesLangSelect();this.subtitlesListVideoId!==this.videoData.videoId&&(this.subtitlesList=await async function(t,e,o){const n="youtube"===t.host?W.getSubtitles():[];let a=!1;const i=[...await Promise.race([new Promise((t=>{setTimeout((()=>{a||(console.error("[VOT] Failed get yandex subtitles. Reason: timeout"),t([]))}),5e3)})),new Promise((n=>{ft(`${t.url}${e}`,o,((t,e)=>{u.A.log("[exec callback] Requesting video subtitles"),t||(console.error("[VOT] Failed get yandex subtitles"),a=!0,n([]));const o=ut.decodeSubtitlesResponse(e);console.log("[VOT] Subtitles response: ",o);let i=o.subtitles??[];i=i.reduce(((t,e)=>(e.language&&!t.find((t=>{if("yandex"===t.source&&t.language===e.language&&!t.translatedFromLanguage)return t}))&&t.push({source:"yandex",language:e.language,url:e.url}),e.translatedLanguage&&t.push({source:"yandex",language:e.translatedLanguage,translatedFromLanguage:e.language,url:e.translatedUrl}),t)),[]),a=!0,n(i)}))}))]),...n].sort(((t,e)=>{if(t.source!==e.source)return"yandex"===t.source?-1:1;if(t.language!==e.language&&(t.language===Y||e.language===Y))return t.language===Y?-1:1;if("yandex"===t.source){if(t.translatedFromLanguage!==e.translatedFromLanguage)return t.translatedFromLanguage&&e.translatedFromLanguage?t.translatedFromLanguage===o?-1:1:t.language===e.language?t.translatedFromLanguage?1:-1:t.translatedFromLanguage?-1:1;if(!t.translatedFromLanguage)return t.language===o?-1:1}return"youtube"===t.source&&t.isAutoGenerated!==e.isAutoGenerated?t.isAutoGenerated?1:-1:0}));return console.log("[VOT] subtitles list",i),i}(this.site,this.videoData.videoId,this.videoData.detectedLanguage),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=W.getVideoVolume()||t),t}setVideoVolume(t){if(["youtube","googledrive"].includes(this.site.host)){if(W.setVideoVolume(t))return}this.video.volume=t}syncVideoVolumeSlider(){const t=Math.round(100*this.getVideoVolume());this.votVideoVolumeSlider.input.value=t,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${t}%`,F.updateSlider(this.votVideoVolumeSlider.input),1===this.data.syncVolume&&(this.tempOriginalVolume=Number(t))}setSelectMenuValues(t,e){this.votTranslationLanguageSelect.fromSelect.setTitle(g.get("langs")[t]),this.votTranslationLanguageSelect.toSelect.setTitle(g.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}syncTranslationWithVideo(t){const e=Number(this.votVideoVolumeSlider.input.value),o=X(this.video,t,e,this.tempVolume);this.votVideoVolumeSlider.input.value=o,this.votVideoVolumeSlider.label.querySelector("strong").innerHTML=`${o}%`,F.updateSlider(this.votVideoVolumeSlider.input),this.tempOriginalVolume=o,this.tempVolume=t}async getVideoData(){const t={translationHelp:null,isStream:!1,duration:this.video?.duration||343,videoId:Z(this.site.host,this.video),detectedLanguage:this.translateFromLang,responseLanguage:this.translateToLang};if(!t.videoId)return this.ytData={},t;if(window.location.hostname.includes("youtube.com"))this.ytData=await W.getVideoData(),t.isStream=this.ytData.isLive,""!==this.ytData.author&&(t.detectedLanguage=this.ytData.detectedLanguage,t.responseLanguage=this.translateToLang);else if(window.location.hostname.includes("rutube")||window.location.hostname.includes("ok.ru")||window.location.hostname.includes("my.mail.ru"))t.detectedLanguage="ru";else if(["bilibili","youku"].includes(this.site.host))t.detectedLanguage="zh";else if(["vk"].includes(this.site.host)){const e=document.getElementsByTagName("track")?.[0]?.srclang;t.detectedLanguage=e||"auto"}else if(window.location.hostname.includes("coursera.org")){const e=await Mt.getVideoData(this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else if(window.location.hostname.includes("coursehunter.net")){const e=await kt.getVideoData();t.translationHelp={url:e.url},t.duration=e.duration||t.duration}else if(window.location.hostname.includes("banned.video")){const e=await _t.getVideoData(t.videoId);t.translationHelp={url:e.url},t.duration=e.duration||t.duration,t.isStream=e.live}else if(window.location.hostname.includes("weverse.io")){const e=await $t.getVideoData();t.detectedLanguage="ko",e&&(t.translationHelp={url:e.url},t.duration=e.duration||t.duration)}else if(window.location.hostname.includes("udemy.com")){const e=await Ft.getVideoData(this.data.udemyData,this.translateToLang);t.duration=e.duration||t.duration,t.detectedLanguage=e.detectedLanguage,t.translationHelp=e.translationHelp}else["piped","invidious","bitchute","rumble","peertube","dailymotion","trovo","yandexdisk","coursehunter"].includes(this.site.host)&&(t.detectedLanguage="auto");return t}videoValidator(){if(["youtube","ok.ru","vk"].includes(this.site.host)){if(u.A.log("VideoValidator videoData: ",this.videoData),1===this.data.dontTranslateYourLang&&this.videoData.detectedLanguage===this.data.dontTranslateLanguage&&this.videoData.responseLanguage===this.data.dontTranslateLanguage)throw new _("VOTDisableFromYourLang");if(!this.videoData.isStream&&this.videoData.duration>14400)throw new _("VOTVideoIsTooLong")}return!0}lipSync(t=!1){if(u.A.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)&&(u.A.log(`lipsync mode is ${t}`),this.audio.pause()),"playing"==t&&(u.A.log("lipsync mode is playing"),this.audio.play());else{u.A.log("lipsync mode is play");const t=this.audio.play();void 0!==t&&t.catch((t=>{if(console.error("[VOT]",t),"NotAllowedError"===t.name)throw this.transformBtn("error",g.get("grantPermissionToAutoPlay")),new _("grantPermissionToAutoPlay");if("NotSupportedError"===t.name)throw this.transformBtn("error",Wt.includes(window.location.hostname)?g.get("neededAdditionalExtension"):g.get("audioFormatNotSupported")),Wt.includes(window.location.hostname)?new _("neededAdditionalExtension"):new _("audioFormatNotSupported")}))}else u.A.log("lipsync mode is not set")}handleVideoEvent(t){u.A.log(`video ${t.type}`),this.lipSync(t.type)}stopTranslate(){Gt.forEach((t=>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",g.get("translateVideo")),u.A.log(`Volume on start: ${this.volumeOnStart}`),this.volumeOnStart&&this.setVideoVolume(this.volumeOnStart),this.volumeOnStart="",clearInterval(this.streamPing),this.hls?.destroy(),this.hls=Q()}async translateExecutor(t){u.A.log("Run translateFunc"),this.translateFunc(t,this.videoData.isStream,this.videoData.detectedLanguage,this.videoData.responseLanguage,this.videoData.translationHelp)}async updateTranslationErrorMsg(t){const e=g.get("translationTake"),o=g.get("VOTTranslatingError"),n=g.lang;if("VOTLocalizedError"===t?.name)this.transformBtn("error",t.localizedMessage);else if(1!==this.data.translateAPIErrors||t.includes(e)||"ru"===n)this.transformBtn("error",t);else{const e=await async function(t,e="",o="ru"){if("yandex"===await h.get("translationService",i.mE)){const n=e&&o?`${e}-${o}`:o;return await q.translate(t,n)}return t}(t,"ru",n);this.transformBtn("error",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").innerHTML=100*this.data.autoVolume+"%",F.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=t}updateTranslation(t){if(this.audio.src=t,this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),"twitter"===this.site.host)document.querySelector('div[data-testid="app-bar-back"][role="button"]').addEventListener("click",this.stopTranslationBound);this.video&&!this.video.paused&&this.lipSync("play"),Gt.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),this.transformBtn("success",g.get("disableTranslate")),this.afterUpdateTranslation(t)}translateFunc(t,e,o,n,a){console.log("[VOT] Video Data: ",this.videoData);const i=a?.url?a.url:`${this.site.url}${t}`;if(u.A.log("Run videoValidator"),this.videoValidator(),e)return u.A.log("Executed stream translation"),void function(t,e,o,n){u.A.log(`Translate stream (url: ${t}, requestLang: ${e}, responseLang: ${o})`),vt(t,e,o,((t,e)=>{if(u.A.log("[exec callback] Requesting stream translation"),!t)return void n(!1,g.get("requestTranslationFailed"));const o=ut.decodeStreamResponse(e);switch(console.log("[VOT] Stream Translation response: ",o),o.interval){case 10:n(!1,o.interval,g.get("translationTakeFewMinutes"));break;case 20:n(!0,o.interval,o||g.get("audioNotReceived"));break;case 0:n(!1,o.interval,g.get("streamNoConnectionToServer"))}}))}(i,o,n,(async(i,r,s)=>{if(u.A.log("[exec callback] translateStream callback"),Z(this.site.host,this.video)!==t)return;if(!i||!s.translatedInfo)return await this.updateTranslationErrorMsg(s),void(10===r&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,o,n,a)),1e3*r)));this.transformBtn("success",g.get("disableTranslate")),console.log(s);const l=s.pingId;u.A.log(`Stream pingId: ${l}`),this.streamPing=setInterval((async()=>await mt(l,(t=>u.A.log("Stream ping result: ",t)))),1e3*r),u.A.log(s.translatedInfo.url);const d=`https://${this.data.m3u8ProxyHost}/?all=yes&origin=${encodeURIComponent("https://strm.yandex.ru")}&referer=${encodeURIComponent("https://strm.yandex.ru")}&url=${encodeURIComponent(s.translatedInfo.url)}`;if(u.A.log(d),this.hls)this.hls.on(Hls.Events.MEDIA_ATTACHED,(function(){u.A.log("audio and hls.js are now bound together !")})),this.hls.on(Hls.Events.MANIFEST_PARSED,(function(t){u.A.log("manifest loaded, found "+t?.levels?.length+" quality level")})),this.hls.loadSource(d),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()}})),u.A.log(this.hls);else{if(!this.audio.canPlayType("application/vnd.apple.mpegurl"))throw new _("audioFormatNotSupported");this.audio.src=d}"youtube"===this.site.host&&W.videoSeek(this.video,10),this.volumeOnStart=this.getVideoVolume(),"number"==typeof this.data.defaultVolume&&(this.audio.volume=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume),this.video.src||this.video.currentSrc||this.video.srcObject?(this.video&&!this.video.paused&&this.lipSync("play"),Gt.forEach((t=>this.video.addEventListener(t,this.handleVideoEventBound))),this.afterUpdateTranslation(d)):this.stopTranslation()}));if(["udemy","coursera"].includes(this.site.host)&&!a)throw new _("VOTTranslationHelpNull");const r=this.videoTranslations.find((e=>e.videoId===t&&e.expires>Date.now()/1e3&&e.from===o&&e.to===n));if(r)return this.updateTranslation(r.url),void u.A.log("[translateFunc] A cached translate was received");Zt(i,this.videoData.duration,o,n,a,(async(i,r)=>{if(u.A.log("[exec callback] translateVideo callback"),Z(this.site.host,this.video)===t){if(!i)return await this.updateTranslationErrorMsg(r),r.includes(g.get("translationTake"))&&(clearTimeout(this.autoRetry),this.autoRetry=setTimeout((()=>this.translateFunc(t,e,o,n,a)),6e4)),void console.error("[VOT]",r);this.updateTranslation(r),this.videoTranslations.push({videoId:t,from:o,to:n,url:r,expires:Date.now()/1e3+this.videoTranslationTTL})}}))}stopTranslation(){this.stopTranslate(),this.syncVideoVolumeSlider()}async handleSrcChanged(){u.A.log("[VideoHandler] src changed",this),this.stopTranslation(),this.firstPlay=!0,this.videoData=await this.getVideoData(),this.videoData.detectedLanguage&&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(){u.A.log("[VideoHandler] release"),this.initialized=!1,this.stopTranslation(),this.releaseExtraEvents(),this.subtitlesWidget.release(),this.votButton.container.remove(),this.votMenu.container.remove()}}const Jt=new class{constructor(){this.onVideoAdded=new Ht,this.onVideoRemoved=new Ht,this.handleVideoAddedBound=this.handleVideoAdded.bind(this),this.handleVideoRemovedBound=this.handleVideoRemoved.bind(this),this.observer=new MutationObserver((t=>{window.requestIdleCallback((()=>{t.forEach((t=>{"childList"===t.type&&(jt(t.addedNodes).forEach(this.handleVideoAddedBound),jt(t.removedNodes).forEach(this.handleVideoRemovedBound))}))}),{timeout:1e3})}))}enable(){this.observer.observe(document,{childList:!0,subtree:!0}),document.querySelectorAll("video").forEach(this.handleVideoAddedBound)}disable(){this.observer.disconnect()}handleVideoAdded(t){this.onVideoAdded.dispatch(t)}handleVideoRemoved(t){document.contains(t)||this.onVideoRemoved.dispatch(t)}},Qt=new WeakMap;(async function(){if(u.A.log("Loading extension..."),await g.update(),u.A.log(`Selected menu language: ${g.lang}`),GM_info?.scriptHandler&&d.includes(GM_info.scriptHandler))return console.error(`[VOT] ${g.getDefault("unSupportedExtensionError").replace("{0}",GM_info.scriptHandler)}`),alert(`[VOT] ${g.get("unSupportedExtensionError").replace("{0}",GM_info.scriptHandler)}`);u.A.log("Extension compatibility passed..."),Jt.onVideoAdded.addListener((t=>{for(const e of Nt.filter((t=>{const e=t=>t instanceof RegExp&&t.test(window.location.hostname)||"string"==typeof t&&window.location.hostname.includes(t)||"function"==typeof t&&t(new URL(window.location));return!!(e(t.match)||t.match instanceof Array&&t.match.some((t=>e(t))))&&t.host&&t.url}))){if(!e)continue;let o;if(e.shadowRoot)o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.shadowRoot.contains(t))):t.parentElement,o=o&&o.shadowRoot?o.parentElement:o;else{const n=Ut.browser.version.split(".")?.[0];if(e.selector?.includes(":not")&&e.selector?.includes("*")&&n&&("Chrome"===Ut.browser.name&&Number(n)<88||"Firefox"===Ut.browser.name&&Number(n)<84)){const n=e.selector?.split(" *")?.[0];o=n?Object.values(document.querySelectorAll(n)).find((e=>e.contains(t))):t.parentElement}else o=e.selector?Object.values(document.querySelectorAll(e.selector)).find((e=>e.contains(t))):t.parentElement}if(o&&!("rumble"===e.host&&o.querySelector("vot-block")||("peertube"===e.host&&(e.url=window.location.origin),Qt.has(t)))){Qt.set(t,new Kt(t,o,e));break}}})),Jt.onVideoRemoved.addListener((async t=>{Qt.has(t)&&(await Qt.get(t).release(),Qt.delete(t))})),Jt.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 18dee75c..ea38698c 100644 --- a/dist/vot.user.js +++ b/dist/vot.user.js @@ -1,123 +1,131 @@ // ==UserScript== -// @name [VOT] - Voice Over Translation -// @name:de [VOT] - Voice-Over-Video-Übersetzung -// @name:es [VOT] - Traducción de vídeo en off -// @name:fr [VOT] - Traduction vidéo voix-off -// @name:it [VOT] - Traduzione Video fuori campo -// @name:ru [VOT] - Закадровый перевод видео -// @name:zh [VOT] - 画外音视频翻译 -// @description A small extension that adds a Yandex Browser video translation to other browsers +// @name [VOT] - Voice Over Translation +// @name:de [VOT] - Voice-Over-Video-Übersetzung +// @name:es [VOT] - Traducción de vídeo en off +// @name:fr [VOT] - Traduction vidéo voix-off +// @name:it [VOT] - Traduzione Video fuori campo +// @name:ru [VOT] - Закадровый перевод видео +// @name:zh [VOT] - 画外音视频翻译 +// @description A small extension that adds a Yandex Browser video translation to other browsers // @description:de Eine kleine Erweiterung, die eine Voice-over-Übersetzung von Videos aus dem Yandex-Browser zu anderen Browsern hinzufügt // @description:es Una pequeña extensión que agrega una traducción de voz en off de un video de Yandex Browser a otros navegadores // @description:fr Une petite extension qui ajoute la traduction vocale de la vidéo du Navigateur Yandex à d'autres navigateurs // @description:it Una piccola estensione che aggiunge la traduzione vocale del video dal browser Yandex ad altri browser // @description:ru Небольшое расширение, которое добавляет закадровый перевод видео из Яндекс Браузера в другие браузеры // @description:zh 一个小扩展,它增加了视频从Yandex浏览器到其他浏览器的画外音翻译 -// @version 1.5.0.5 -// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD -// @supportURL https://github.com/ilyhalight/voice-over-translation/issues -// @match *://*.youtube.com/* -// @match *://*.youtube-nocookie.com/* -// @match *://*.youtubekids.com/* -// @match *://*.twitch.tv/* -// @match *://*.xvideos.com/* -// @match *://*.pornhub.com/* -// @match *://*.vk.com/* -// @match *://*.vk.ru/* -// @match *://invidious.snopyta.org/* -// @match *://invidious.kavin.rocks/* -// @match *://vid.puffyan.us/* -// @match *://invidious.namazso.eu/* -// @match *://inv.riverside.rocks/* -// @match *://yt.artemislena.eu/* -// @match *://invidious.flokinet.to/* -// @match *://invidious.esmailelbob.xyz/* -// @match *://invidious.nerdvpn.de/* -// @match *://invidious.slipfox.xyz/* -// @match *://invidio.xamh.de/* -// @match *://invidious.dhusch.de/* -// @match *://*.piped.video/* -// @match *://piped.tokhmi.xyz/* -// @match *://piped.moomoo.me/* -// @match *://piped.syncpundit.io/* -// @match *://piped.mha.fi/* -// @match *://watch.whatever.social/* -// @match *://piped.garudalinux.org/* -// @match *://efy.piped.pages.dev/* -// @match *://watch.leptons.xyz/* -// @match *://piped.lunar.icu/* -// @match *://yt.dc09.ru/* -// @match *://piped.mint.lgbt/* -// @match *://*.il.ax/* -// @match *://piped.privacy.com.de/* -// @match *://piped.esmailelbob.xyz/* -// @match *://piped.projectsegfau.lt/* -// @match *://piped.in.projectsegfau.lt/* -// @match *://piped.us.projectsegfau.lt/* -// @match *://piped.privacydev.net/* -// @match *://piped.palveluntarjoaja.eu/* -// @match *://piped.smnz.de/* -// @match *://piped.adminforge.de/* -// @match *://piped.qdi.fi/* -// @match *://piped.hostux.net/* -// @match *://piped.chauvet.pro/* -// @match *://piped.jotoma.de/* -// @match *://piped.pfcd.me/* -// @match *://piped.frontendfriendly.xyz/* -// @match *://*.yewtu.be/* -// @match *://inv.vern.cc/* -// @match *://*.vimeo.com/* -// @match *://*.9gag.com/* -// @match *://*.twitter.com/* -// @match *://*.facebook.com/* -// @match *://*.rutube.ru/* -// @match *://*.bilibili.com/* -// @match *://my.mail.ru/* -// @match *://*.bitchute.com/* -// @match *://*.coursera.org/learn/* -// @match *://*.udemy.com/course/* -// @match *://*.tiktok.com/* -// @match *://proxitok.pabloferreiro.es/* -// @match *://proxitok.pussthecat.org/* -// @match *://tok.habedieeh.re/* -// @match *://proxitok.esmailelbob.xyz/* -// @match *://proxitok.privacydev.net/* -// @match *://tok.artemislena.eu/* -// @match *://tok.adminforge.de/* -// @match *://tik.hostux.net/* -// @match *://tt.vern.cc/* -// @match *://cringe.whatever.social/* -// @match *://proxitok.lunar.icu/* -// @match *://proxitok.privacy.com.de/* -// @match *://rumble.com/* -// @match *://*.eporner.com/* -// @match *://peertube.1312.media/* -// @match *://tube.shanti.cafe/* -// @match *://bee-tube.fr/* -// @match *://video.sadmin.io/* -// @match *://dalek.zone/* -// @match *://review.peertube.biz/* -// @match *://peervideo.club/* -// @match *://tube.la-dina.net/* -// @match *://peertube.tmp.rcp.tf/* -// @match *://geo.dailymotion.com/* -// @match *://trovo.live/* -// @match *://disk.yandex.ru/i/* -// @match *://coursehunter.net/* -// @connect api.browser.yandex.ru -// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot.user.js -// @grant GM_xmlhttpRequest -// @grant GM_info -// @grant GM_setValue -// @grant GM_getValue -// @grant GM_deleteValue -// @grant GM_listValues -// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues -// @icon https://translate.yandex.ru/icons/favicon.ico -// @namespace vot -// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js -// @require https://cdn.jsdelivr.net/npm/hls.js@1 -// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot.user.js +// @grant GM_addStyle +// @grant GM_deleteValue +// @grant GM_listValues +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_xmlhttpRequest +// @grant GM_info +// @require https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js +// @require https://cdn.jsdelivr.net/npm/hls.js/dist/hls.light.min.js +// @match *://*.youtube.com/* +// @match *://*.youtube-nocookie.com/* +// @match *://*.youtubekids.com/* +// @match *://*.twitch.tv/* +// @match *://*.xvideos.com/* +// @match *://*.pornhub.com/* +// @match *://*.vk.com/* +// @match *://*.vk.ru/* +// @match *://invidious.snopyta.org/* +// @match *://invidious.kavin.rocks/* +// @match *://vid.puffyan.us/* +// @match *://invidious.namazso.eu/* +// @match *://inv.riverside.rocks/* +// @match *://yt.artemislena.eu/* +// @match *://invidious.flokinet.to/* +// @match *://invidious.esmailelbob.xyz/* +// @match *://invidious.nerdvpn.de/* +// @match *://invidious.slipfox.xyz/* +// @match *://invidio.xamh.de/* +// @match *://invidious.dhusch.de/* +// @match *://*.piped.video/* +// @match *://piped.tokhmi.xyz/* +// @match *://piped.moomoo.me/* +// @match *://piped.syncpundit.io/* +// @match *://piped.mha.fi/* +// @match *://watch.whatever.social/* +// @match *://piped.garudalinux.org/* +// @match *://efy.piped.pages.dev/* +// @match *://watch.leptons.xyz/* +// @match *://piped.lunar.icu/* +// @match *://yt.dc09.ru/* +// @match *://piped.mint.lgbt/* +// @match *://*.il.ax/* +// @match *://piped.privacy.com.de/* +// @match *://piped.esmailelbob.xyz/* +// @match *://piped.projectsegfau.lt/* +// @match *://piped.in.projectsegfau.lt/* +// @match *://piped.us.projectsegfau.lt/* +// @match *://piped.privacydev.net/* +// @match *://piped.palveluntarjoaja.eu/* +// @match *://piped.smnz.de/* +// @match *://piped.adminforge.de/* +// @match *://piped.qdi.fi/* +// @match *://piped.hostux.net/* +// @match *://piped.chauvet.pro/* +// @match *://piped.jotoma.de/* +// @match *://piped.pfcd.me/* +// @match *://piped.frontendfriendly.xyz/* +// @match *://*.yewtu.be/* +// @match *://inv.vern.cc/* +// @match *://*.vimeo.com/* +// @match *://*.9gag.com/* +// @match *://*.twitter.com/* +// @match *://*.facebook.com/* +// @match *://*.rutube.ru/* +// @match *://*.bilibili.com/* +// @match *://my.mail.ru/* +// @match *://*.bitchute.com/* +// @match *://*.coursera.org/learn/* +// @match *://*.udemy.com/course/* +// @match *://*.tiktok.com/* +// @match *://proxitok.pabloferreiro.es/* +// @match *://proxitok.pussthecat.org/* +// @match *://tok.habedieeh.re/* +// @match *://proxitok.esmailelbob.xyz/* +// @match *://proxitok.privacydev.net/* +// @match *://tok.artemislena.eu/* +// @match *://tok.adminforge.de/* +// @match *://tik.hostux.net/* +// @match *://tt.vern.cc/* +// @match *://cringe.whatever.social/* +// @match *://proxitok.lunar.icu/* +// @match *://proxitok.privacy.com.de/* +// @match *://rumble.com/* +// @match *://*.eporner.com/* +// @match *://peertube.1312.media/* +// @match *://tube.shanti.cafe/* +// @match *://bee-tube.fr/* +// @match *://video.sadmin.io/* +// @match *://dalek.zone/* +// @match *://review.peertube.biz/* +// @match *://peervideo.club/* +// @match *://tube.la-dina.net/* +// @match *://peertube.tmp.rcp.tf/* +// @match *://geo.dailymotion.com/* +// @match *://*.ok.ru/* +// @match *://trovo.live/* +// @match *://disk.yandex.ru/i/* +// @match *://coursehunter.net/* +// @match *://youtube.googleapis.com/embed/* +// @match *://*.banned.video/* +// @match *://*.weverse.io/* +// @match *://*.newgrounds.com/* +// @match *://*.egghead.io/* +// @match *://*.youku.com/* +// @connect api.browser.yandex.ru +// @namespace vot +// @version 1.5.1 +// @icon https://translate.yandex.ru/icons/favicon.ico +// @author sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD +// @homepageURL https://github.com/ilyhalight/voice-over-translation/issues +// @updateURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot.user.js +// @downloadURL https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist/vot.user.js +// @supportURL https://github.com/ilyhalight/voice-over-translation/issues // ==/UserScript== /******/ (() => { // webpackBootstrap @@ -135,7 +143,7 @@ "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Z: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./node_modules/css-loader/dist/runtime/noSourceMaps.js"); /* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); @@ -146,7 +154,7 @@ var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); // Module -___CSS_LOADER_EXPORT___.push([module.id, `.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}`, ""]); +___CSS_LOADER_EXPORT___.push([module.id, `.vot-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border:none;border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer;transition:box-shadow .2s}.vot-button[hidden]{display:none !important}.vot-button::-moz-focus-inner{border:none}.vot-button::before,.vot-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-button::before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity .2s}.vot-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-button:hover{box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)}.vot-button:hover::before{opacity:.08}.vot-button:active{box-shadow:0 5px 5px -3px rgba(0,0,0,.2),0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12)}.vot-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s}.vot-button:disabled{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.12);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);box-shadow:none;cursor:initial}.vot-button:disabled::before,.vot-button:disabled::after{opacity:0}.vot-outlined-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:solid 1px;border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.24);border-radius:4px;padding:0 16px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:34px;outline:none;cursor:pointer}.vot-outlined-button[hidden]{display:none !important}.vot-outlined-button::-moz-focus-inner{border:none}.vot-outlined-button::before,.vot-outlined-button::after{content:"";position:absolute;border-radius:3px;top:0;right:0;bottom:0;left:0;opacity:0}.vot-outlined-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-outlined-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-outlined-button:hover::before{opacity:.04}.vot-outlined-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-outlined-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-outlined-button:disabled::before,.vot-outlined-button:disabled::after{opacity:0}.vot-text-button{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:4px;padding:0 8px;min-width:64px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;color:rgb(var(--vot-helper-theme));background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-text-button[hidden]{display:none !important}.vot-text-button::-moz-focus-inner{border:none}.vot-text-button::before,.vot-text-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-text-button::before{background-color:rgb(var(--vot-helper-theme));transition:opacity .2s}.vot-text-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-text-button:hover::before{opacity:.04}.vot-text-button:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-text-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-text-button:disabled::before,.vot-text-button:disabled::after{opacity:0}.vot-icon-button{--vot-helper-onsurface: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);position:relative;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;border:none;border-radius:50%;padding:0;width:36px;height:36px;vertical-align:middle;text-align:center;text-overflow:ellipsis;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:rgba(0,0,0,0);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;font-weight:500;line-height:36px;outline:none;cursor:pointer}.vot-icon-button[hidden]{display:none !important}.vot-icon-button::-moz-focus-inner{border:none}.vot-icon-button::before,.vot-icon-button::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-icon-button::before{background-color:var(--vot-helper-onsurface);transition:opacity .2s}.vot-icon-button::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity .3s,background-size .4s}.vot-icon-button:hover::before{opacity:.04}.vot-icon-button:active::after{opacity:.32;background-size:100% 100%;transition:background-size 0s,opacity 0s}.vot-icon-button:disabled{background-color:rgba(0,0,0,0);color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);fill:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-icon-button:disabled::before,.vot-icon-button:disabled::after{opacity:0}.vot-textfield{--vot-helper-theme: rgb( var(--vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243)) ) !important;--vot-helper-safari1: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.38 ) !important;--vot-helper-safari2: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari3: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;position:relative !important;display:inline-block;padding-top:6px !important;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-textfield[hidden]{display:none !important}.vot-textfield>input,.vot-textfield>textarea{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:0 !important;border-style:solid !important;border-width:1px !important;border-color:rgba(0,0,0,0) var(--vot-helper-safari2) var(--vot-helper-safari2) !important;border-radius:4px !important;padding:15px 13px 15px !important;width:100% !important;height:inherit !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;-webkit-text-fill-color:currentColor !important;background-color:rgba(0,0,0,0) !important;box-shadow:inset 1px 0 rgba(0,0,0,0),inset -1px 0 rgba(0,0,0,0),inset 0 -1px rgba(0,0,0,0) !important;font-family:inherit !important;font-size:inherit !important;line-height:inherit !important;caret-color:var(--vot-helper-theme) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input:not(:focus):placeholder-shown,.vot-textfield>textarea:not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2) !important}.vot-textfield>input+span,.vot-textfield>textarea+span{position:absolute !important;top:0 !important;left:0 !important;display:flex !important;width:100% !important;max-height:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;font-size:75% !important;line-height:15px !important;cursor:text !important;transition:color .2s,font-size .2s,line-height .2s !important;pointer-events:none !important}.vot-textfield>input:not(:focus):placeholder-shown+span,.vot-textfield>textarea:not(:focus):placeholder-shown+span{font-size:inherit !important;line-height:68px !important}.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{content:"" !important;display:block !important;-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin-top:6px !important;border-top:solid 1px var(--vot-helper-safari2) !important;min-width:10px !important;height:8px !important;pointer-events:none !important;box-shadow:inset 0 1px rgba(0,0,0,0) !important;transition:border .2s,box-shadow .2s !important}.vot-textfield>input+span::before,.vot-textfield>textarea+span::before{margin-right:4px !important;border-left:solid 1px rgba(0,0,0,0) !important;border-radius:4px 0 !important}.vot-textfield>input+span::after,.vot-textfield>textarea+span::after{flex-grow:1 !important;margin-left:4px !important;border-right:solid 1px rgba(0,0,0,0) !important;border-radius:0 4px !important}.vot-textfield>input:not(:focus):placeholder-shown+span::before,.vot-textfield>input:not(:focus):placeholder-shown+span::after,.vot-textfield>textarea:not(:focus):placeholder-shown+span::before,.vot-textfield>textarea:not(:focus):placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}.vot-textfield:hover>input,.vot-textfield:hover>textarea{border-color:rgba(0,0,0,0) var(--vot-helper-safari3) var(--vot-helper-safari3) !important}.vot-textfield:hover>input+span::before,.vot-textfield:hover>input+span::after,.vot-textfield:hover>textarea+span::before,.vot-textfield:hover>textarea+span::after{border-top-color:var(--vot-helper-safari3) !important}.vot-textfield:hover>input:not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3) !important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:rgba(0,0,0,0) var(--vot-helper-theme) var(--vot-helper-theme) !important;box-shadow:inset 1px 0 var(--vot-helper-theme),inset -1px 0 var(--vot-helper-theme),inset 0 -1px var(--vot-helper-theme) !important;outline:none !important}.vot-textfield>input:focus+span,.vot-textfield>textarea:focus+span{color:var(--vot-helper-theme) !important}.vot-textfield>input:focus+span::before,.vot-textfield>input:focus+span::after,.vot-textfield>textarea:focus+span::before,.vot-textfield>textarea:focus+span::after{border-top-color:var(--vot-helper-theme) !important;box-shadow:inset 0 1px var(--vot-helper-theme) !important}.vot-textfield>input:disabled,.vot-textfield>input:disabled+span,.vot-textfield>textarea:disabled,.vot-textfield>textarea:disabled+span{border-color:rgba(0,0,0,0) var(--vot-helper-safari1) var(--vot-helper-safari1) !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;pointer-events:none !important}.vot-textfield>input:disabled+span::before,.vot-textfield>input:disabled+span::after,.vot-textfield>textarea:disabled+span::before,.vot-textfield>textarea:disabled+span::after{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown,.vot-textfield>input:disabled:placeholder-shown+span,.vot-textfield>textarea:disabled:placeholder-shown,.vot-textfield>textarea:disabled:placeholder-shown+span{border-top-color:var(--vot-helper-safari1) !important}.vot-textfield>input:disabled:placeholder-shown+span::before,.vot-textfield>input:disabled:placeholder-shown+span::after,.vot-textfield>textarea:disabled:placeholder-shown+span::before,.vot-textfield>textarea:disabled:placeholder-shown+span::after{border-top-color:rgba(0,0,0,0) !important}@media not all and (min-resolution: 0.001dpcm){@supports(-webkit-appearance: none){.vot-textfield>input,.vot-textfield>input+span,.vot-textfield>textarea,.vot-textfield>textarea+span,.vot-textfield>input+span::before,.vot-textfield>input+span::after,.vot-textfield>textarea+span::before,.vot-textfield>textarea+span::after{transition-duration:.1s !important}}}.vot-checkbox{--vot-helper-theme: var( --vot-theme-rgb, var(--vot-primary-rgb, 33, 150, 243) );--vot-helper-ontheme: var( --vot-ontheme-rgb, var(--vot-onprimary-rgb, 255, 255, 255) );z-index:0;position:relative;display:inline-block;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-checkbox[hidden]{display:none !important}.vot-checkbox>input{appearance:none;-moz-appearance:none;-webkit-appearance:none;z-index:1;position:absolute;display:block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:3px 1px;border:solid 2px;background:rgba(0,0,0,0);border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6);border-radius:2px;width:18px;height:18px;outline:none;cursor:pointer;transition:border-color .2s,background-color .2s}.vot-checkbox>input+span{display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding-left:30px;width:inherit;cursor:pointer}.vot-checkbox>input+span::before{content:"";position:absolute;left:-10px;top:-8px;display:block;border-radius:50%;width:40px;height:40px;background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0));opacity:0;transform:scale(1);pointer-events:none;transition:opacity .3s,transform .2s}.vot-checkbox>input+span::after{content:"";z-index:1;display:block;position:absolute;top:3px;left:1px;-webkit-box-sizing:content-box !important;-moz-box-sizing:content-box !important;box-sizing:content-box !important;width:10px;height:5px;border:solid 2px rgba(0,0,0,0);border-right-width:0;border-top-width:0;pointer-events:none;transform:translate(3px, 4px) rotate(-45deg);transition:border-color .2s}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{border-color:rgb(var(--vot-helper-theme));background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::before,.vot-checkbox>input:indeterminate+span::before{background-color:rgb(var(--vot-helper-theme))}.vot-checkbox>input:checked+span::after,.vot-checkbox>input:indeterminate+span::after{border-color:rgb(var(--vot-helper-ontheme, 255, 255, 255))}.vot-checkbox>input:indeterminate+span::after{border-left-width:0;transform:translate(4px, 3px)}.vot-checkbox:hover>input+span::before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input{border-color:rgb(var(--vot-helper-theme))}.vot-checkbox:active>input:checked{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6)}.vot-checkbox:active>input+span::before{opacity:1;transform:scale(0);transition:transform 0s,opacity 0s}.vot-checkbox>input:disabled{border-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{border-color:rgba(0,0,0,0);background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38)}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38);cursor:initial}.vot-checkbox>input:disabled+span::before{opacity:0;transform:scale(0)}.vot-slider{--vot-safari-helper1: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.04 ) !important;--vot-safari-helper2: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.12 ) !important;--vot-safari-helper3: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.16 ) !important;--vot-safari-helper4: rgba( var(--vot-primary-rgb, 33, 150, 243), 0.24 ) !important;display:inline-block;width:100% !important;color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important;font-family:var(--vot-font, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system) !important;font-size:16px !important;line-height:1.5 !important;text-align:start !important}.vot-slider[hidden]{display:none !important}.vot-slider>input{-webkit-appearance:none !important;appearance:none !important;position:relative !important;top:24px !important;display:block !important;margin:0 0 -36px !important;width:100% !important;height:36px !important;background-color:rgba(0,0,0,0) !important;cursor:pointer !important}.vot-slider>input:last-child{position:static !important;margin:0 !important}.vot-slider>span{display:inline-block !important;margin-bottom:36px !important}.vot-slider>input:disabled{cursor:default !important;opacity:.38 !important}.vot-slider>input:disabled+span{color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input::-webkit-slider-runnable-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-webkit-slider-thumb{margin:0 !important;appearance:none !important;-webkit-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper1) !important}.vot-slider>input:active::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--vot-safari-helper4) !important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-webkit-slider-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;color:rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-range-track{margin:17px 0 !important;border-radius:1px !important;width:100% !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-moz-range-thumb{appearance:none !important;-moz-appearance:none !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider>input::-moz-range-progress{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider:hover>input:hover::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.87) !important}.vot-slider>input:disabled::-moz-range-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::-moz-focus-outer{border:none !important}.vot-slider>input::-ms-track{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important;margin:17px 0 !important;border:none !important;border-radius:1px !important;padding:0 17px !important;width:100% !important;height:2px !important;background-color:rgba(0,0,0,0) !important}.vot-slider>input::-ms-fill-lower{border-radius:1px !important;height:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-slider>input::-ms-fill-upper{border-radius:1px !important;height:2px !important;background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input::-ms-thumb{appearance:none !important;margin:0 17px !important;border:none !important;border-radius:50% !important;height:2px !important;width:2px !important;background-color:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important;transform:scale(6, 6) !important;transition:box-shadow .2s !important}.vot-slider:hover>input::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.04) !important}.vot-slider>input:active::-ms-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb, 33, 150, 243), 0.24) !important}.vot-slider>input:disabled::-ms-fill-lower{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important}.vot-slider>input:disabled::-ms-fill-upper{background-color:rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.38) !important;opacity:.38 !important}.vot-slider>input:disabled::-ms-thumb{background-color:rgb(var(--vot-onsurface-rgb, 0, 0, 0)) !important;box-shadow:0 0 0 1px rgb(var(--vot-surface-rgb, 255, 255, 255)) !important;transform:scale(4, 4) !important}.vot-slider>input::before{content:"" !important;display:block !important;position:absolute !important;width:calc(100%*var(--vot-progress, 0)) !important;height:2px !important;top:calc(50% - 1px) !important;background:rgb(var(--vot-primary-rgb, 33, 150, 243)) !important}.vot-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0) !important;--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87) !important;--vot-helper-safari1: rgba(var(--vot-onsurface-rgb, 0, 0, 0), 0.6) !important;--vot-helper-safari2: rgba( var(--vot-onsurface-rgb, 0, 0, 0), 0.87 ) !important;display:flex;align-items:center;justify-content:space-between;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:14px;line-height:1.5;text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-select[hidden]{display:none !important}.vot-select-label{font-size:16px}.vot-select-outer{display:flex;align-items:center;justify-content:space-between;max-width:120px;width:120px;padding:0 5px;border-style:solid !important;border-width:1px !important;border-color:var(--vot-helper-safari1) !important;border-radius:4px !important;cursor:pointer;transition:border .2s !important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2) !important}.vot-select-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vot-select-arrow-icon{width:20px;height:32px;display:flex;justify-content:center;align-items:center}.vot-select-content-list{display:flex;flex-direction:column}.vot-select-content-list .vot-select-content-item{padding:5px 10px;border-radius:8px;cursor:pointer}.vot-select-content-list .vot-select-content-item:not([inert]):hover{background-color:#2a2c31}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]{color:rgb(var(--vot-primary-rgb, 33, 150, 243));background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb, 33, 150, 243), 0.1) !important}.vot-select-content-list .vot-select-content-item[data-vot-disabled=true]{cursor:default}.vot-select-content-list .vot-select-content-item[hidden]{display:none !important}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-weight:bold;line-height:1.5;text-align:start}.vot-header[hidden]{display:none !important}.vot-header:not(:first-child){padding-top:8px}.vot-header-level-1{font-size:2em}.vot-header-level-2{font-size:1.5em}.vot-header-level-3{font-size:1.17em}.vot-header-level-4{font-size:1em}.vot-header-level-5{font-size:.83em}.vot-header-level-6{font-size:.67em}.vot-info{display:flex;color:rgba(var(--vot-helper-onsurface-rgb), 0.87);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;text-align:start}.vot-info[hidden]{display:none !important}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), 0.5);flex:1;margin-left:8px}.vot-lang-select{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);display:flex;align-items:center;justify-content:space-between;color:var(--vot-helper-theme);fill:var(--vot-helper-theme)}.vot-lang-select[hidden]{display:none !important}.vot-lang-select-icon{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.vot-segmented-button{--vot-helper-theme-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-theme: rgba(var(--vot-helper-theme-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:5rem;transform:translate(-50%);user-select:none;display:flex;align-items:center;height:32px;max-width:100vw;background:rgb(var(--vot-surface-rgb, 255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);border-radius:4px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;cursor:default;transition:opacity .5s;z-index:100}.vot-segmented-button[hidden]{display:none !important}.vot-segmented-button *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-segmented-button .vot-separator{width:1px;height:50%;background:rgba(var(--vot-helper-theme-rgb), 0.1)}.vot-segmented-button .vot-separator[hidden]{display:none !important}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{position:relative;overflow:hidden;display:flex;justify-content:center;align-items:center;height:100%;padding:0 8px;background-color:rgba(0,0,0,0);color:inherit;transition:background-color 100ms ease-in-out;border:none}.vot-segmented-button .vot-segment[hidden],.vot-segmented-button [hidden].vot-segment-only-icon{display:none !important}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before,.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{content:"";position:absolute;border-radius:inherit;top:0;right:0;bottom:0;left:0;opacity:0}.vot-segmented-button .vot-segment::before,.vot-segmented-button .vot-segment-only-icon::before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity .2s}.vot-segmented-button .vot-segment::after,.vot-segmented-button .vot-segment-only-icon::after{background:radial-gradient(circle at center, currentColor 1%, transparent 1%) center/10000% 10000% no-repeat;transition:opacity 1s,background-size .5s}.vot-segmented-button .vot-segment:hover::before,.vot-segmented-button .vot-segment-only-icon:hover::before{opacity:.04}.vot-segmented-button .vot-segment:active::after,.vot-segmented-button .vot-segment-only-icon:active::after{opacity:.16;background-size:100% 100%;transition:background-size 0s}.vot-segmented-button .vot-segment-only-icon{min-width:32px;padding:0}.vot-segmented-button .vot-segment-label{margin-left:8px;white-space:nowrap}.vot-segmented-button[data-status=success] .vot-translate-button{color:rgb(var(--vot-primary-rgb, 33, 150, 243));fill:rgb(var(--vot-primary-rgb, 33, 150, 243))}.vot-segmented-button[data-status=error] .vot-translate-button{color:#f28b82;fill:#f28b82}.vot-segmented-button svg{width:fit-content}.vot-menu{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);overflow:hidden;position:absolute;left:50%;top:calc(5rem + 32px + 16px);user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);border-radius:8px;font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;min-width:300px;cursor:default;z-index:100;visibility:visible;opacity:1;transform-origin:top;transform:translate(-50%) scale(1);transition:opacity .3s,transform .1s}.vot-menu *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-menu[hidden]{pointer-events:none;display:block !important;visibility:hidden;opacity:0;transform:translate(-50%) scale(0)}.vot-menu-content-wrapper{display:flex;flex-direction:column;min-height:100px;max-height:calc(var(--vot-container-height, 75vh) - (5rem + 32px + 16px)*2);overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-menu-header-container:empty{padding:0 0 16px 0}.vot-menu-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-menu-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0;text-align:start}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 16px;gap:8px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar,.vot-menu-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-menu-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-menu-footer-container:empty{padding:16px 0 0 0}.vot-dialog-container{visibility:visible;position:absolute;z-index:10000}.vot-dialog-container[hidden]{display:block !important;pointer-events:none;visibility:hidden}.vot-dialog-container *{-webkit-box-sizing:border-box !important;-moz-box-sizing:border-box !important;box-sizing:border-box !important}.vot-dialog-backdrop{background-color:rgba(0,0,0,.6);position:fixed;top:0;right:0;bottom:0;left:0;opacity:1;transition:opacity .3s}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog{--vot-helper-surface-rgb: var(--vot-surface-rgb, 255, 255, 255);--vot-helper-surface: rgb(var(--vot-helper-surface-rgb));--vot-helper-onsurface-rgb: var(--vot-onsurface-rgb, 0, 0, 0);--vot-helper-onsurface: rgba(var(--vot-helper-onsurface-rgb), 0.87);display:block;position:fixed;top:50%;bottom:50%;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width, 512px),100%);height:fit-content;inset-inline-start:0px;inset-inline-end:0px;inset-block-start:0px;inset-block-end:0px;border-radius:8px;margin:auto;padding:0;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);box-shadow:0 0 16px rgba(0,0,0,.12),0 16px 16px rgba(0,0,0,.24);font-family:var(--vot-font-family, "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system);font-size:16px;line-height:1.5;user-select:none;visibility:visible;overflow:auto;overflow-y:hidden;opacity:1;transform-origin:center;transform:scale(1);transition:opacity .3s,transform .1s}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transform:scale(0.5);transition:opacity .1s,transform .2s}.vot-dialog-content-wrapper{display:flex;flex-direction:column;max-height:75vh;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;display:flex;min-height:31px}.vot-dialog-header-container:empty{padding:0 0 20px 0}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:4px;margin-top:4px}.vot-dialog-title-container{display:flex;flex:1;font-size:inherit;font-weight:inherit;margin:0;outline:0}.vot-dialog-title{flex:1;font-size:115.3846153846%;font-weight:bold;line-height:1;padding-bottom:16px;padding-inline-end:20px;padding-inline-start:20px;padding-top:20px}.vot-dialog-body-container{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:flex;flex-direction:column;min-height:1.375rem;overflow:auto;padding:0 20px;gap:16px;overscroll-behavior:contain;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), 0.1) var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar,.vot-dialog-body-container::-webkit-scrollbar-track{height:12px !important;width:12px !important;background:var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb{background:rgba(var(--vot-helper-onsurface-rgb), 0.1) !important;-webkit-border-radius:1ex !important;border:5px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border:3px solid var(--vot-helper-surface) !important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface) !important}.vot-dialog-footer-container{flex-shrink:0;display:flex;justify-content:flex-end;padding-bottom:16px;padding-inline-end:16px;padding-inline-start:16px;padding-top:16px}.vot-dialog-footer-container:empty{padding:20px 0 0 0}.vot-subtitles-widget{display:flex;justify-content:center;align-items:center;position:absolute;width:50%;max-height:100%;min-height:20%;z-index:100;left:25%;top:75%;pointer-events:none}.vot-subtitles{position:relative;max-width:100%;max-height:100%;width:max-content;background:var(--vot-subtitles-background, rgba(46, 47, 52, 0.8));color:var(--vot-subtitles-color, rgb(227, 227, 227));border-radius:1rem;pointer-events:all;padding:1rem;font-size:2rem;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.vot-subtitles .passed{color:var(--vot-subtitles-passed-color, rgb(33, 150, 243))}:root{--vot-font-family: "Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system;--vot-primary-rgb: 139, 180, 245;--vot-onprimary-rgb: 32, 33, 36;--vot-surface-rgb: 32, 33, 36;--vot-onsurface-rgb: 227, 227, 227;--vot-subtitles-background: rgba(var(--vot-surface-rgb, 46, 47, 52), 0.8);--vot-subtitles-color: rgb(var(--vot-onsurface-rgb, 227, 227, 227));--vot-subtitles-passed-color: rgb(var(--vot-primary-rgb, 33, 150, 243))}vot-block{display:block}`, ""]); // Exports /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); @@ -415,23 +423,6 @@ module.exports = insertBySelector; /***/ }), -/***/ "./node_modules/style-loader/dist/runtime/insertStyleElement.js": -/***/ ((module) => { - -"use strict"; - - -/* istanbul ignore next */ -function insertStyleElement(options) { - var element = document.createElement("style"); - options.setAttributes(element, options.attributes); - options.insert(element, options.options); - return element; -} -module.exports = insertStyleElement; - -/***/ }), - /***/ "./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js": /***/ ((module, __unused_webpack_exports, __webpack_require__) => { @@ -536,6 +527,22 @@ function styleTagTransform(css, styleElement) { } module.exports = styleTagTransform; +/***/ }), + +/***/ "./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js": +/***/ ((module) => { + +module.exports = function () { + return (function styleLoaderInsertStyleElement(options) { + options.styleTagTransform = function monkeyStyleTagTransform(css, styleElement) { + styleElement?.remove(); + GM_addStyle(css); + }; + return document.createElement("style"); +}).apply(null, arguments) +} + + /***/ }), /***/ "./src/config/config.js": @@ -543,25 +550,21 @@ module.exports = styleTagTransform; "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ EY: () => (/* binding */ defaultDetectService), -/* harmony export */ I1: () => (/* binding */ yandexHmacKey), -/* harmony export */ Rr: () => (/* binding */ yandexUserAgent), -/* harmony export */ e6: () => (/* binding */ m3u8ProxyHost), -/* harmony export */ ez: () => (/* binding */ proxyWorkerHost), -/* harmony export */ iF: () => (/* binding */ workerHost), -/* harmony export */ jm: () => (/* binding */ detectUrls), -/* harmony export */ kF: () => (/* binding */ defaultTranslationService), -/* harmony export */ rm: () => (/* binding */ translateUrls), -/* harmony export */ sN: () => (/* binding */ defaultAutoVolume) +/* harmony export */ Cc: () => (/* binding */ yandexUserAgent), +/* harmony export */ JD: () => (/* binding */ defaultAutoVolume), +/* harmony export */ K2: () => (/* binding */ defaultDetectService), +/* harmony export */ Pm: () => (/* binding */ proxyWorkerHost), +/* harmony export */ QL: () => (/* binding */ detectUrls), +/* harmony export */ S7: () => (/* binding */ yandexHmacKey), +/* harmony export */ mE: () => (/* binding */ defaultTranslationService), +/* harmony export */ rl: () => (/* binding */ workerHost), +/* harmony export */ rw: () => (/* binding */ translateUrls), +/* harmony export */ se: () => (/* binding */ m3u8ProxyHost) /* harmony export */ }); -/* harmony import */ var _utils_utils_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils/utils.js"); - - // CONFIGURATION const workerHost = "api.browser.yandex.ru"; -const m3u8ProxyHost = "m3u8proxy.toil-dump.workers.dev"; -const proxyWorkerHost = - _utils_utils_js__WEBPACK_IMPORTED_MODULE_0__/* .lang */ .KQ === "uk" ? "vot-new.toil-dump.workers.dev" : "vot-worker.onrender.com"; // used for cloudflare version (vot-new.toil-dump.workers.dev || vot-worker.onrender.com) +const m3u8ProxyHost = "m3u8-proxy.toil.cc"; // used for striming +const proxyWorkerHost = "vot.toil.cc"; // used for cloudflare version (vot-new.toil-dump.workers.dev || vot-worker.onrender.com) const yandexHmacKey = "xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm"; const yandexUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36"; @@ -581,203 +584,6 @@ const translateUrls = { -/***/ }), - -/***/ "./src/localization/localizationProvider.js": -/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { - -"use strict"; - -// EXPORTS -__webpack_require__.d(__webpack_exports__, { - Z: () => (/* binding */ availableLocales), - V: () => (/* binding */ localizationProvider) -}); - -;// CONCATENATED MODULE: ./src/localization/locales/en.json -const en_namespaceObject = JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}'); -// EXTERNAL MODULE: ./src/utils/debug.js -var debug = __webpack_require__("./src/utils/debug.js"); -// EXTERNAL MODULE: ./src/utils/storage.js -var storage = __webpack_require__("./src/utils/storage.js"); -;// CONCATENATED MODULE: ./src/localization/localizationProvider.js - - - - -const localesVersion = 2; -const localesUrl = `https://raw.githubusercontent.com/ilyhalight/voice-over-translation/${ - false ? 0 : "master" -}/src/localization/locales`; - -const availableLocales = [ - "auto", - "en", - "ru", - - "af", - "am", - "ar", - "az", - "bg", - "bn", - "bs", - "ca", - "cs", - "cy", - "da", - "de", - "el", - "es", - "et", - "eu", - "fa", - "fi", - "fr", - "gl", - "hi", - "hr", - "hu", - "hy", - "id", - "it", - "ja", - "jv", - "kk", - "km", - "kn", - "ko", - "lo", - "mk", - "ml", - "mn", - "ms", - "mt", - "my", - "ne", - "nl", - "pa", - "pl", - "pt", - "ro", - "si", - "sk", - "sl", - "sq", - "sr", - "su", - "sv", - "sw", - "tr", - "uk", - "ur", - "uz", - "vi", - "zh", - "zu", -]; - -const localizationProvider = new (class { - lang = "en"; - locale = {}; - gmValues = [ - "locale-phrases", - "locale-lang", - "locale-version", - "locale-lang-override", - ]; - - constructor() { - const langOverride = storage/* votStorage */.i.syncGet("locale-lang-override", "auto"); - if (langOverride && langOverride !== "auto") { - this.lang = langOverride; - } else { - this.lang = - (navigator.language || navigator.userLanguage) - ?.substr(0, 2) - ?.toLowerCase() ?? "en"; - } - this.setLocaleFromJsonString(storage/* votStorage */.i.syncGet("locale-phrases", "")); - } - - reset() { - this.gmValues.forEach((v) => storage/* votStorage */.i.syncDelete(v)); - } - - async update(force = false) { - if ( - !force && - (await storage/* votStorage */.i.get("locale-version", 0, true)) === localesVersion && - (await storage/* votStorage */.i.get("locale-lang")) === this.lang - ) { - return; - } - - debug/* default */.Z.log("Updating locale..."); - - await fetch(`${localesUrl}/${this.lang}.json`) - .then((response) => { - if (response.status === 200) return response.text(); - throw response.status; - }) - .then(async (text) => { - await storage/* votStorage */.i.set("locale-phrases", text); - this.setLocaleFromJsonString(text); - const version = this.getFromLocale(this.locale, "__version__"); - if (typeof version === "number") - await storage/* votStorage */.i.set("locale-version", version); - await storage/* votStorage */.i.set("locale-lang", this.lang); - }) - .catch(async (error) => { - console.error( - "[VOT] [localizationProvider] failed get locale, cause:", - error, - ); - this.setLocaleFromJsonString( - await storage/* votStorage */.i.get("locale-phrases", ""), - ); - }); - } - - setLocaleFromJsonString(json) { - try { - this.locale = JSON.parse(json) ?? {}; - } catch (exception) { - console.error("[VOT] [localizationProvider]", exception); - this.locale = {}; - } - } - - getFromLocale(locale, key) { - const result = key.split(".").reduce((locale, key) => { - if (typeof locale === "object" && locale) return locale[key]; - return undefined; - }, locale); - if (result === undefined) { - console.warn( - "[VOT] [localizationProvider] locale", - locale, - "doesn't contain key", - key, - ); - } - return result; - } - - getDefault(key) { - return this.getFromLocale(en_namespaceObject, key) ?? key; - } - - get(key) { - return ( - this.getFromLocale(this.locale, key) ?? - this.getFromLocale(en_namespaceObject, key) ?? - key - ); - } -})(); - - /***/ }), /***/ "./src/utils/debug.js": @@ -785,7 +591,7 @@ const localizationProvider = new (class { "use strict"; /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ Z: () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ A: () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); const debug = {}; debug.log = (...text) => { @@ -804,505 +610,65 @@ debug.log = (...text) => { /***/ }), -/***/ "./src/utils/storage.js": +/***/ "./src/yandexRequest.js": /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { "use strict"; +__webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ i: () => (/* binding */ votStorage) +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); -/* harmony import */ var _debug_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/utils/debug.js"); +/* harmony import */ var _config_config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/config/config.js"); +/* harmony import */ var _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/utils/debug.js"); -const votStorage = new (class { - constructor() { - this.gmSupport = typeof GM_getValue === "function"; - _debug_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z.log(`GM Storage Status: ${this.gmSupport}`); + +async function yandexRequest(path, body, headers, callback) { + try { + _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.log("yandexRequest:", path); + // Create a fetch options object with headers and body + const options = { + url: `https://${_config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .workerHost */ .rl}${path}`, + method: "POST", + headers: { + ...{ + Accept: "application/x-protobuf", + "Accept-Language": "en", + "Content-Type": "application/x-protobuf", + "User-Agent": _config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .yandexUserAgent */ .Cc, + Pragma: "no-cache", + "Cache-Control": "no-cache", + "Sec-Fetch-Mode": "no-cors", + "sec-ch-ua": null, + "sec-ch-ua-mobile": null, + "sec-ch-ua-platform": null, + }, + ...headers, + }, + binary: true, + data: new Blob([body]), + responseType: "arraybuffer", + }; + // Send the request using GM_xmlhttpRequest + GM_xmlhttpRequest({ + ...options, + onload: (http) => { + _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .A.log("yandexRequest:", http.status, http); + callback(http.status === 200, http.response); + }, + onerror: (error) => { + console.error("[VOT]", error); + callback(false); + }, + }); + } catch (exception) { + console.error("[VOT]", exception); + // Handle errors + callback(false); } +} - syncGet(name, def = undefined, toNumber = false) { - if (this.gmSupport) { - return GM_getValue(name, def); - } - - let val = window.localStorage.getItem(name); - if (name === "udemyData" && typeof val === "string") { - try { - val = JSON.parse(val); - } catch { - val = def; - } - } - - return toNumber ? Number(val) ?? Number(def) : val ?? def; - } - - async get(name, def = undefined, toNumber = false) { - if (this.gmSupport) { - return await GM_getValue(name, def); - } - - return new Promise((resolve) => { - resolve(this.syncGet(name, def, toNumber)); - }); - } - - syncSet(name, value) { - if (this.gmSupport) { - return GM_setValue(name, value); - } - - if (name === "udemyData") { - value = JSON.stringify(value); - } - - return window.localStorage.setItem(name, value); - } - - async set(name, value) { - if (this.gmSupport) { - return await GM_setValue(name, value); - } - - return new Promise((resolve) => { - resolve(this.syncSet(name, value)); - }); - } - - syncDelete(name) { - if (this.gmSupport) { - return GM_deleteValue(name); - } - - return window.localStorage.removeItem(name); - } - - async delete(name) { - if (this.gmSupport) { - return await GM_deleteValue(name); - } - - return new Promise((resolve) => { - resolve(this.syncDelete(name)); - }); - } - - syncList() { - if (this.gmSupport) { - return GM_listValues(); - } - - return [ - "autoTranslate", - "dontTranslateLanguage", - "dontTranslateYourLang", - "autoSetVolumeYandexStyle", - "showVideoSlider", - "syncVolume", - "subtitlesMaxLength", - "highlightWords", - "responseLanguage", - "defaultVolume", - "udemyData", - "audioProxy", - "showPiPButton", - "locale-version", - "locale-lang", - "locale-phrases", - ]; - } - - async list() { - if (this.gmSupport) { - return await GM_listValues(); - } - - return new Promise((resolve) => { - resolve(this.syncList()); - }); - } -})(); - - -/***/ }), - -/***/ "./src/utils/utils.js": -/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { - -"use strict"; -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ KQ: () => (/* binding */ lang), -/* harmony export */ PG: () => (/* binding */ secsToStrTime), -/* harmony export */ QZ: () => (/* binding */ initHls), -/* harmony export */ _v: () => (/* binding */ sleep), -/* harmony export */ eL: () => (/* binding */ langTo6391), -/* harmony export */ gJ: () => (/* binding */ getVideoId), -/* harmony export */ qq: () => (/* binding */ isPiPAvailable) -/* harmony export */ }); -/* unused harmony export waitForElm */ -/* harmony import */ var _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/localization/localizationProvider.js"); - - -const userlang = navigator.language || navigator.userLanguage; -const lang = userlang?.substr(0, 2)?.toLowerCase() ?? "en"; - -if (!String.prototype.format) { - // https://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format - // syntax example: "is {0} function".format("format") - String.prototype.format = function () { - // store arguments in an array - var args = arguments; - // use replace to iterate over the string - // select the match and check if the related argument is present - // if yes, replace the match with the argument - return this.replace(/{(\d+)}/g, function (match, index) { - // check if the argument is present - return typeof args[index] != "undefined" ? args[index] : match; - }); - }; -} - -function waitForElm(selector) { - // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists - return new Promise((resolve) => { - const element = document.querySelector(selector); - if (element) { - return resolve(element); - } - - const observer = new MutationObserver(() => { - const element = document.querySelector(selector); - if (element) { - resolve(element); - observer.disconnect(); - } - }); - - observer.observe(document.body, { - childList: true, - subtree: true, - once: true, - }); - }); -} - -const sleep = (m) => new Promise((r) => setTimeout(r, m)); - -const getVideoId = (service, video) => { - const url = new URL(window.location.href); - - switch (service) { - case "piped": - case "invidious": - case "youtube": - return ( - url.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1] || - url.searchParams.get("v") - ); - case "vk": - if (url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)) { - return url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1); - } else if (url.searchParams.get("z")) { - return url.searchParams.get("z").split("/")[0]; - } else if (url.searchParams.get("oid") && url.searchParams.get("id")) { - return `video-${Math.abs( - url.searchParams.get("oid"), - )}_${url.searchParams.get("id")}`; - } else { - return false; - } - case "nine_gag": - case "9gag": - case "gag": - return url.pathname.match(/gag\/([^/]+)/)?.[1]; - case "twitch": - if (/^m\.twitch\.tv$/.test(window.location.hostname)) { - const linkUrl = document.head.querySelector('link[rel="canonical"]'); - return ( - linkUrl?.href.match(/videos\/([^/]+)/)?.[0] || url.pathname.slice(1) - ); - } else if (/^player\.twitch\.tv$/.test(window.location.hostname)) { - return `videos/${url.searchParams.get("video")}`; - } else if (/^clips\.twitch\.tv$/.test(window.location.hostname)) { - // get link to twitch channel (ex.: https://www.twitch.tv/xqc) - const channelLink = document.querySelector( - ".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']", - ); - if (!channelLink) { - return false; - } - - const channelName = channelLink.href.replace( - "https://www.twitch.tv/", - "", - ); - return `${channelName}/clip/${url.searchParams.get("clip")}`; - } else if (url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)) { - return url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]; - } else { - return url.pathname.match(/(?:videos)\/([^/]+)/)?.[0]; - } - case "proxytok": - return url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; - case "tiktok": { - let id = url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; - if (!id) { - const playerEl = video.closest(".xgplayer-playing, .tiktok-web-player"); - const itemEl = playerEl?.closest( - 'div[data-e2e="recommend-list-item-container"]', - ); - const authorEl = itemEl?.querySelector( - 'a[data-e2e="video-author-avatar"]', - ); - if (playerEl && authorEl) { - const videoId = playerEl.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1); - const author = authorEl.href?.match(/.*(@.*)$/)?.at(1); - if (videoId && author) { - id = `${author}/video/${videoId}`; - } - } - } - return id; - } - case "vimeo": - return ( - url.pathname.match(/[^/]+\/[^/]+$/)?.[0] || - url.pathname.match(/[^/]+$/)?.[0] - ); - case "xvideos": - return url.pathname.match(/[^/]+\/[^/]+$/)?.[0]; - case "pornhub": - return ( - url.searchParams.get("viewkey") || - url.pathname.match(/embed\/([^/]+)/)?.[1] - ); - case "twitter": - return url.pathname.match(/status\/([^/]+)/)?.[1]; - case "udemy": - return url.pathname; - case "rumble": - return url.pathname; - case "facebook": - // ...watch?v=XXX - // CHANNEL_ID/videos/VIDEO_ID/ - // returning "Видео недоступно для перевода" - - // fb.watch/YYY - // returning "Возникла ошибка, попробуйте позже" - if (url.searchParams.get("v")) { - return url.searchParams.get("v"); - } - - return false; - case "rutube": - return url.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1]; - case "coub": - if (url.pathname.includes("/view")) { - return url.pathname.match(/view\/([^/]+)/)?.[1]; - } else if (url.pathname.includes("/embed")) { - return url.pathname.match(/embed\/([^/]+)/)?.[1]; - } else { - return document.querySelector(".coub.active")?.dataset?.permalink; - } - case "bilibili": { - const bvid = url.searchParams.get("bvid"); - if (bvid) { - return bvid; - } else { - let vid = url.pathname.match(/video\/([^/]+)/)?.[1]; - if (vid && url.search && url.searchParams.get("p") !== null) { - vid += `/?p=${url.searchParams.get("p")}`; - } - return vid; - } - } - case "mail_ru": - if (url.pathname.startsWith("/v/") || url.pathname.startsWith("/mail/")) { - return url.pathname; - } else if (url.pathname.match(/video\/embed\/([^/]+)/)) { - const referer = document.querySelector( - ".b-video-controls__mymail-link", - ); - if (!referer) { - return false; - } - - return referer?.href.split("my.mail.ru")?.[1]; - } - return false; - case "bitchute": - return url.pathname.match(/video\/([^/]+)/)?.[1]; - case "coursera": - // ! LINK SHOULD BE LIKE THIS https://www.coursera.org/learn/learning-how-to-learn/lecture/75EsZ - // return url.pathname.match(/lecture\/([^/]+)\/([^/]+)/)?.[1]; // <--- COURSE PREVIEW - return url.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0]; // <--- COURSE PASSING (IF YOU LOGINED TO COURSERA) - case "eporner": - // ! LINK SHOULD BE LIKE THIS eporner.com/video-XXXXXXXXX/isdfsd-dfjsdfjsdf-dsfsdf-dsfsda-dsad-ddsd - return url.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0]; - case "peertube": - return url.pathname.match(/\/w\/([^/]+)/)?.[0]; - case "dailymotion": { - // we work in the context of the player - // geo.dailymotion.com - - const plainPlayerConfig = Array.from(document.scripts).filter((s) => - s.innerText.trim().includes("window.__PLAYER_CONFIG__ = {"), - ); - if (!plainPlayerConfig.length) { - return false; - } - - try { - let clearPlainConfig = plainPlayerConfig[0].innerText - .trim() - .replace("window.__PLAYER_CONFIG__ = ", ""); - if (clearPlainConfig.endsWith("};")) { - clearPlainConfig = clearPlainConfig.substring( - 0, - clearPlainConfig.length - 1, - ); - } - const playerConfig = JSON.parse(clearPlainConfig); - const videoUrl = - playerConfig.context.embedder ?? playerConfig.context.http_referer; - console.log(videoUrl, playerConfig); - return videoUrl.match(/\/video\/([^/]+)/)?.[1]; - } catch (e) { - console.error("[VOT]", e); - return false; - } - } - case "trovo": { - if (!url.pathname.startsWith("/s/")) { - return false; - } - - const vid = url.searchParams.get("vid"); - if (!vid) { - return false; - } - - const path = url.pathname.match(/([^/]+)\/([\d]+)/)?.[0]; - if (!path) { - return false; - } - - return `${path}?vid=${vid}`; - } - case "yandexdisk": - return url.pathname.match(/\/[i|s|d]\/([^/]+)/)?.[1]; - case "coursehunter": { - const courseId = url.pathname.match(/\/course\/([^/]+)/)?.[1]; - return courseId ? courseId + url.search : false; - } - default: - return false; - } -}; - -function secsToStrTime(secs) { - const minutes = Math.floor(secs / 60); - const seconds = Math.floor(secs % 60); - if (minutes >= 60) { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V.get("translationTakeMoreThanHour"); - } else if (minutes >= 10 && minutes % 10) { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V - .get("translationTakeApproximatelyMinutes") - .format(minutes); - } else if (minutes == 1 || (minutes == 0 && seconds > 0)) { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V.get("translationTakeAboutMinute"); - } else { - return _localization_localizationProvider_js__WEBPACK_IMPORTED_MODULE_0__/* .localizationProvider */ .V - .get("translationTakeApproximatelyMinute") - .format(minutes); - } -} - -function langTo6391(lang) { - // convert lang to ISO 639-1 - return lang.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]; -} - -function isPiPAvailable() { - return ( - "pictureInPictureEnabled" in document && document.pictureInPictureEnabled - ); -} - -function initHls() { - return typeof Hls != "undefined" && Hls?.isSupported() - ? new Hls({ - debug: false, // turn it on manually if necessary - lowLatencyMode: true, - backBufferLength: 90, - }) - : undefined; -} - - - - -/***/ }), - -/***/ "./src/yandexRequest.js": -/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) -/* harmony export */ }); -/* harmony import */ var _config_config_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/config/config.js"); -/* harmony import */ var _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/utils/debug.js"); - - - -async function yandexRequest(path, body, headers, callback) { - try { - _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .Z.log("yandexRequest:", path); - // Create a fetch options object with headers and body - const options = { - url: `https://${_config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .workerHost */ .iF}${path}`, - method: "POST", - headers: { - ...{ - Accept: "application/x-protobuf", - "Accept-Language": "en", - "Content-Type": "application/x-protobuf", - "User-Agent": _config_config_js__WEBPACK_IMPORTED_MODULE_0__/* .yandexUserAgent */ .Rr, - Pragma: "no-cache", - "Cache-Control": "no-cache", - "Sec-Fetch-Mode": "no-cors", - "sec-ch-ua": null, - "sec-ch-ua-mobile": null, - "sec-ch-ua-platform": null, - }, - ...headers, - }, - binary: true, - data: new Blob([body]), - responseType: "arraybuffer", - }; - // Send the request using GM_xmlhttpRequest - GM_xmlhttpRequest({ - ...options, - onload: (http) => { - _utils_debug_js__WEBPACK_IMPORTED_MODULE_1__/* ["default"] */ .Z.log("yandexRequest:", http.status, http); - callback(http.status === 200, http.response); - }, - onerror: (error) => { - console.error("[VOT]", error); - callback(false); - }, - }); - } catch (exception) { - console.error("[VOT]", exception); - // Handle errors - callback(false); - } -} - -/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (yandexRequest); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (yandexRequest); /***/ }) @@ -1385,71 +751,90 @@ var __webpack_exports__ = {}; (() => { "use strict"; -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js -var injectStylesIntoStyleTag = __webpack_require__("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); -var injectStylesIntoStyleTag_default = /*#__PURE__*/__webpack_require__.n(injectStylesIntoStyleTag); -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleDomAPI.js -var styleDomAPI = __webpack_require__("./node_modules/style-loader/dist/runtime/styleDomAPI.js"); -var styleDomAPI_default = /*#__PURE__*/__webpack_require__.n(styleDomAPI); -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertBySelector.js -var insertBySelector = __webpack_require__("./node_modules/style-loader/dist/runtime/insertBySelector.js"); -var insertBySelector_default = /*#__PURE__*/__webpack_require__.n(insertBySelector); -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js -var setAttributesWithoutAttributes = __webpack_require__("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"); -var setAttributesWithoutAttributes_default = /*#__PURE__*/__webpack_require__.n(setAttributesWithoutAttributes); -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertStyleElement.js -var insertStyleElement = __webpack_require__("./node_modules/style-loader/dist/runtime/insertStyleElement.js"); -var insertStyleElement_default = /*#__PURE__*/__webpack_require__.n(insertStyleElement); -// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleTagTransform.js -var styleTagTransform = __webpack_require__("./node_modules/style-loader/dist/runtime/styleTagTransform.js"); -var styleTagTransform_default = /*#__PURE__*/__webpack_require__.n(styleTagTransform); -// EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss -var main = __webpack_require__("./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss"); -;// CONCATENATED MODULE: ./src/styles/main.scss - - - - - - - - - - - -var options = {}; - -options.styleTagTransform = (styleTagTransform_default()); -options.setAttributes = (setAttributesWithoutAttributes_default()); - - options.insert = insertBySelector_default().bind(null, "head"); - -options.domAPI = (styleDomAPI_default()); -options.insertStyleElement = (insertStyleElement_default()); - -var update = injectStylesIntoStyleTag_default()(main/* default */.Z, options); - - +;// CONCATENATED MODULE: ./src/config/alternativeUrls.js +// Sites host Invidious. I tested the performance only on invidious.kevin.rocks, youtu.be and inv.vern.cc +const sitesInvidious = [ + "invidious.snopyta.org", + "yewtu.be", + "invidious.kavin.rocks", + "vid.puffyan.us", + "invidious.namazso.eu", + "inv.riverside.rocks", + "yt.artemislena.eu", + "invidious.flokinet.to", + "invidious.esmailelbob.xyz", + "y.com.sb", + "invidious.nerdvpn.de", + "inv.vern.cc", + "invidious.slipfox.xyz", + "invidio.xamh.de", + "invidious.dhusch.de", +]; +// Sites host Piped. I tested the performance only on piped.video +const sitesPiped = [ + "piped.video", + "piped.tokhmi.xyz", + "piped.moomoo.me", + "piped.syncpundit.io", + "piped.mha.fi", + "watch.whatever.social", + "piped.garudalinux.org", + "efy.piped.pages.dev", + "watch.leptons.xyz", + "piped.lunar.icu", + "yt.dc09.ru", + "piped.mint.lgbt", + "il.ax", + "piped.privacy.com.de", + "piped.esmailelbob.xyz", + "piped.projectsegfau.lt", + "piped.in.projectsegfau.lt", + "piped.us.projectsegfau.lt", + "piped.privacydev.net", + "piped.palveluntarjoaja.eu", + "piped.smnz.de", + "piped.adminforge.de", + "piped.qdi.fi", + "piped.hostux.net", + "piped.chauvet.pro", + "piped.jotoma.de", + "piped.pfcd.me", + "piped.frontendfriendly.xyz", +]; - /* harmony default export */ const styles_main = (main/* default */.Z && main/* default */.Z.locals ? main/* default */.Z.locals : undefined); +const sitesProxyTok = [ + "proxitok.pabloferreiro.es", + "proxitok.pussthecat.org", + "tok.habedieeh.re", + "proxitok.esmailelbob.xyz", + "proxitok.privacydev.net", + "tok.artemislena.eu", + "tok.adminforge.de", + "tik.hostux.net", // maybe instance doesn't working + "tt.vern.cc", + "cringe.whatever.social", + "proxitok.lunar.icu", + "proxitok.privacy.com.de", // maybe instance doesn't working +]; -// EXTERNAL MODULE: ./src/localization/localizationProvider.js + 1 modules -var localizationProvider = __webpack_require__("./src/localization/localizationProvider.js"); -;// CONCATENATED MODULE: ./src/utils/VOTLocalizedError.js +// Sites host Peertube. I tested the performance only on dalek.zone and tube.shanti.cafe +const sitesPeertube = [ + "peertube.1312.media", + "tube.shanti.cafe", + "bee-tube.fr", + "video.sadmin.io", + "dalek.zone", + "review.peertube.biz", + "peervideo.club", + "tube.la-dina.net", + "peertube.tmp.rcp.tf", +]; -class VOTLocalizedError extends Error { - constructor(message) { - super(localizationProvider/* localizationProvider */.V.getDefault(message)); - this.name = "VOTLocalizedError"; - this.unlocalizedMessage = message; - this.localizedMessage = localizationProvider/* localizationProvider */.V.get(message); - } -} -// EXTERNAL MODULE: ./src/utils/debug.js -var debug = __webpack_require__("./src/utils/debug.js"); +// EXTERNAL MODULE: ./src/config/config.js +var config = __webpack_require__("./src/config/config.js"); ;// CONCATENATED MODULE: ./src/config/constants.js // available languages for translation const availableLangs = [ @@ -1540,1049 +925,1437 @@ const cfOnlyExtensions = [ -// EXTERNAL MODULE: ./src/utils/utils.js -var utils = __webpack_require__("./src/utils/utils.js"); -// EXTERNAL MODULE: ./src/config/config.js -var config = __webpack_require__("./src/config/config.js"); -// EXTERNAL MODULE: ./src/utils/storage.js -var storage = __webpack_require__("./src/utils/storage.js"); -;// CONCATENATED MODULE: ./src/utils/translateApis.js +;// CONCATENATED MODULE: ./src/localization/locales/en.json +const en_namespaceObject = /*#__PURE__*/JSON.parse('{"__version__":3,"recommended":"recommended","translateVideo":"Translate video","disableTranslate":"Turn off","translationSettings":"Translation settings","subtitlesSettings":"Subtitles settings","about":"About extension","resetSettings":"Reset settings","videoBeingTranslated":"The video is being translated","videoLanguage":"Video language","translationLanguage":"Translation language","translationTake":"The translation will take","translationTakeMoreThanHour":"The translation will take more than an hour","translationTakeAboutMinute":"The translation will take about a minute","translationTakeFewMinutes":"The translation will take a few minutes","translationTakeApproximatelyMinutes":"The translation will take approximately {0} minutes","translationTakeApproximatelyMinute":"The translation will take approximately {0} minutes","unSupportedExtensionError":"Error! {0} is not supported by this version of the extension!\\n\\nPlease use the cloudflare version of the VOT extension.","requestTranslationFailed":"Failed to request video translation","audioNotReceived":"Audio link not received","grantPermissionToAutoPlay":"Grant permission to autoplay","neededAdditionalExtension":"An additional extension is needed to support this site","audioFormatNotSupported":"The audio format is not supported","VOTAutoTranslate":"Translate on open","VOTDontTranslateYourLang":"Do not translate from my language","VOTVolume":"Video volume","VOTVolumeTranslation":"Translation Volume","VOTAutoSetVolume":"Reduce video volume to ","VOTShowVideoSlider":"Video volume slider","VOTSyncVolume":"Link translation and video volume","VOTAudioProxy":"Proxy received audio","VOTDisableFromYourLang":"You have disabled the translation of the video in your language","VOTLiveNotSupported":"Translation of live streams is not supported","VOTPremiere":"Wait for the premiere to end before translating","VOTVideoIsTooLong":"Video is too long","VOTNoVideoIDFound":"No video ID found","VOTSubtitles":"Subtitles","VOTSubtitlesDisabled":"Disabled","VOTSubtitlesMaxLength":"Subtitles max length","VOTHighlightWords":"Highlight words","VOTTranslatedFrom":"translated from","VOTAutogenerated":"autogenerated","VOTSettings":"VOT Settings","VOTMenuLanguage":"Menu language","VOTAuthors":"Authors","VOTVersion":"Version","VOTLoader":"Loader","VOTBrowser":"Browser","VOTShowPiPButton":"Show PiP button","langs":{"auto":"Auto","af":"Afrikaans","ak":"Akan","sq":"Albanian","am":"Amharic","ar":"Arabic","hy":"Armenian","as":"Assamese","ay":"Aymara","az":"Azerbaijani","bn":"Bangla","eu":"Basque","be":"Belarusian","bho":"Bhojpuri","bs":"Bosnian","bg":"Bulgarian","my":"Burmese","ca":"Catalan","ceb":"Cebuano","zh":"Chinese","zh-Hans":"Chinese (Simplified)","zh-Hant":"Chinese (Traditional)","co":"Corsican","hr":"Croatian","cs":"Czech","da":"Danish","dv":"Divehi","nl":"Dutch","en":"English","eo":"Esperanto","et":"Estonian","ee":"Ewe","fil":"Filipino","fi":"Finnish","fr":"French","gl":"Galician","lg":"Ganda","ka":"Georgian","de":"German","el":"Greek","gn":"Guarani","gu":"Gujarati","ht":"Haitian Creole","ha":"Hausa","haw":"Hawaiian","iw":"Hebrew","hi":"Hindi","hmn":"Hmong","hu":"Hungarian","is":"Icelandic","ig":"Igbo","id":"Indonesian","ga":"Irish","it":"Italian","ja":"Japanese","jv":"Javanese","kn":"Kannada","kk":"Kazakh","km":"Khmer","rw":"Kinyarwanda","ko":"Korean","kri":"Krio","ku":"Kurdish","ky":"Kyrgyz","lo":"Lao","la":"Latin","lv":"Latvian","ln":"Lingala","lt":"Lithuanian","lb":"Luxembourgish","mk":"Macedonian","mg":"Malagasy","ms":"Malay","ml":"Malayalam","mt":"Maltese","mi":"Māori","mr":"Marathi","mn":"Mongolian","ne":"Nepali","nso":"Northern Sotho","no":"Norwegian","ny":"Nyanja","or":"Odia","om":"Oromo","ps":"Pashto","fa":"Persian","pl":"Polish","pt":"Portuguese","pa":"Punjabi","qu":"Quechua","ro":"Romanian","ru":"Russian","sm":"Samoan","sa":"Sanskrit","gd":"Scottish Gaelic","sr":"Serbian","sn":"Shona","sd":"Sindhi","si":"Sinhala","sk":"Slovak","sl":"Slovenian","so":"Somali","st":"Southern Sotho","es":"Spanish","su":"Sundanese","sw":"Swahili","sv":"Swedish","tg":"Tajik","ta":"Tamil","tt":"Tatar","te":"Telugu","th":"Thai","ti":"Tigrinya","ts":"Tsonga","tr":"Turkish","tk":"Turkmen","uk":"Ukrainian","ur":"Urdu","ug":"Uyghur","uz":"Uzbek","vi":"Vietnamese","cy":"Welsh","fy":"Western Frisian","xh":"Xhosa","yi":"Yiddish","yo":"Yoruba","zu":"Zulu"},"udemyAccessTokenExpired":"Your entered Udemy Access Token has expired","udemyModuleArgsNotFound":"Could not get udemy module data due to the fact that ModuleArgs was not found","VOTTranslationHelpNull":"Could not get the data required for the translate","enterUdemyAccessToken":"Enter Udemy Access Token","VOTUdemyData":"Udemy Data","streamNoConnectionToServer":"There is no connection to the server","searchField":"Search...","VOTTranslateAPIErrors":"Translate errors from the API","VOTTranslationService":"Translation Service","VOTDetectService":"Detect Service","VOTTranslatingError":"Translating the error","VOTProxyWorkerHost":"Enter the proxy worker address","VOTM3u8ProxyHost":"Enter the address of the m3u8 proxy worker","proxySettings":"Proxy Settings"}'); +// EXTERNAL MODULE: ./src/utils/debug.js +var debug = __webpack_require__("./src/utils/debug.js"); +;// CONCATENATED MODULE: ./src/utils/storage.js + + +const votStorage = new (class { + constructor() { + this.gmSupport = typeof GM_getValue === "function"; + debug/* default */.A.log(`GM Storage Status: ${this.gmSupport}`); + } + + syncGet(name, def = undefined, toNumber = false) { + if (this.gmSupport) { + return GM_getValue(name, def); + } + + let val = window.localStorage.getItem(name); + if (name === "udemyData" && typeof val === "string") { + try { + val = JSON.parse(val); + } catch { + val = def; + } + } + + return toNumber ? Number(val) ?? Number(def) : val ?? def; + } + + async get(name, def = undefined, toNumber = false) { + if (this.gmSupport) { + return await GM_getValue(name, def); + } + + return Promise.resolve(this.syncGet(name, def, toNumber)); + } + + syncSet(name, value) { + if (this.gmSupport) { + return GM_setValue(name, value); + } + + if (name === "udemyData") { + value = JSON.stringify(value); + } + + return window.localStorage.setItem(name, value); + } + + async set(name, value) { + if (this.gmSupport) { + return await GM_setValue(name, value); + } + + return Promise.resolve(this.syncSet(name, value)); + } + + syncDelete(name) { + if (this.gmSupport) { + return GM_deleteValue(name); + } + + return window.localStorage.removeItem(name); + } + + async delete(name) { + if (this.gmSupport) { + return await GM_deleteValue(name); + } + + return Promise.resolve(this.syncDelete(name)); + } + + syncList() { + if (this.gmSupport) { + return GM_listValues(); + } + + return [ + "autoTranslate", + "dontTranslateLanguage", + "dontTranslateYourLang", + "autoSetVolumeYandexStyle", + "showVideoSlider", + "syncVolume", + "subtitlesMaxLength", + "highlightWords", + "responseLanguage", + "defaultVolume", + "udemyData", + "audioProxy", + "showPiPButton", + "locale-version", + "locale-lang", + "locale-phrases", + ]; + } + + async list() { + if (this.gmSupport) { + return await GM_listValues(); + } + + return Promise.resolve(this.syncList()); + } +})(); + +;// CONCATENATED MODULE: ./src/localization/localizationProvider.js + + + + +const localesVersion = 2; +const localesUrl = `https://raw.githubusercontent.com/ilyhalight/voice-over-translation/${ + false ? 0 : "master" +}/src/localization/locales`; + +const availableLocales = [ + "auto", + "en", + "ru", + + "af", + "am", + "ar", + "az", + "bg", + "bn", + "bs", + "ca", + "cs", + "cy", + "da", + "de", + "el", + "es", + "et", + "eu", + "fa", + "fi", + "fr", + "gl", + "hi", + "hr", + "hu", + "hy", + "id", + "it", + "ja", + "jv", + "kk", + "km", + "kn", + "ko", + "lo", + "mk", + "ml", + "mn", + "ms", + "mt", + "my", + "ne", + "nl", + "pa", + "pl", + "pt", + "ro", + "si", + "sk", + "sl", + "sq", + "sr", + "su", + "sv", + "sw", + "tr", + "uk", + "ur", + "uz", + "vi", + "zh", + "zu", +]; + +const localizationProvider = new (class { + lang = "en"; + locale = {}; + gmValues = [ + "locale-phrases", + "locale-lang", + "locale-version", + "locale-lang-override", + ]; + + constructor() { + const langOverride = votStorage.syncGet("locale-lang-override", "auto"); + if (langOverride && langOverride !== "auto") { + this.lang = langOverride; + } else { + this.lang = + (navigator.language || navigator.userLanguage) + ?.substr(0, 2) + ?.toLowerCase() ?? "en"; + } + this.setLocaleFromJsonString(votStorage.syncGet("locale-phrases", "")); + } + + reset() { + this.gmValues.forEach((v) => votStorage.syncDelete(v)); + } + + async update(force = false) { + if ( + !force && + (await votStorage.get("locale-version", 0, true)) === localesVersion && + (await votStorage.get("locale-lang")) === this.lang + ) { + return; + } + debug/* default */.A.log("Updating locale..."); + await fetch(`${localesUrl}/${this.lang}.json`) + .then((response) => { + if (response.status === 200) return response.text(); + throw response.status; + }) + .then(async (text) => { + await votStorage.set("locale-phrases", text); + this.setLocaleFromJsonString(text); + const version = this.getFromLocale(this.locale, "__version__"); + if (typeof version === "number") + await votStorage.set("locale-version", version); + await votStorage.set("locale-lang", this.lang); + }) + .catch(async (error) => { + console.error( + "[VOT] [localizationProvider] failed get locale, cause:", + error, + ); + this.setLocaleFromJsonString( + await votStorage.get("locale-phrases", ""), + ); + }); + } -const HTTP_TIMEOUT = 3000; + setLocaleFromJsonString(json) { + try { + this.locale = JSON.parse(json) ?? {}; + } catch (exception) { + console.error("[VOT] [localizationProvider]", exception); + this.locale = {}; + } + } -async function fetchWithTimeout(url, options) { - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT); + getFromLocale(locale, key) { + const result = key.split(".").reduce((locale, key) => { + if (typeof locale === "object" && locale) return locale[key]; + return undefined; + }, locale); + if (result === undefined) { + console.warn( + "[VOT] [localizationProvider] locale", + locale, + "doesn't contain key", + key, + ); + } + return result; + } - try { - return await fetch(url, { - ...options, - signal: controller.signal, - }); - } catch (error) { - console.error("Fetch timed-out. Error:", error); - return error; - } finally { - clearTimeout(timeoutId); + getDefault(key) { + return this.getFromLocale(en_namespaceObject, key) ?? key; } -} -const YandexTranslateAPI = { - async translate(text, lang) { - // Limit: 10k symbols - // - // Lang examples: - // en-ru, uk-ru, ru-en... - // ru, en (instead of auto-ru, auto-en) + get(key) { + return ( + this.getFromLocale(this.locale, key) ?? + this.getFromLocale(en_namespaceObject, key) ?? + key + ); + } +})(); - try { - const response = await fetchWithTimeout(config/* translateUrls */.rm.yandex, { - method: "POST", - headers: { - "content-type": "application/json", - }, - body: JSON.stringify({ - text, - lang, - }), - }); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js +var injectStylesIntoStyleTag = __webpack_require__("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"); +var injectStylesIntoStyleTag_default = /*#__PURE__*/__webpack_require__.n(injectStylesIntoStyleTag); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleDomAPI.js +var styleDomAPI = __webpack_require__("./node_modules/style-loader/dist/runtime/styleDomAPI.js"); +var styleDomAPI_default = /*#__PURE__*/__webpack_require__.n(styleDomAPI); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertBySelector.js +var insertBySelector = __webpack_require__("./node_modules/style-loader/dist/runtime/insertBySelector.js"); +var insertBySelector_default = /*#__PURE__*/__webpack_require__.n(insertBySelector); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js +var setAttributesWithoutAttributes = __webpack_require__("./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js"); +var setAttributesWithoutAttributes_default = /*#__PURE__*/__webpack_require__.n(setAttributesWithoutAttributes); +// EXTERNAL MODULE: ./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js +var style_loader_insertStyleElement = __webpack_require__("./node_modules/webpack-monkey/lib/node/deps/style-loader-insertStyleElement.js"); +var style_loader_insertStyleElement_default = /*#__PURE__*/__webpack_require__.n(style_loader_insertStyleElement); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleTagTransform.js +var styleTagTransform = __webpack_require__("./node_modules/style-loader/dist/runtime/styleTagTransform.js"); +var styleTagTransform_default = /*#__PURE__*/__webpack_require__.n(styleTagTransform); +// EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss +var main = __webpack_require__("./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/styles/main.scss"); +;// CONCATENATED MODULE: ./src/styles/main.scss - if (response instanceof Error) { - throw response; - } + + + + + + + + + - const content = await response.json(); +var options = {}; - if (content.code !== 200) { - throw content.message; - } +options.styleTagTransform = (styleTagTransform_default()); +options.setAttributes = (setAttributesWithoutAttributes_default()); - return content.text[0]; - } catch (error) { - console.error("Error translating text:", error); - return text; - } - }, + options.insert = insertBySelector_default().bind(null, "head"); + +options.domAPI = (styleDomAPI_default()); +options.insertStyleElement = (style_loader_insertStyleElement_default()); - async detect(text, lang) { - // Limit: 10k symbols - try { - const response = await fetchWithTimeout(config/* detectUrls */.jm.yandex, { - method: "POST", - headers: { - "content-type": "application/json", - }, - body: JSON.stringify({ - text, - lang, - }), - }); +var update = injectStylesIntoStyleTag_default()(main/* default */.A, options); - if (response instanceof Error) { - throw response; - } - const content = await response.json(); - if (content.code !== 200) { - throw content.message; - } - return content.lang ?? "en"; - } catch (error) { - console.error("Error translating text:", error); - return "en"; - } - }, -}; -const RustServerAPI = { - async detect(text) { - try { - const response = await fetch(config/* detectUrls */.jm.rustServer, { - method: "POST", - body: text, - }); + /* harmony default export */ const styles_main = (main/* default */.A && main/* default */.A.locals ? main/* default */.A.locals : undefined); - if (response instanceof Error) { - throw response; - } +;// CONCATENATED MODULE: ./src/ui.js - return await response.text(); - } catch (error) { - console.error("Error getting lang from text:", error); - return "en"; - } - }, -}; -async function translate(text, fromLang = "", toLang = "ru") { - const service = await storage/* votStorage */.i.get( - "translationService", - config/* defaultTranslationService */.kF, - ); - switch (service) { - case "yandex": { - const langPair = fromLang && toLang ? `${fromLang}-${toLang}` : toLang; - return await YandexTranslateAPI.translate(text, langPair); - } - default: - return text; - } -} +function createHeader(html, level = 4) { + const header = document.createElement("vot-block"); + header.classList.add("vot-header"); + header.classList.add(`vot-header-level-${level}`); + header.innerHTML = html; -async function detect(text) { - const service = await storage/* votStorage */.i.get("detectService", config/* defaultDetectService */.EY); - switch (service) { - case "yandex": - return await YandexTranslateAPI.detect(text); - case "rust-server": - return await RustServerAPI.detect(text); - default: - return "en"; - } + return header; } -const translateServices = ["yandex"]; -const detectServices = ["yandex", "rust-server"]; +function createInformation(html, valueHtml) { + const container = document.createElement("vot-block"); + container.classList.add("vot-info"); + + const header = document.createElement("vot-block"); + header.innerHTML = html; + const value = document.createElement("vot-block"); + value.innerHTML = valueHtml; + container.appendChild(header); + container.appendChild(value); -;// CONCATENATED MODULE: ./src/utils/youtubeUtils.js + return { + container, + header, + value, + }; +} + +function createButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-button"); + button.innerHTML = html; + return button; +} +function createTextButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-text-button"); + button.innerHTML = html; + return button; +} +function createOutlinedButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-outlined-button"); + button.innerHTML = html; -// Get the language code from the response or the text -async function getLanguage(player, response, title, description) { - if ( - !window.location.hostname.includes("m.youtube.com") && - player?.getAudioTrack - ) { - // ! Experimental ! get lang from selected audio track if availabled - const audioTracks = player.getAudioTrack(); - const trackInfo = audioTracks?.getLanguageInfo(); // get selected track info (id === "und" if tracks are not available) - if (trackInfo?.id !== "und") { - return (0,utils/* langTo6391 */.eL)(trackInfo.id.split(".")[0]); - } - } + return button; +} - // TODO: If the audio tracks will work fine, transfer the receipt of captions to the audioTracks variable - // Check if there is an automatic caption track in the response - const captionTracks = - response?.captions?.playerCaptionsTracklistRenderer?.captionTracks; - if (captionTracks?.length) { - const autoCaption = captionTracks.find((caption) => caption.kind === "asr"); - if (autoCaption && autoCaption.languageCode) { - return (0,utils/* langTo6391 */.eL)(autoCaption.languageCode); - } - } +function createIconButton(html) { + const button = document.createElement("vot-block"); + button.classList.add("vot-icon-button"); + button.innerHTML = html; - // the "delayed video upload" fix for YouTube (#387) - if (!(description && title)) { - return "en"; - } + return button; +} - // If there is no caption track, use detect to get the language code from the description +function createCheckbox(html, value = false) { + const container = document.createElement("label"); + container.classList.add("vot-checkbox"); - const deletefilter = [ - /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g, // remove links - /Auto-generated by YouTube/g, - /Provided to YouTube by/g, - /Released on/g, - /Bitcoin/g, - /USDT/g, - /Paypal/g, - ]; + const input = document.createElement("input"); + input.type = "checkbox"; + input.checked = Boolean(value); - const cleanedDescription = description - .split("\n\n") - .filter((line) => !deletefilter.some((regex) => regex.test(line))) - .join("\n\n") - .replace(/[^\p{L}\s]/gu, " ") - .trim() - .replace(/\s+/g, " ") - .slice(0, 250); + const label = document.createElement("span"); + label.innerHTML = html; - const cleanText = [cleanedDescription, title].join(" "); + container.appendChild(input); + container.appendChild(label); - return await detect(cleanText); + return { container, input, label }; } -function isMobile() { - return /^m\.youtube\.com$/.test(window.location.hostname); +function updateSlider(input) { + const value = parseFloat(input.value); + const min = input.min === "" ? 0 : parseFloat(input.min); + const max = input.max === "" ? 100 : parseFloat(input.max); + const progress = (value - min) / (max - min); + input.parentElement.setAttribute("style", `--vot-progress: ${progress}`); } -function getPlayer() { - if (window.location.pathname.startsWith("/shorts/")) { - return isMobile() - ? document.querySelector("#movie_player") - : document.querySelector("#shorts-player"); - } +function createSlider(html, value = 50, min = 0, max = 100) { + const container = document.createElement("vot-block"); + container.classList.add("vot-slider"); - return document.querySelector("#movie_player"); -} + const input = document.createElement("input"); + input.type = "range"; + input.min = min; + input.max = max; + input.value = value; -function getPlayerResponse() { - const player = getPlayer(); - if (player?.getPlayerResponse) - return player?.getPlayerResponse?.call() ?? null; - return player?.data?.playerResponse ?? null; -} + const label = document.createElement("span"); + label.innerHTML = html; -function getPlayerData() { - const player = getPlayer(); - if (player?.getVideoData) return player?.getVideoData?.call() ?? null; - return player?.data?.playerResponse?.videoDetails ?? null; -} + container.appendChild(input); + container.appendChild(label); -function getVideoVolume() { - const player = getPlayer(); - if (player?.getVolume) { - return player.getVolume.call() / 100; - } + input.addEventListener("input", (e) => updateSlider(e.target)); + updateSlider(input); - return 1; + return { + container, + input, + label, + }; } -function setVideoVolume(volume) { - const player = getPlayer(); - if (player?.setVolume) { - player.setVolume(Math.round(volume * 100)); - return true; - } -} +function createTextfield( + html, + value = "", + placeholder = " ", + multiline = false, +) { + const container = document.createElement("vot-block"); + container.classList.add("vot-textfield"); -function videoSeek(video, time) { - // * TIME IN MS - debug/* default */.Z.log("videoSeek", time); - const preTime = - getPlayer()?.getProgressState()?.seekableEnd || video.currentTime; - const finalTime = preTime - time; // we always throw it to the end of the stream - time - video.currentTime = finalTime; -} + const input = document.createElement(multiline ? "textarea" : "input"); + input.placeholder = placeholder; + input.value = value; -function getSubtitles() { - const response = getPlayerResponse(); - let captionTracks = - response?.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? []; - captionTracks = captionTracks.reduce((result, captionTrack) => { - if ("languageCode" in captionTrack) { - const language = captionTrack?.languageCode - ? (0,utils/* langTo6391 */.eL)(captionTrack?.languageCode) - : undefined; - const url = captionTrack?.url || captionTrack?.baseUrl; - language && - url && - result.push({ - source: "youtube", - language, - isAutoGenerated: captionTrack?.kind === "asr", - url: `${ - url.startsWith("http") ? url : `${window.location.origin}/${url}` - }&fmt=json3`, - }); - } - return result; - }, []); - debug/* default */.Z.log("youtube subtitles:", captionTracks); - return captionTracks; -} + const label = document.createElement("span"); + label.innerHTML = html; -// Get the video data from the player -async function getVideoData() { - const player = getPlayer(); - const response = getPlayerResponse(); // null in /embed - const data = getPlayerData(); - const { author, title } = data ?? {}; - const { - shortDescription: description, - isLive, - isLiveContent, - isUpcoming, - } = response?.videoDetails ?? {}; - const isPremiere = (!!isLive || !!isUpcoming) && !isLiveContent; - let detectedLanguage = await getLanguage( - player, - response, - title, - description, - author, - ); - if (!availableLangs.includes(detectedLanguage)) { - detectedLanguage = "en"; - } - const videoData = { - isLive: !!isLive, - isPremiere, - title, - description, - author, - detectedLanguage, + container.appendChild(input); + container.appendChild(label); + + return { + container, + input, + label, }; - debug/* default */.Z.log("youtube video data:", videoData); - console.log("[VOT] Detected language: ", videoData.detectedLanguage); - return videoData; } -const youtubeUtils = { - isMobile, - getPlayer, - getPlayerResponse, - getPlayerData, - getVideoVolume, - getSubtitles, - getVideoData, - setVideoVolume, - videoSeek, -}; +function createDialog(html) { + const container = document.createElement("vot-block"); + container.classList.add("vot-dialog-container"); + container.hidden = true; -;// CONCATENATED MODULE: ./src/yandexProtobuf.js -// coursera & udemy translation help object -const VideoTranslationHelpObject = new protobuf.Type( - "VideoTranslationHelpObject", -) - .add(new protobuf.Field("target", 1, "string")) // video_file_url or subtitles_file_url - .add(new protobuf.Field("targetUrl", 2, "string")); // url to video_file or url to subtitles + const backdrop = document.createElement("vot-block"); + backdrop.classList.add("vot-dialog-backdrop"); -const VideoTranslationRequest = new protobuf.Type("VideoTranslationRequest") - .add(new protobuf.Field("url", 3, "string")) - .add(new protobuf.Field("deviceId", 4, "string")) // removed? - .add(new protobuf.Field("firstRequest", 5, "bool")) // true for the first request, false for subsequent ones - .add(new protobuf.Field("duration", 6, "double")) - .add(new protobuf.Field("unknown2", 7, "int32")) // 1 1 - .add(new protobuf.Field("language", 8, "string")) // source language code - .add(new protobuf.Field("unknown3", 9, "int32")) // 0 - without translationHelp | 1 - with translationHelp (??? But it works without it) - .add(new protobuf.Field("unknown4", 10, "int32")) // 0 0 - .add( - new protobuf.Field( - "translationHelp", - 11, - "VideoTranslationHelpObject", - "repeated", - ), - ) // array for translation assistance ([0] -> {2: link to video, 1: "video_file_url"}, [1] -> {2: link to subtitles, 1: "subtitles_file_url"}) - .add(new protobuf.Field("responseLanguage", 14, "string")) - .add(new protobuf.Field("unknown5", 15, "int32")) // 0 - .add(new protobuf.Field("unknown6", 16, "int32")) // 1 - .add(new protobuf.Field("unknown7", 17, "int32")); // 0 + const dialog = document.createElement("vot-block"); + dialog.classList.add("vot-dialog"); + + const contentWrapper = document.createElement("vot-block"); + contentWrapper.classList.add("vot-dialog-content-wrapper"); + + const headerContainer = document.createElement("vot-block"); + headerContainer.classList.add("vot-dialog-header-container"); + + const bodyContainer = document.createElement("vot-block"); + bodyContainer.classList.add("vot-dialog-body-container"); -const VideoSubtitlesRequest = new protobuf.Type("VideoSubtitlesRequest") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("language", 2, "string")); // source language code + const footerContainer = document.createElement("vot-block"); + footerContainer.classList.add("vot-dialog-footer-container"); -const VideoStreamRequest = new protobuf.Type("VideoStreamRequest") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("language", 2, "string")) - .add(new protobuf.Field("responseLanguage", 3, "string")); + const titleContainer = document.createElement("vot-block"); + titleContainer.classList.add("vot-dialog-title-container"); -const VideoStreamPingRequest = new protobuf.Type("VideoStreamPingRequest").add( - new protobuf.Field("pingId", 1, "int32"), -); + const closeButton = createIconButton( + ``, + ); + closeButton.classList.add("vot-dialog-close-button"); -const VideoTranslationResponse = new protobuf.Type("VideoTranslationResponse") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("duration", 2, "double")) - .add(new protobuf.Field("status", 4, "int32")) - .add(new protobuf.Field("remainingTime", 5, "int32")) // secs before translation (used as interval before next request in yaBrowser) - .add(new protobuf.Field("unknown0", 6, "int32")) // unknown 0 (1st request) -> 10 (2nd, 3th and etc requests) - .add(new protobuf.Field("unknown1", 7, "string")) - .add(new protobuf.Field("language", 8, "string")) // detected language (if the wrong one is set) - .add(new protobuf.Field("message", 9, "string")); + backdrop.onclick = closeButton.onclick = () => { + container.hidden = true; + }; -const VideoSubtitlesObject = new protobuf.Type("VideoSubtitlesObject") - .add(new protobuf.Field("language", 1, "string")) - .add(new protobuf.Field("url", 2, "string")) - .add(new protobuf.Field("unknown2", 3, "int32")) - .add(new protobuf.Field("translatedLanguage", 4, "string")) - .add(new protobuf.Field("translatedUrl", 5, "string")) - .add(new protobuf.Field("unknown5", 6, "int32")) - .add(new protobuf.Field("unknown6", 7, "int32")); + const title = document.createElement("vot-block"); + title.classList.add("vot-dialog-title"); + title.innerHTML = html; -const VideoSubtitlesResponse = new protobuf.Type("VideoSubtitlesResponse") - .add(new protobuf.Field("unknown0", 1, "int32")) - .add(new protobuf.Field("subtitles", 2, "VideoSubtitlesObject", "repeated")); + container.appendChild(backdrop); + container.appendChild(dialog); + dialog.appendChild(contentWrapper); + contentWrapper.appendChild(headerContainer); + contentWrapper.appendChild(bodyContainer); + contentWrapper.appendChild(footerContainer); + headerContainer.appendChild(titleContainer); + headerContainer.appendChild(closeButton); + titleContainer.appendChild(title); -const VideoStreamObject = new protobuf.Type("VideoStreamObject") - .add(new protobuf.Field("url", 1, "string")) - .add(new protobuf.Field("timestamp", 2, "int64")); // timestamp in ms (probably means the time of 1 request to translate the stream) + return { + container, + backdrop, + dialog, + contentWrapper, + headerContainer, + bodyContainer, + footerContainer, + titleContainer, + closeButton, + title, + }; +} -const VideoStreamResponse = new protobuf.Type("VideoStreamResponse") - .add(new protobuf.Field("interval", 1, "int32")) // 20s - streaming, 10s - translating, 0s - there is no connection with the server (the broadcast is finished or deleted) - .add(new protobuf.Field("translatedInfo", 2, "VideoStreamObject")) - .add(new protobuf.Field("pingId", 3, "int32")); +function createVOTButton(html) { + const container = document.createElement("vot-block"); + container.classList.add("vot-segmented-button"); -// * Yandex has been skipping any translation streams for a long time (whitelist always return true) -// * Most likely, it is already outdated and will not be used -// const VideoWhitelistStreamRequest = new protobuf.Type("VideoWhitelistStreamRequest") -// .add(new protobuf.Field("url", 1, "string")) -// .add(new protobuf.Field("deviceId", 4, "string")) + const translateButton = document.createElement("vot-block"); + translateButton.classList.add("vot-segment"); + translateButton.classList.add("vot-translate-button"); + translateButton.innerHTML = ``; -// const VideoWhitelistStreamResponse = new protobuf.Type("VideoWhitelistStreamResponse") -// .add(new protobuf.Field("inWhitelist", 1, "bool")) + const separator = document.createElement("vot-block"); + separator.classList.add("vot-separator"); -// Create a root namespace and add the types -const root = new protobuf.Root() - .define("yandex") - .add(VideoTranslationHelpObject) - .add(VideoTranslationRequest) - .add(VideoTranslationResponse) - .add(VideoSubtitlesRequest) - .add(VideoSubtitlesObject) - .add(VideoSubtitlesResponse) - .add(VideoStreamPingRequest) - .add(VideoStreamRequest) - .add(VideoStreamObject) - .add(VideoStreamResponse); + const pipButton = document.createElement("vot-block"); + pipButton.classList.add("vot-segment-only-icon"); + pipButton.innerHTML = ``; -// Export the encoding and decoding functions -const yandexProtobuf = { - encodeTranslationRequest( - url, - duration, - requestLang, - responseLang, - translationHelp, - ) { - return root.VideoTranslationRequest.encode({ - url, - firstRequest: true, - duration, - unknown2: 1, - language: requestLang, - unknown3: 0, - unknown4: 0, - translationHelp, - responseLanguage: responseLang, - unknown5: 0, - unknown6: 1, - unknown7: 0, - }).finish(); - }, - decodeTranslationResponse(response) { - return root.VideoTranslationResponse.decode(new Uint8Array(response)); - }, - encodeSubtitlesRequest(url, requestLang) { - return root.VideoSubtitlesRequest.encode({ - url, - language: requestLang, - }).finish(); - }, - decodeSubtitlesResponse(response) { - return root.VideoSubtitlesResponse.decode(new Uint8Array(response)); - }, - encodeStreamPingRequest(pingId) { - return root.VideoStreamPingRequest.encode({ - pingId, - }).finish(); - }, - encodeStreamRequest(url, requestLang, responseLang) { - return root.VideoStreamRequest.encode({ - url, - language: requestLang, - responseLanguage: responseLang, - }).finish(); - }, - decodeStreamResponse(response) { - return root.VideoStreamResponse.decode(new Uint8Array(response)); - }, -}; + const separator2 = document.createElement("vot-block"); + separator2.classList.add("vot-separator"); -;// CONCATENATED MODULE: ./src/config/alternativeUrls.js -// Sites host Invidious. I tested the performance only on invidious.kevin.rocks, youtu.be and inv.vern.cc -const sitesInvidious = [ - "invidious.snopyta.org", - "yewtu.be", - "invidious.kavin.rocks", - "vid.puffyan.us", - "invidious.namazso.eu", - "inv.riverside.rocks", - "yt.artemislena.eu", - "invidious.flokinet.to", - "invidious.esmailelbob.xyz", - "y.com.sb", - "invidious.nerdvpn.de", - "inv.vern.cc", - "invidious.slipfox.xyz", - "invidio.xamh.de", - "invidious.dhusch.de", -]; + const menuButton = document.createElement("vot-block"); + menuButton.classList.add("vot-segment-only-icon"); + menuButton.innerHTML = ``; -// Sites host Piped. I tested the performance only on piped.video -const sitesPiped = [ - "piped.video", - "piped.tokhmi.xyz", - "piped.moomoo.me", - "piped.syncpundit.io", - "piped.mha.fi", - "watch.whatever.social", - "piped.garudalinux.org", - "efy.piped.pages.dev", - "watch.leptons.xyz", - "piped.lunar.icu", - "yt.dc09.ru", - "piped.mint.lgbt", - "il.ax", - "piped.privacy.com.de", - "piped.esmailelbob.xyz", - "piped.projectsegfau.lt", - "piped.in.projectsegfau.lt", - "piped.us.projectsegfau.lt", - "piped.privacydev.net", - "piped.palveluntarjoaja.eu", - "piped.smnz.de", - "piped.adminforge.de", - "piped.qdi.fi", - "piped.hostux.net", - "piped.chauvet.pro", - "piped.jotoma.de", - "piped.pfcd.me", - "piped.frontendfriendly.xyz", -]; + const label = document.createElement("span"); + label.classList.add("vot-segment-label"); + label.innerHTML = html; -const sitesProxyTok = [ - "proxitok.pabloferreiro.es", - "proxitok.pussthecat.org", - "tok.habedieeh.re", - "proxitok.esmailelbob.xyz", - "proxitok.privacydev.net", - "tok.artemislena.eu", - "tok.adminforge.de", - "tik.hostux.net", // maybe instance doesn't working - "tt.vern.cc", - "cringe.whatever.social", - "proxitok.lunar.icu", - "proxitok.privacy.com.de", // maybe instance doesn't working -]; + container.appendChild(translateButton); + container.appendChild(separator); + container.appendChild(pipButton); + container.appendChild(separator2); + container.appendChild(menuButton); + translateButton.appendChild(label); + + return { + container, + translateButton, + separator, + pipButton, + separator2, + menuButton, + label, + }; +} + +function createVOTMenu(html) { + const container = document.createElement("vot-block"); + container.classList.add("vot-menu"); + container.hidden = true; + + const contentWrapper = document.createElement("vot-block"); + contentWrapper.classList.add("vot-menu-content-wrapper"); + + const headerContainer = document.createElement("vot-block"); + headerContainer.classList.add("vot-menu-header-container"); -// Sites host Peertube. I tested the performance only on dalek.zone and tube.shanti.cafe -const sitesPeertube = [ - "peertube.1312.media", - "tube.shanti.cafe", - "bee-tube.fr", - "video.sadmin.io", - "dalek.zone", - "review.peertube.biz", - "peervideo.club", - "tube.la-dina.net", - "peertube.tmp.rcp.tf", -]; + const bodyContainer = document.createElement("vot-block"); + bodyContainer.classList.add("vot-menu-body-container"); + const footerContainer = document.createElement("vot-block"); + footerContainer.classList.add("vot-menu-footer-container"); + const titleContainer = document.createElement("vot-block"); + titleContainer.classList.add("vot-menu-title-container"); -;// CONCATENATED MODULE: ./src/ui.js + const title = document.createElement("vot-block"); + title.classList.add("vot-menu-title"); + title.innerHTML = html; + container.appendChild(contentWrapper); + contentWrapper.appendChild(headerContainer); + contentWrapper.appendChild(bodyContainer); + contentWrapper.appendChild(footerContainer); + headerContainer.appendChild(titleContainer); + titleContainer.appendChild(title); -function createHeader(html, level = 4) { - const header = document.createElement("vot-block"); - header.classList.add("vot-header"); - header.classList.add(`vot-header-level-${level}`); - header.innerHTML = html; + return { + container, + contentWrapper, + headerContainer, + bodyContainer, + footerContainer, + titleContainer, + title, + }; +} - return header; +function createVOTSelectLabel(text) { + const label = document.createElement("span"); + label.classList.add("vot-select-label"); + label.innerText = text; + return label; } -function createInformation(html, valueHtml) { +function createVOTSelect(selectTitle, dialogTitle, items, options = {}) { + const onSelectCb = options.onSelectCb || function () {}; + const labelElement = options.labelElement || ""; + let selectedItems = []; + const container = document.createElement("vot-block"); - container.classList.add("vot-info"); + container.classList.add("vot-select"); - const header = document.createElement("vot-block"); - header.innerHTML = html; + if (labelElement) { + container.appendChild(labelElement); + } - const value = document.createElement("vot-block"); - value.innerHTML = valueHtml; + const outer = document.createElement("vot-block"); + outer.classList.add("vot-select-outer"); - container.appendChild(header); - container.appendChild(value); + const title = document.createElement("span"); + title.classList.add("vot-select-title"); + title.innerText = selectTitle; - return { - container, - header, - value, - }; -} + if (selectTitle === undefined) { + title.innerText = items.find((i) => i.selected === true)?.label; + } -function createButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-button"); - button.innerHTML = html; + const arrowIcon = document.createElement("vot-block"); + arrowIcon.classList.add("vot-select-arrow-icon"); + arrowIcon.innerHTML = ``; - return button; -} + outer.append(title, arrowIcon); + outer.onclick = () => { + const votSelectDialog = createDialog(dialogTitle); + votSelectDialog.container.classList.add("vot-dialog-temp"); + votSelectDialog.container.hidden = false; + document.documentElement.appendChild(votSelectDialog.container); -function createTextButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-text-button"); - button.innerHTML = html; + const contentList = document.createElement("vot-block"); + contentList.classList.add("vot-select-content-list"); - return button; -} + for (const item of items) { + const contentItem = document.createElement("vot-block"); + contentItem.classList.add("vot-select-content-item"); + contentItem.innerText = item.label; + contentItem.dataset.votSelected = item.selected; + contentItem.dataset.votValue = item.value; + if (item.disabled) { + contentItem.inert = true; + } -function createOutlinedButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-outlined-button"); - button.innerHTML = html; + contentItem.onclick = async (e) => { + if (e.target.inert) return; - return button; -} + // removing the selected value for updating + const contentItems = contentList.childNodes; + contentItems.forEach((ci) => (ci.dataset.votSelected = false)); + // fixed selection after closing the modal and opening again + items.forEach((i) => (i.selected = i.value === item.value)); -function createIconButton(html) { - const button = document.createElement("vot-block"); - button.classList.add("vot-icon-button"); - button.innerHTML = html; + contentItem.dataset.votSelected = true; + title.innerText = item.label; - return button; -} + // !!! use e.target.dataset.votValue instead of e.target.value !!! + await onSelectCb(e); + }; + contentList.appendChild(contentItem); + } -function createCheckbox(html, value = false) { - const container = document.createElement("label"); - container.classList.add("vot-checkbox"); + // search logic + const votSearchLangTextfield = createTextfield( + localizationProvider.get("searchField"), + ); - const input = document.createElement("input"); - input.type = "checkbox"; - input.checked = Boolean(value); + votSearchLangTextfield.input.oninput = (e) => { + const searchText = e.target.value.toLowerCase(); + // check if there are lovercase characters in the string. used for smarter search + Array.from(selectedItems).forEach( + (ci) => (ci.hidden = !ci.innerText.toLowerCase().includes(searchText)), + ); + }; - const label = document.createElement("span"); - label.innerHTML = html; + votSelectDialog.bodyContainer.append( + votSearchLangTextfield.container, + contentList, + ); + selectedItems = contentList.childNodes; - container.appendChild(input); - container.appendChild(label); + // remove the modal so that they do not accumulate + votSelectDialog.backdrop.onclick = votSelectDialog.closeButton.onclick = + () => { + votSelectDialog.container.remove(); + selectedItems = []; + }; + }; - return { container, input, label }; + container.append(outer); + + const setTitle = (newTitle) => { + title.innerText = newTitle; + }; + + const setSelected = (val) => { + Array.from(selectedItems) + .filter((ci) => !ci.inert) + .forEach((ci) => (ci.dataset.votSelected = ci.dataset.votValue === val)); + items.forEach((i) => (i.selected = String(i.value) === val)); + }; + + const updateItems = (newItems) => { + items = newItems; + }; + + return { + container, + title, + arrowIcon, + labelElement, + setTitle, + setSelected, + updateItems, + }; } -function updateSlider(input) { - const value = parseFloat(input.value); - const min = input.min === "" ? 0 : parseFloat(input.min); - const max = input.max === "" ? 100 : parseFloat(input.max); - const progress = (value - min) / (max - min); - input.parentElement.setAttribute("style", `--vot-progress: ${progress}`); +function createVOTLanguageSelect(options) { + const fromTitle = options.fromTitle || "#UNDEFINED"; + const fromDialogTitle = options.fromDialogTitle || "#UNDEFINED"; + const fromItems = options.fromItems || []; + const fromOnSelectCB = options.fromOnSelectCB || function () {}; + const toTitle = options.toTitle || "#UNDEFINED"; + const toDialogTitle = options.toDialogTitle || "#UNDEFINED"; + const toItems = options.toItems || []; + const toOnSelectCB = options.toOnSelectCB || function () {}; + + const container = document.createElement("vot-block"); + container.classList.add("vot-lang-select"); + + const fromSelect = createVOTSelect(fromTitle, fromDialogTitle, fromItems, { + onSelectCb: fromOnSelectCB, + }); + + const icon = document.createElement("vot-block"); + icon.classList.add("vot-lang-select-icon"); + icon.innerHTML = ``; + + const toSelect = createVOTSelect(toTitle, toDialogTitle, toItems, { + onSelectCb: toOnSelectCB, + }); + + container.append(fromSelect.container, icon, toSelect.container); + + return { + container, + fromSelect, + icon, + toSelect, + }; } -function createSlider(html, value = 50, min = 0, max = 100) { - const container = document.createElement("vot-block"); - container.classList.add("vot-slider"); +/* harmony default export */ const ui = ({ + createHeader, + createInformation, + createButton, + createTextButton, + createOutlinedButton, + createIconButton, + createCheckbox, + createSlider, + createTextfield, + createDialog, + createVOTButton, + createVOTMenu, + createVOTSelectLabel, + createVOTSelect, + createVOTLanguageSelect, + updateSlider, +}); + +;// CONCATENATED MODULE: ./src/utils/VOTLocalizedError.js - const input = document.createElement("input"); - input.type = "range"; - input.min = min; - input.max = max; - input.value = value; - const label = document.createElement("span"); - label.innerHTML = html; +class VOTLocalizedError extends Error { + constructor(message) { + super(localizationProvider.getDefault(message)); + this.name = "VOTLocalizedError"; + this.unlocalizedMessage = message; + this.localizedMessage = localizationProvider.get(message); + } +} - container.appendChild(input); - container.appendChild(label); +;// CONCATENATED MODULE: ./src/utils/translateApis.js - input.addEventListener("input", (e) => updateSlider(e.target)); - updateSlider(input); - return { - container, - input, - label, - }; -} -function createTextfield( - html, - value = "", - placeholder = " ", - multiline = false, -) { - const container = document.createElement("vot-block"); - container.classList.add("vot-textfield"); +const HTTP_TIMEOUT = 3000; - const input = document.createElement(multiline ? "textarea" : "input"); - input.placeholder = placeholder; - input.value = value; +async function fetchWithTimeout(url, options) { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT); - const label = document.createElement("span"); - label.innerHTML = html; + try { + return await fetch(url, { + ...options, + signal: controller.signal, + }); + } catch (error) { + console.error("Fetch timed-out. Error:", error); + return error; + } finally { + clearTimeout(timeoutId); + } +} - container.appendChild(input); - container.appendChild(label); +const YandexTranslateAPI = { + async translate(text, lang) { + // Limit: 10k symbols + // + // Lang examples: + // en-ru, uk-ru, ru-en... + // ru, en (instead of auto-ru, auto-en) - return { - container, - input, - label, - }; -} + try { + const response = await fetchWithTimeout(config/* translateUrls */.rw.yandex, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + text, + lang, + }), + }); -function createDialog(html) { - const container = document.createElement("vot-block"); - container.classList.add("vot-dialog-container"); - container.hidden = true; + if (response instanceof Error) { + throw response; + } - const backdrop = document.createElement("vot-block"); - backdrop.classList.add("vot-dialog-backdrop"); + const content = await response.json(); - const dialog = document.createElement("vot-block"); - dialog.classList.add("vot-dialog"); + if (content.code !== 200) { + throw content.message; + } - const contentWrapper = document.createElement("vot-block"); - contentWrapper.classList.add("vot-dialog-content-wrapper"); + return content.text[0]; + } catch (error) { + console.error("Error translating text:", error); + return text; + } + }, - const headerContainer = document.createElement("vot-block"); - headerContainer.classList.add("vot-dialog-header-container"); + async detect(text, lang) { + // Limit: 10k symbols + try { + const response = await fetchWithTimeout(config/* detectUrls */.QL.yandex, { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify({ + text, + lang, + }), + }); - const bodyContainer = document.createElement("vot-block"); - bodyContainer.classList.add("vot-dialog-body-container"); + if (response instanceof Error) { + throw response; + } - const footerContainer = document.createElement("vot-block"); - footerContainer.classList.add("vot-dialog-footer-container"); + const content = await response.json(); + if (content.code !== 200) { + throw content.message; + } - const titleContainer = document.createElement("vot-block"); - titleContainer.classList.add("vot-dialog-title-container"); + return content.lang ?? "en"; + } catch (error) { + console.error("Error translating text:", error); + return "en"; + } + }, +}; - const closeButton = createIconButton( - ``, - ); - closeButton.classList.add("vot-dialog-close-button"); +const RustServerAPI = { + async detect(text) { + try { + const response = await fetch(config/* detectUrls */.QL.rustServer, { + method: "POST", + body: text, + }); - backdrop.onclick = closeButton.onclick = () => { - container.hidden = true; - }; + if (response instanceof Error) { + throw response; + } - const title = document.createElement("vot-block"); - title.classList.add("vot-dialog-title"); - title.innerHTML = html; + return await response.text(); + } catch (error) { + console.error("Error getting lang from text:", error); + return "en"; + } + }, +}; - container.appendChild(backdrop); - container.appendChild(dialog); - dialog.appendChild(contentWrapper); - contentWrapper.appendChild(headerContainer); - contentWrapper.appendChild(bodyContainer); - contentWrapper.appendChild(footerContainer); - headerContainer.appendChild(titleContainer); - headerContainer.appendChild(closeButton); - titleContainer.appendChild(title); +async function translate(text, fromLang = "", toLang = "ru") { + const service = await votStorage.get( + "translationService", + config/* defaultTranslationService */.mE, + ); + switch (service) { + case "yandex": { + const langPair = fromLang && toLang ? `${fromLang}-${toLang}` : toLang; + return await YandexTranslateAPI.translate(text, langPair); + } + default: + return text; + } +} - return { - container, - backdrop, - dialog, - contentWrapper, - headerContainer, - bodyContainer, - footerContainer, - titleContainer, - closeButton, - title, - }; +async function detect(text) { + const service = await votStorage.get("detectService", config/* defaultDetectService */.K2); + switch (service) { + case "yandex": + return await YandexTranslateAPI.detect(text); + case "rust-server": + return await RustServerAPI.detect(text); + default: + return "en"; + } } -function createVOTButton(html) { - const container = document.createElement("vot-block"); - container.classList.add("vot-segmented-button"); +const translateServices = ["yandex"]; +const detectServices = ["yandex", "rust-server"]; - const translateButton = document.createElement("vot-block"); - translateButton.classList.add("vot-segment"); - translateButton.classList.add("vot-translate-button"); - translateButton.innerHTML = ``; - const separator = document.createElement("vot-block"); - separator.classList.add("vot-separator"); - const pipButton = document.createElement("vot-block"); - pipButton.classList.add("vot-segment-only-icon"); - pipButton.innerHTML = ``; +;// CONCATENATED MODULE: ./src/utils/youtubeUtils.js - const separator2 = document.createElement("vot-block"); - separator2.classList.add("vot-separator"); - const menuButton = document.createElement("vot-block"); - menuButton.classList.add("vot-segment-only-icon"); - menuButton.innerHTML = ``; - const label = document.createElement("span"); - label.classList.add("vot-segment-label"); - label.innerHTML = html; - container.appendChild(translateButton); - container.appendChild(separator); - container.appendChild(pipButton); - container.appendChild(separator2); - container.appendChild(menuButton); - translateButton.appendChild(label); - return { - container, - translateButton, - separator, - pipButton, - separator2, - menuButton, - label, - }; -} +// Get the language code from the response or the text +async function getLanguage(player, response, title, description) { + if ( + !window.location.hostname.includes("m.youtube.com") && + player?.getAudioTrack + ) { + // ! Experimental ! get lang from selected audio track if availabled + const audioTracks = player.getAudioTrack(); + const trackInfo = audioTracks?.getLanguageInfo(); // get selected track info (id === "und" if tracks are not available) + if (trackInfo?.id !== "und") { + return langTo6391(trackInfo.id.split(".")[0]); + } + } -function createVOTMenu(html) { - const container = document.createElement("vot-block"); - container.classList.add("vot-menu"); - container.hidden = true; + // TODO: If the audio tracks will work fine, transfer the receipt of captions to the audioTracks variable + // Check if there is an automatic caption track in the response + const captionTracks = + response?.captions?.playerCaptionsTracklistRenderer?.captionTracks; + if (captionTracks?.length) { + const autoCaption = captionTracks.find((caption) => caption.kind === "asr"); + if (autoCaption && autoCaption.languageCode) { + return langTo6391(autoCaption.languageCode); + } + } - const contentWrapper = document.createElement("vot-block"); - contentWrapper.classList.add("vot-menu-content-wrapper"); + // If there is no caption track, use detect to get the language code from the description - const headerContainer = document.createElement("vot-block"); - headerContainer.classList.add("vot-menu-header-container"); + const deletefilter = [ + /(?:https?|ftp):\/\/[\S]+/g, //temp fix + /https?:\/\/\S+|www\.\S+/gm, + /\b\S+\.\S+/gm, + /#[^\s#]+/g, // hash tags + /Auto-generated by YouTube/g, + /Provided to YouTube by/g, + /Released on/g, + /Bitcoin/g, + /USDT/g, + /Paypal/g, + ]; - const bodyContainer = document.createElement("vot-block"); - bodyContainer.classList.add("vot-menu-body-container"); + const cleanedDescription = description + .split("\n\n") + .filter((line) => !deletefilter.some((regex) => regex.test(line))) + .join("\n\n"); - const footerContainer = document.createElement("vot-block"); - footerContainer.classList.add("vot-menu-footer-container"); + const cleanText = [title, cleanedDescription] + .join(" ") + .replace(/[^\p{L}\s]/gu, " ") + .trim() + .replace(/\s+/g, " ") + .slice(0, 1000); - const titleContainer = document.createElement("vot-block"); - titleContainer.classList.add("vot-menu-title-container"); + return await detect(cleanText); +} - const title = document.createElement("vot-block"); - title.classList.add("vot-menu-title"); - title.innerHTML = html; +function isMobile() { + return /^m\.youtube\.com$/.test(window.location.hostname); +} - container.appendChild(contentWrapper); - contentWrapper.appendChild(headerContainer); - contentWrapper.appendChild(bodyContainer); - contentWrapper.appendChild(footerContainer); - headerContainer.appendChild(titleContainer); - titleContainer.appendChild(title); +function getPlayer() { + if (window.location.pathname.startsWith("/shorts/")) { + return isMobile() + ? document.querySelector("#movie_player") + : document.querySelector("#shorts-player"); + } - return { - container, - contentWrapper, - headerContainer, - bodyContainer, - footerContainer, - titleContainer, - title, - }; + return document.querySelector("#movie_player"); } -function createVOTSelectLabel(text) { - const label = document.createElement("span"); - label.classList.add("vot-select-label"); - label.innerText = text; - return label; +function getPlayerResponse() { + const player = getPlayer(); + if (player?.getPlayerResponse) + return player?.getPlayerResponse?.call() ?? null; + return player?.data?.playerResponse ?? null; } -function createVOTSelect(selectTitle, dialogTitle, items, options = {}) { - const onSelectCb = options.onSelectCb || function () {}; - const labelElement = options.labelElement || ""; - let selectedItems = []; +function getPlayerData() { + const player = getPlayer(); + if (player?.getVideoData) return player?.getVideoData?.call() ?? null; + return player?.data?.playerResponse?.videoDetails ?? null; +} - const container = document.createElement("vot-block"); - container.classList.add("vot-select"); +function getVideoVolume() { + const player = getPlayer(); + if (player?.getVolume) { + return player.getVolume.call() / 100; + } - if (labelElement) { - container.appendChild(labelElement); + return 1; +} + +function setVideoVolume(volume) { + const player = getPlayer(); + if (player?.setVolume) { + player.setVolume(Math.round(volume * 100)); + return true; } +} - const outer = document.createElement("vot-block"); - outer.classList.add("vot-select-outer"); +function videoSeek(video, time) { + // * TIME IN MS + debug/* default */.A.log("videoSeek", time); + const preTime = + getPlayer()?.getProgressState()?.seekableEnd || video.currentTime; + const finalTime = preTime - time; // we always throw it to the end of the stream - time + video.currentTime = finalTime; +} - const title = document.createElement("span"); - title.classList.add("vot-select-title"); - title.innerText = selectTitle; +function getSubtitles() { + const response = getPlayerResponse(); + let captionTracks = + response?.captions?.playerCaptionsTracklistRenderer?.captionTracks ?? []; + captionTracks = captionTracks.reduce((result, captionTrack) => { + if ("languageCode" in captionTrack) { + const language = captionTrack?.languageCode + ? langTo6391(captionTrack?.languageCode) + : undefined; + const url = captionTrack?.url || captionTrack?.baseUrl; + language && + url && + result.push({ + source: "youtube", + language, + isAutoGenerated: captionTrack?.kind === "asr", + url: `${ + url.startsWith("http") ? url : `${window.location.origin}/${url}` + }&fmt=json3`, + }); + } + return result; + }, []); + debug/* default */.A.log("youtube subtitles:", captionTracks); + return captionTracks; +} - if (selectTitle === undefined) { - title.innerText = items.find((i) => i.selected === true)?.label; +// Get the video data from the player +async function getVideoData() { + const player = getPlayer(); + const response = getPlayerResponse(); // null in /embed + const data = getPlayerData(); + const { title } = data ?? {}; + const { + shortDescription: description, + isLive, + isLiveContent, + isUpcoming, + } = response?.videoDetails ?? {}; + const isPremiere = (!!isLive || !!isUpcoming) && !isLiveContent; + let detectedLanguage = await getLanguage( + player, + response, + title, + description, + ); + if (!availableLangs.includes(detectedLanguage)) { + detectedLanguage = "en"; } + const videoData = { + isLive: !!isLive, + isPremiere, + title, + description, + detectedLanguage, + }; + debug/* default */.A.log("youtube video data:", videoData); + console.log("[VOT] Detected language: ", videoData.detectedLanguage); + return videoData; +} - const arrowIcon = document.createElement("vot-block"); - arrowIcon.classList.add("vot-select-arrow-icon"); - arrowIcon.innerHTML = ``; +/* harmony default export */ const youtubeUtils = ({ + isMobile, + getPlayer, + getPlayerResponse, + getPlayerData, + getVideoVolume, + getSubtitles, + getVideoData, + setVideoVolume, + videoSeek, +}); - outer.append(title, arrowIcon); - outer.onclick = () => { - const votSelectDialog = createDialog(dialogTitle); - votSelectDialog.container.classList.add("vot-dialog-temp"); - votSelectDialog.container.hidden = false; - document.documentElement.appendChild(votSelectDialog.container); +;// CONCATENATED MODULE: ./src/utils/utils.js - const contentList = document.createElement("vot-block"); - contentList.classList.add("vot-select-content-list"); - for (const item of items) { - const contentItem = document.createElement("vot-block"); - contentItem.classList.add("vot-select-content-item"); - contentItem.innerText = item.label; - contentItem.dataset.votSelected = item.selected; - contentItem.dataset.votValue = item.value; - if (item.disabled) { - contentItem.inert = true; - } - contentItem.onclick = async (e) => { - if (e.target.inert) return; +const userlang = navigator.language || navigator.userLanguage; +const lang = userlang?.substr(0, 2)?.toLowerCase() ?? "en"; - // removing the selected value for updating - const contentItems = contentList.childNodes; - contentItems.forEach((ci) => (ci.dataset.votSelected = false)); - // fixed selection after closing the modal and opening again - items.forEach((i) => (i.selected = i.value === item.value)); +// not used +// function waitForElm(selector) { +// // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists +// return new Promise((resolve) => { +// const element = document.querySelector(selector); +// if (element) { +// return resolve(element); +// } + +// const observer = new MutationObserver(() => { +// const element = document.querySelector(selector); +// if (element) { +// resolve(element); +// observer.disconnect(); +// } +// }); + +// observer.observe(document.body, { +// childList: true, +// subtree: true, +// once: true, +// }); +// }); +// } + +// not used +// const sleep = (m) => new Promise((r) => setTimeout(r, m)); - contentItem.dataset.votSelected = true; - title.innerText = item.label; +const getVideoId = (service, video) => { + let url = new URL(window.location.href); + + switch (service) { + case "piped": + case "invidious": + case "youtube": { + if (url.searchParams.has("enablejsapi")) { + const videoUrl = youtubeUtils.getPlayer().getVideoUrl(); + url = new URL(videoUrl); + } + + return ( + url.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1] || + url.searchParams.get("v") + ); + } + case "vk": + if (url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)) { + return url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1); + } else if (url.searchParams.get("z")) { + return url.searchParams.get("z").split("/")[0]; + } else if (url.searchParams.get("oid") && url.searchParams.get("id")) { + return `video-${Math.abs( + url.searchParams.get("oid"), + )}_${url.searchParams.get("id")}`; + } else { + return false; + } + case "nine_gag": + case "9gag": + case "gag": + return url.pathname.match(/gag\/([^/]+)/)?.[1]; + case "twitch": + if (/^m\.twitch\.tv$/.test(window.location.hostname)) { + const linkUrl = document.head.querySelector('link[rel="canonical"]'); + return ( + linkUrl?.href.match(/videos\/([^/]+)/)?.[0] || url.pathname.slice(1) + ); + } else if (/^player\.twitch\.tv$/.test(window.location.hostname)) { + return `videos/${url.searchParams.get("video")}`; + } else if (/^clips\.twitch\.tv$/.test(window.location.hostname)) { + // get link to twitch channel (ex.: https://www.twitch.tv/xqc) + const channelLink = document.querySelector( + ".tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']", + ); + if (!channelLink) { + return false; + } - // !!! use e.target.dataset.votValue instead of e.target.value !!! - await onSelectCb(e); - }; - contentList.appendChild(contentItem); + const channelName = channelLink.href.replace( + "https://www.twitch.tv/", + "", + ); + return `${channelName}/clip/${url.searchParams.get("clip")}`; + } else if (url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)) { + return url.pathname.match(/([^/]+)\/(?:clip)\/([^/]+)/)[0]; + } else { + return url.pathname.match(/(?:videos)\/([^/]+)/)?.[0]; + } + case "proxytok": + return url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; + case "tiktok": { + let id = url.pathname.match(/([^/]+)\/video\/([^/]+)/)?.[0]; + if (!id) { + const playerEl = video.closest(".xgplayer-playing, .tiktok-web-player"); + const itemEl = playerEl?.closest( + 'div[data-e2e="recommend-list-item-container"]', + ); + const authorEl = itemEl?.querySelector( + 'a[data-e2e="video-author-avatar"]', + ); + if (playerEl && authorEl) { + const videoId = playerEl.id?.match(/^xgwrapper-[0-9]+-(.*)$/)?.at(1); + const author = authorEl.href?.match(/.*(@.*)$/)?.at(1); + if (videoId && author) { + id = `${author}/video/${videoId}`; + } + } + } + return id; } + case "vimeo": { + const appId = url.searchParams.get("app_id"); + const videoId = + url.pathname.match(/[^/]+\/[^/]+$/)?.[0] || + url.pathname.match(/[^/]+$/)?.[0]; - // search logic - const votSearchLangTextfield = createTextfield( - localizationProvider/* localizationProvider */.V.get("searchField"), - ); - - votSearchLangTextfield.input.oninput = (e) => { - const searchText = e.target.value.toLowerCase(); - // check if there are lovercase characters in the string. used for smarter search - Array.from(selectedItems).forEach( - (ci) => (ci.hidden = !ci.innerText.toLowerCase().includes(searchText)), + return appId ? `${videoId}?app_id=${appId}` : videoId; + } + case "xvideos": + return url.pathname.match(/[^/]+\/[^/]+$/)?.[0]; + case "pornhub": + return ( + url.searchParams.get("viewkey") || + url.pathname.match(/embed\/([^/]+)/)?.[1] ); - }; - - votSelectDialog.bodyContainer.append( - votSearchLangTextfield.container, - contentList, - ); - selectedItems = contentList.childNodes; - - // remove the modal so that they do not accumulate - votSelectDialog.backdrop.onclick = votSelectDialog.closeButton.onclick = - () => { - votSelectDialog.container.remove(); - selectedItems = []; - }; - }; + case "twitter": + return url.pathname.match(/status\/([^/]+)/)?.[1]; + case "udemy": + return url.pathname; + case "rumble": + return url.pathname; + case "facebook": + return url.pathname; + case "rutube": + return url.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1]; + case "coub": + if (url.pathname.includes("/view")) { + return url.pathname.match(/view\/([^/]+)/)?.[1]; + } else if (url.pathname.includes("/embed")) { + return url.pathname.match(/embed\/([^/]+)/)?.[1]; + } else { + return document.querySelector(".coub.active")?.dataset?.permalink; + } + case "bilibili": { + const bvid = url.searchParams.get("bvid"); + if (bvid) { + return bvid; + } else { + let vid = url.pathname.match(/video\/([^/]+)/)?.[1]; + if (vid && url.search && url.searchParams.get("p") !== null) { + vid += `/?p=${url.searchParams.get("p")}`; + } + return vid; + } + } + case "mail_ru": + if (url.pathname.startsWith("/v/") || url.pathname.startsWith("/mail/")) { + return url.pathname; + } else if (url.pathname.match(/video\/embed\/([^/]+)/)) { + const referer = document.querySelector( + ".b-video-controls__mymail-link", + ); + if (!referer) { + return false; + } - container.append(outer); + return referer?.href.split("my.mail.ru")?.[1]; + } + return false; + case "bitchute": + return url.pathname.match(/video\/([^/]+)/)?.[1]; + case "coursera": + // ! LINK SHOULD BE LIKE THIS https://www.coursera.org/learn/learning-how-to-learn/lecture/75EsZ + // return url.pathname.match(/lecture\/([^/]+)\/([^/]+)/)?.[1]; // <--- COURSE PREVIEW + return url.pathname.match(/learn\/([^/]+)\/lecture\/([^/]+)/)?.[0]; // <--- COURSE PASSING (IF YOU LOGINED TO COURSERA) + case "eporner": + // ! LINK SHOULD BE LIKE THIS eporner.com/video-XXXXXXXXX/isdfsd-dfjsdfjsdf-dsfsdf-dsfsda-dsad-ddsd + return url.pathname.match(/video-([^/]+)\/([^/]+)/)?.[0]; + case "peertube": + return url.pathname.match(/\/w\/([^/]+)/)?.[0]; + case "dailymotion": { + // we work in the context of the player + // geo.dailymotion.com + const plainPlayerConfig = Array.from( + document.querySelectorAll("*"), + ).filter((s) => s.innerHTML.trim().includes(".m3u8")); + try { + let videoUrl = plainPlayerConfig[1].lastChild.src; + return videoUrl.match(/\/video\/(\w+)\.m3u8/)?.[1]; + } catch (e) { + console.error("[VOT]", e); + return false; + } + } + case "trovo": { + if (!url.pathname.startsWith("/s/")) { + return false; + } - const setTitle = (newTitle) => { - title.innerText = newTitle; - }; + const vid = url.searchParams.get("vid"); + if (!vid) { + return false; + } - const setSelected = (val) => { - Array.from(selectedItems) - .filter((ci) => !ci.inert) - .forEach((ci) => (ci.dataset.votSelected = ci.dataset.votValue === val)); - items.forEach((i) => (i.selected = String(i.value) === val)); - }; + const path = url.pathname.match(/([^/]+)\/([\d]+)/)?.[0]; + if (!path) { + return false; + } - const updateItems = (newItems) => { - items = newItems; - }; + return `${path}?vid=${vid}`; + } + case "yandexdisk": + return url.pathname.match(/\/i\/([^/]+)/)?.[1]; + case "coursehunter": { + const courseId = url.pathname.match(/\/course\/([^/]+)/)?.[1]; + return courseId ? courseId + url.search : false; + } + case "ok.ru": { + return url.pathname.match(/\/video\/(\d+)/)?.[0]; + } + case "googledrive": + return url.searchParams.get("docid"); + case "bannedvideo": + return url.searchParams.get("id"); + case "weverse": + return url.pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[0]; + case "newgrounds": + return url.pathname.match(/([^/]+)\/(view)\/([^/]+)/)?.[0]; + case "egghead": + return url.pathname; + case "youku": + return url.pathname.match(/v_show\/id_[\w=]+/)?.[0]; + default: + return false; + } +}; - return { - container, - title, - arrowIcon, - labelElement, - setTitle, - setSelected, - updateItems, - }; +function secsToStrTime(secs) { + const minutes = Math.floor(secs / 60); + const seconds = Math.floor(secs % 60); + if (minutes >= 60) { + return localizationProvider.get("translationTakeMoreThanHour"); + } else if (minutes >= 10 && minutes % 10) { + return localizationProvider + .get("translationTakeApproximatelyMinutes") + .replace("{0}", minutes); + } else if (minutes == 1 || (minutes == 0 && seconds > 0)) { + return localizationProvider.get("translationTakeAboutMinute"); + } else { + return localizationProvider + .get("translationTakeApproximatelyMinute") + .replace("{0}", minutes); + } +} +function langTo6391(lang) { + // convert lang to ISO 639-1 + return lang.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]; } -function createVOTLanguageSelect(options) { - const fromTitle = options.fromTitle || "#UNDEFINED"; - const fromDialogTitle = options.fromDialogTitle || "#UNDEFINED"; - const fromItems = options.fromItems || []; - const fromOnSelectCB = options.fromOnSelectCB || function () {}; - const toTitle = options.toTitle || "#UNDEFINED"; - const toDialogTitle = options.toDialogTitle || "#UNDEFINED"; - const toItems = options.toItems || []; - const toOnSelectCB = options.toOnSelectCB || function () {}; - - const container = document.createElement("vot-block"); - container.classList.add("vot-lang-select"); - - const fromSelect = createVOTSelect(fromTitle, fromDialogTitle, fromItems, { - onSelectCb: fromOnSelectCB, - }); - - const icon = document.createElement("vot-block"); - icon.classList.add("vot-lang-select-icon"); - icon.innerHTML = ``; - - const toSelect = createVOTSelect(toTitle, toDialogTitle, toItems, { - onSelectCb: toOnSelectCB, - }); - - container.append(fromSelect.container, icon, toSelect.container); - - return { - container, - fromSelect, - icon, - toSelect, - }; +function isPiPAvailable() { + return ( + "pictureInPictureEnabled" in document && document.pictureInPictureEnabled + ); } -/* harmony default export */ const ui = ({ - createHeader, - createInformation, - createButton, - createTextButton, - createOutlinedButton, - createIconButton, - createCheckbox, - createSlider, - createTextfield, - createDialog, - createVOTButton, - createVOTMenu, - createVOTSelectLabel, - createVOTSelect, - createVOTLanguageSelect, - updateSlider, -}); +function initHls() { + return typeof Hls != "undefined" && Hls?.isSupported() + ? new Hls({ + debug: false, // turn it on manually if necessary + lowLatencyMode: true, + backBufferLength: 90, + }) + : undefined; +} + + ;// CONCATENATED MODULE: ./src/utils/volume.js // element - audio / video element @@ -2615,6 +2388,157 @@ function syncVolume(element, sliderVolume, otherSliderVolume, tempVolume) { +;// CONCATENATED MODULE: ./src/yandexProtobuf.js +// coursera & udemy translation help object +const VideoTranslationHelpObject = new protobuf.Type( + "VideoTranslationHelpObject", +) + .add(new protobuf.Field("target", 1, "string")) // video_file_url or subtitles_file_url + .add(new protobuf.Field("targetUrl", 2, "string")); // url to video_file or url to subtitles + +const VideoTranslationRequest = new protobuf.Type("VideoTranslationRequest") + .add(new protobuf.Field("url", 3, "string")) + .add(new protobuf.Field("deviceId", 4, "string")) // removed? + .add(new protobuf.Field("firstRequest", 5, "bool")) // true for the first request, false for subsequent ones + .add(new protobuf.Field("duration", 6, "double")) + .add(new protobuf.Field("unknown2", 7, "int32")) // 1 1 + .add(new protobuf.Field("language", 8, "string")) // source language code + .add(new protobuf.Field("unknown3", 9, "int32")) // 0 - without translationHelp | 1 - with translationHelp (??? But it works without it) + .add(new protobuf.Field("unknown4", 10, "int32")) // 0 0 + .add( + new protobuf.Field( + "translationHelp", + 11, + "VideoTranslationHelpObject", + "repeated", + ), + ) // array for translation assistance ([0] -> {2: link to video, 1: "video_file_url"}, [1] -> {2: link to subtitles, 1: "subtitles_file_url"}) + .add(new protobuf.Field("responseLanguage", 14, "string")) + .add(new protobuf.Field("unknown5", 15, "int32")) // 0 + .add(new protobuf.Field("unknown6", 16, "int32")) // 1 + .add(new protobuf.Field("unknown7", 17, "int32")); // 0 + +const VideoSubtitlesRequest = new protobuf.Type("VideoSubtitlesRequest") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("language", 2, "string")); // source language code + +const VideoStreamRequest = new protobuf.Type("VideoStreamRequest") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("language", 2, "string")) + .add(new protobuf.Field("responseLanguage", 3, "string")); + +const VideoStreamPingRequest = new protobuf.Type("VideoStreamPingRequest").add( + new protobuf.Field("pingId", 1, "int32"), +); + +const VideoTranslationResponse = new protobuf.Type("VideoTranslationResponse") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("duration", 2, "double")) + .add(new protobuf.Field("status", 4, "int32")) + .add(new protobuf.Field("remainingTime", 5, "int32")) // secs before translation (used as interval before next request in yaBrowser) + .add(new protobuf.Field("unknown0", 6, "int32")) // unknown 0 (1st request) -> 10 (2nd, 3th and etc requests) + .add(new protobuf.Field("unknown1", 7, "string")) + .add(new protobuf.Field("language", 8, "string")) // detected language (if the wrong one is set) + .add(new protobuf.Field("message", 9, "string")); + +const VideoSubtitlesObject = new protobuf.Type("VideoSubtitlesObject") + .add(new protobuf.Field("language", 1, "string")) + .add(new protobuf.Field("url", 2, "string")) + .add(new protobuf.Field("unknown2", 3, "int32")) + .add(new protobuf.Field("translatedLanguage", 4, "string")) + .add(new protobuf.Field("translatedUrl", 5, "string")) + .add(new protobuf.Field("unknown5", 6, "int32")) + .add(new protobuf.Field("unknown6", 7, "int32")); + +const VideoSubtitlesResponse = new protobuf.Type("VideoSubtitlesResponse") + .add(new protobuf.Field("unknown0", 1, "int32")) + .add(new protobuf.Field("subtitles", 2, "VideoSubtitlesObject", "repeated")); + +const VideoStreamObject = new protobuf.Type("VideoStreamObject") + .add(new protobuf.Field("url", 1, "string")) + .add(new protobuf.Field("timestamp", 2, "int64")); // timestamp in ms (probably means the time of 1 request to translate the stream) + +const VideoStreamResponse = new protobuf.Type("VideoStreamResponse") + .add(new protobuf.Field("interval", 1, "int32")) // 20s - streaming, 10s - translating, 0s - there is no connection with the server (the broadcast is finished or deleted) + .add(new protobuf.Field("translatedInfo", 2, "VideoStreamObject")) + .add(new protobuf.Field("pingId", 3, "int32")); + +// * Yandex has been skipping any translation streams for a long time (whitelist always return true) +// * Most likely, it is already outdated and will not be used +// const VideoWhitelistStreamRequest = new protobuf.Type("VideoWhitelistStreamRequest") +// .add(new protobuf.Field("url", 1, "string")) +// .add(new protobuf.Field("deviceId", 4, "string")) + +// const VideoWhitelistStreamResponse = new protobuf.Type("VideoWhitelistStreamResponse") +// .add(new protobuf.Field("inWhitelist", 1, "bool")) + +// Create a root namespace and add the types +const root = new protobuf.Root() + .define("yandex") + .add(VideoTranslationHelpObject) + .add(VideoTranslationRequest) + .add(VideoTranslationResponse) + .add(VideoSubtitlesRequest) + .add(VideoSubtitlesObject) + .add(VideoSubtitlesResponse) + .add(VideoStreamPingRequest) + .add(VideoStreamRequest) + .add(VideoStreamObject) + .add(VideoStreamResponse); + +// Export the encoding and decoding functions +const yandexProtobuf = { + encodeTranslationRequest( + url, + duration, + requestLang, + responseLang, + translationHelp, + ) { + return root.VideoTranslationRequest.encode({ + url, + firstRequest: true, + duration, + unknown2: 1, + language: requestLang, + unknown3: 0, + unknown4: 0, + translationHelp, + responseLanguage: responseLang, + unknown5: 0, + unknown6: 1, + unknown7: 0, + }).finish(); + }, + decodeTranslationResponse(response) { + return root.VideoTranslationResponse.decode(new Uint8Array(response)); + }, + encodeSubtitlesRequest(url, requestLang) { + return root.VideoSubtitlesRequest.encode({ + url, + language: requestLang, + }).finish(); + }, + decodeSubtitlesResponse(response) { + return root.VideoSubtitlesResponse.decode(new Uint8Array(response)); + }, + encodeStreamPingRequest(pingId) { + return root.VideoStreamPingRequest.encode({ + pingId, + }).finish(); + }, + encodeStreamRequest(url, requestLang, responseLang) { + return root.VideoStreamRequest.encode({ + url, + language: requestLang, + responseLanguage: responseLang, + }).finish(); + }, + decodeStreamResponse(response) { + return root.VideoStreamResponse.decode(new Uint8Array(response)); + }, +}; + // EXTERNAL MODULE: ./node_modules/bowser/es5.js var es5 = __webpack_require__("./node_modules/bowser/es5.js"); ;// CONCATENATED MODULE: ./src/getUUID.js @@ -2638,7 +2562,7 @@ async function getSignature(body) { const utf8Encoder = new TextEncoder("utf-8"); const key = await window.crypto.subtle.importKey( "raw", - utf8Encoder.encode(config/* yandexHmacKey */.I1), + utf8Encoder.encode(config/* yandexHmacKey */.S7), { name: "HMAC", hash: { name: "SHA-256" } }, false, ["sign", "verify"], @@ -2653,39 +2577,25 @@ async function getSignature(body) { -;// CONCATENATED MODULE: ./src/rvt.js +;// CONCATENATED MODULE: ./src/rsp.js -// Request video translation from Yandex API -async function requestVideoTranslation( - url, - duration, - requestLang, - responseLang, - translationHelp, - callback, -) { +// Request stream ping from Yandex API +async function requestStreamPing(pingId, callback) { try { - debug/* default */.Z.log("requestVideoTranslation"); + debug/* default */.A.log("requestStreamPing"); + // ! CURRENT CLOUDFLARE WORKER DOESN'T SUPPORT STREAM TRANSLATIONS const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables - const body = yandexProtobuf.encodeTranslationRequest( - url, - duration, - requestLang, - responseLang, - translationHelp, - ); + const body = yandexProtobuf.encodeStreamPingRequest(pingId); // Send the request await yandexRequest( - // "/stream-translation/whitelist-stream", - // "/stream-translation/translate-stream", - "/video-translation/translate", + "/stream-translation/ping-stream", body, { "Vtrans-Signature": await getSignature(body), @@ -2700,7 +2610,7 @@ async function requestVideoTranslation( } } -/* harmony default export */ const rvt = (requestVideoTranslation); +/* harmony default export */ const rsp = (requestStreamPing); ;// CONCATENATED MODULE: ./src/rst.js @@ -2716,11 +2626,11 @@ async function requestStreamTranslation( callback, ) { try { - debug/* default */.Z.log("requestStreamTranslation"); + debug/* default */.A.log("requestStreamTranslation"); // ! CURRENT CLOUDFLARE WORKER DOESN'T SUPPORT STREAM TRANSLATIONS const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables const body = yandexProtobuf.encodeStreamRequest( url, @@ -2746,25 +2656,39 @@ async function requestStreamTranslation( /* harmony default export */ const rst = (requestStreamTranslation); -;// CONCATENATED MODULE: ./src/rsp.js +;// CONCATENATED MODULE: ./src/rvt.js -// Request stream ping from Yandex API -async function requestStreamPing(pingId, callback) { +// Request video translation from Yandex API +async function requestVideoTranslation( + url, + duration, + requestLang, + responseLang, + translationHelp, + callback, +) { try { - debug/* default */.Z.log("requestStreamPing"); - // ! CURRENT CLOUDFLARE WORKER DOESN'T SUPPORT STREAM TRANSLATIONS + debug/* default */.A.log("requestVideoTranslation"); const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables - const body = yandexProtobuf.encodeStreamPingRequest(pingId); + const body = yandexProtobuf.encodeTranslationRequest( + url, + duration, + requestLang, + responseLang, + translationHelp, + ); // Send the request await yandexRequest( - "/stream-translation/ping-stream", + // "/stream-translation/whitelist-stream", + // "/stream-translation/translate-stream", + "/video-translation/translate", body, { "Vtrans-Signature": await getSignature(body), @@ -2779,7 +2703,7 @@ async function requestStreamPing(pingId, callback) { } } -/* harmony default export */ const rsp = (requestStreamPing); +/* harmony default export */ const rvt = (requestVideoTranslation); ;// CONCATENATED MODULE: ./src/rvs.js @@ -2790,10 +2714,10 @@ async function requestStreamPing(pingId, callback) { // Request video subtitles from Yandex API async function requestVideoSubtitles(url, requestLang, callback) { try { - debug/* default */.Z.log("requestVideoSubtitles"); + debug/* default */.A.log("requestVideoSubtitles"); const yar = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "./src/yandexRequest.js")); const yandexRequest = yar.default; - debug/* default */.Z.log("Inited yandexRequest..."); + debug/* default */.A.log("Inited yandexRequest..."); // Initialize variables const body = yandexProtobuf.encodeSubtitlesRequest(url, requestLang); // Send the request @@ -2826,17 +2750,17 @@ function formatYandexSubtitlesTokens(line) { const lineEndMs = line.startMs + line.durationMs; return line.tokens.reduce((result, token, index) => { const nextToken = line.tokens[index + 1]; - const lastToken = result[result.length - 1]; + let lastToken; + if (result.length > 0) { + lastToken = result[result.length - 1]; + } const alignRangeEnd = lastToken?.alignRange?.end ?? 0; const newAlignRangeEnd = alignRangeEnd + token.text.length; - result.push( - Object.assign(Object.assign({}, token), { - alignRange: { - start: alignRangeEnd, - end: newAlignRangeEnd, - }, - }), - ); + token.alignRange = { + start: alignRangeEnd, + end: newAlignRangeEnd, + }; + result.push(token); if (nextToken) { const endMs = token.startMs + token.durationMs; const durationMs = nextToken.startMs @@ -2857,33 +2781,32 @@ function formatYandexSubtitlesTokens(line) { } function createSubtitlesTokens(line, previousLineLastToken) { - const tokens = line.text - .split(new RegExp("([\n \t])")) - .reduce((result, tokenText) => { - if (tokenText.length) { - const lastToken = result[result.length - 1] ?? previousLineLastToken; - const alignRangeStart = lastToken?.alignRange?.end ?? 0; - const alignRangeEnd = alignRangeStart + tokenText.length; - result.push({ - text: tokenText, - alignRange: { - start: alignRangeStart, - end: alignRangeEnd, - }, - }); - } - return result; - }, []); + const tokens = line.text.split(/([\n \t])/).reduce((result, tokenText) => { + if (tokenText.length) { + const lastToken = result[result.length - 1] ?? previousLineLastToken; + const alignRangeStart = lastToken?.alignRange?.end ?? 0; + const alignRangeEnd = alignRangeStart + tokenText.length; + result.push({ + text: tokenText, + alignRange: { + start: alignRangeStart, + end: alignRangeEnd, + }, + }); + } + return result; + }, []); const tokenDurationMs = Math.floor(line.durationMs / tokens.length); const lineEndMs = line.startMs + line.durationMs; return tokens.map((token, index) => { const isLastToken = index === tokens.length - 1; const startMs = line.startMs + tokenDurationMs * index; const durationMs = isLastToken ? lineEndMs - startMs : tokenDurationMs; - return Object.assign(Object.assign({}, token), { + return { + ...token, startMs, durationMs, - }); + }; }); } @@ -2904,11 +2827,10 @@ function getSubtitlesTokens(subtitles, source) { tokens = createSubtitlesTokens(line, lastToken); } lastToken = tokens[tokens.length - 1]; - result.push( - Object.assign(Object.assign({}, line), { - tokens, - }), - ); + result.push({ + ...line, + tokens, + }); } subtitles.containsTokens = true; return result; @@ -2955,17 +2877,17 @@ function formatYoutubeSubtitles(subtitles) { async function fetchSubtitles(subtitlesObject) { let resolved = false; let subtitles = await Promise.race([ - new Promise(async (resolve) => { - await (0,utils/* sleep */._v)(5000); - if (!resolved) { - console.error("[VOT] Failed to fetch subtitles. Reason: timeout"); - } - resolved = true; - resolve([]); + new Promise((resolve) => { + setTimeout(() => { + if (!resolved) { + console.error("[VOT] Failed to fetch subtitles. Reason: timeout"); + resolve([]); + } + }, 5000); }), - new Promise(async (resolve) => { - debug/* default */.Z.log("Fetching subtitles:", subtitlesObject); - await fetch(subtitlesObject.url) + new Promise((resolve) => { + debug/* default */.A.log("Fetching subtitles:", subtitlesObject); + fetch(subtitlesObject.url) .then((response) => response.json()) .then((json) => { resolved = true; @@ -2994,20 +2916,20 @@ async function subtitles_getSubtitles(site, videoId, requestLang) { site.host === "youtube" ? youtubeUtils.getSubtitles() : []; let resolved = false; const yaSubtitles = await Promise.race([ - new Promise(async (resolve) => { - await (0,utils/* sleep */._v)(5000); - if (!resolved) { - console.error("[VOT] Failed get yandex subtitles. Reason: timeout"); - } - resolved = true; - resolve([]); + new Promise((resolve) => { + setTimeout(() => { + if (!resolved) { + console.error("[VOT] Failed get yandex subtitles. Reason: timeout"); + resolve([]); + } + }, 5000); }), new Promise((resolve) => { rvs( `${site.url}${videoId}`, requestLang, (success, response) => { - debug/* default */.Z.log("[exec callback] Requesting video subtitles"); + debug/* default */.A.log("[exec callback] Requesting video subtitles"); if (!success) { console.error("[VOT] Failed get yandex subtitles"); @@ -3062,10 +2984,10 @@ async function subtitles_getSubtitles(site, videoId, requestLang) { } if ( a.language !== b.language && - (a.language === utils/* lang */.KQ || b.language === utils/* lang */.KQ) + (a.language === lang || b.language === lang) ) { // sort by user language - return a.language === utils/* lang */.KQ ? -1 : 1; + return a.language === lang ? -1 : 1; } if (a.source === "yandex") { // sort by translation @@ -3172,25 +3094,22 @@ class SubtitlesWidget { if (top && bottom) { this.votSubtitlesContainer.style.top = `${y - this.containerRect.y}px`; + } else if (!top) { + this.votSubtitlesContainer.style.top = `${0}px`; } else { - if (!top) { - this.votSubtitlesContainer.style.top = `${0}px`; - } else { - this.votSubtitlesContainer.style.top = `${ - this.containerRect.height - this.subtitlesContainerRect.height - }px`; - } + this.votSubtitlesContainer.style.top = `${ + this.containerRect.height - this.subtitlesContainerRect.height + }px`; } + if (left && right) { this.votSubtitlesContainer.style.left = `${x - this.containerRect.x}px`; + } else if (!left) { + this.votSubtitlesContainer.style.left = `${0}px`; } else { - if (!left) { - this.votSubtitlesContainer.style.left = `${0}px`; - } else { - this.votSubtitlesContainer.style.left = `${ - this.containerRect.width - this.subtitlesContainerRect.width - }px`; - } + this.votSubtitlesContainer.style.left = `${ + this.containerRect.width - this.subtitlesContainerRect.width + }px`; } } } @@ -3235,7 +3154,7 @@ class SubtitlesWidget { }); if (line) { if (highlightWords) { - let tokens = line.tokens; + let { tokens } = line; if (tokens.at(-1).alignRange.end > this.maxLength) { let chunks = []; let chunkStartIndex = 0; @@ -3261,12 +3180,12 @@ class SubtitlesWidget { } chunkEndIndex = i; } - for (let i = 0; i < chunks.length; i++) { + for (const chunk of chunks) { if ( - chunks[i].startMs < time && - time < chunks[i].startMs + chunks[i].durationMs + chunk.startMs < time && + time < chunk.startMs + chunk.durationMs ) { - tokens = chunks[i].tokens; + tokens = chunk.tokens; break; } } @@ -3279,23 +3198,21 @@ class SubtitlesWidget { ? 'class="passed"' : "" }>${token.text}`; - } - } else { - if (line.text.length > this.maxLength) { - let chunks = line.text.match(this.maxLengthRegexp); - let chunkDurationMs = line.durationMs / chunks.length; - for (let i = 0; i < chunks.length; i++) { - if ( - line.startMs + chunkDurationMs * i < time && - time < line.startMs + chunkDurationMs * (i + 1) - ) { - content = chunks[i].trim(); - break; - } + } + } else if (line.text.length > this.maxLength) { + let chunks = line.text.match(this.maxLengthRegexp); + let chunkDurationMs = line.durationMs / chunks.length; + for (let i = 0; i < chunks.length; i++) { + if ( + line.startMs + chunkDurationMs * i < time && + time < line.startMs + chunkDurationMs * (i + 1) + ) { + content = chunks[i].trim(); + break; } - } else { - content = line.text; } + } else { + content = line.text; } } if (content !== this.lastContent) { @@ -3335,16 +3252,16 @@ async function coursehunterUtils_getVideoData() { const { file: videoUrl, duration } = lessonData; - debug/* default */.Z.log("coursehunter course data:", courseData); + debug/* default */.A.log("coursehunter course data:", courseData); return { url: videoUrl, duration, }; } -const coursehunterUtils = { +/* harmony default export */ const coursehunterUtils = ({ getVideoData: coursehunterUtils_getVideoData, -}; +}); ;// CONCATENATED MODULE: ./src/utils/courseraUtils.js @@ -3361,13 +3278,13 @@ async function courseraUtils_getCourseData(courseId) { function getSubtitlesFileURL(captions, detectedLanguage, responseLang) { let subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.srclang) === detectedLanguage, + (caption) => langTo6391(caption.srclang) === detectedLanguage, ); if (!subtitle) { subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.srclang) === responseLang, + (caption) => langTo6391(caption.srclang) === responseLang, ) || captions?.[0]; } @@ -3401,7 +3318,7 @@ async function courseraUtils_getVideoData(responseLang = "en") { const courseData = await courseraUtils_getCourseData(courseId); let detectedLanguage = courseData?.primaryLanguageCodes?.[0]; - detectedLanguage = detectedLanguage ? (0,utils/* langTo6391 */.eL)(detectedLanguage) : "en"; + detectedLanguage = detectedLanguage ? langTo6391(detectedLanguage) : "en"; if (!availableLangs.includes(detectedLanguage)) { detectedLanguage = "en"; @@ -3437,16 +3354,16 @@ async function courseraUtils_getVideoData(responseLang = "en") { translationHelp, }; - debug/* default */.Z.log("coursera video data:", videoData); + debug/* default */.A.log("coursera video data:", videoData); console.log("[VOT] Detected language: ", videoData.detectedLanguage); return videoData; } -const courseraUtils = { +/* harmony default export */ const courseraUtils = ({ getPlayer: courseraUtils_getPlayer, getPlayerData: courseraUtils_getPlayerData, getVideoData: courseraUtils_getVideoData, -}; +}); ;// CONCATENATED MODULE: ./src/utils/udemyUtils.js @@ -3476,7 +3393,7 @@ function checkUdemyTokenExpire(expires) { async function getLectureData(udemyData, courseId, lectureId) { // reference: https://greasyfork.org/ru/scripts/422576-udemy-subtitle-downloader-v3/code if (!checkUdemyTokenExpire(udemyData.expires) || !udemyData.accessToken) { - console.error(localizationProvider/* localizationProvider */.V.get("udemyAccessTokenExpired")); + console.error(localizationProvider.get("udemyAccessTokenExpired")); return undefined; } @@ -3499,13 +3416,13 @@ async function getLectureData(udemyData, courseId, lectureId) { function udemyUtils_getSubtitlesFileURL(captions, detectedLanguage, responseLang) { let subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.locale_id) === detectedLanguage, + (caption) => langTo6391(caption.locale_id) === detectedLanguage, ); if (!subtitle) { subtitle = captions?.find( - (caption) => (0,utils/* langTo6391 */.eL)(caption.locale_id) === responseLang, + (caption) => langTo6391(caption.locale_id) === responseLang, ) || captions?.[0]; } @@ -3529,7 +3446,7 @@ function getModuleData() { ".ud-app-loader[data-module-id='course-taking']", )?.dataset?.moduleArgs; if (!moduleArgs) { - console.error(localizationProvider/* localizationProvider */.V.get("udemyModuleArgsNotFound")); + console.error(localizationProvider.get("udemyModuleArgsNotFound")); return {}; } return JSON.parse(moduleArgs); @@ -3552,22 +3469,22 @@ function getVideoURLFromPlayer() { async function udemyUtils_getVideoData(udemyData, responseLang = "en") { let translationHelp = null; const data = udemyUtils_getPlayerData(); - debug/* default */.Z.log("udemyData", udemyData); + debug/* default */.A.log("udemyData", udemyData); const moduleData = getModuleData(); - debug/* default */.Z.log("moduleData: ", moduleData); + debug/* default */.A.log("moduleData: ", moduleData); const courseId = moduleData.courseId; const lectureId = getLectureId(); - debug/* default */.Z.log(`CourseId: ${courseId}, lectureId: ${lectureId}`); + debug/* default */.A.log(`CourseId: ${courseId}, lectureId: ${lectureId}`); const courseLang = await getCourseLang(courseId); - debug/* default */.Z.log("courseLang Data:", courseLang); + debug/* default */.A.log("courseLang Data:", courseLang); const lectureData = await getLectureData(udemyData, courseId, lectureId); console.log("lecture Data:", lectureData); let detectedLanguage = courseLang?.locale?.locale; - detectedLanguage = detectedLanguage ? (0,utils/* langTo6391 */.eL)(detectedLanguage) : "en"; + detectedLanguage = detectedLanguage ? langTo6391(detectedLanguage) : "en"; if (!availableLangs.includes(detectedLanguage)) { detectedLanguage = "en"; @@ -3608,120 +3525,266 @@ async function udemyUtils_getVideoData(udemyData, responseLang = "en") { translationHelp, }; - debug/* default */.Z.log("udemy video data:", videoData); + debug/* default */.A.log("udemy video data:", videoData); console.log("[VOT] Detected language: ", videoData.detectedLanguage); return videoData; } -const udemyUtils = { +/* harmony default export */ const udemyUtils = ({ getPlayer: udemyUtils_getPlayer, getPlayerData: udemyUtils_getPlayerData, getVideoData: udemyUtils_getVideoData, getModuleData, getCourseLang, getLectureData, -}; +}); -// EXTERNAL MODULE: ./node_modules/requestidlecallback-polyfill/index.js -var requestidlecallback_polyfill = __webpack_require__("./node_modules/requestidlecallback-polyfill/index.js"); -;// CONCATENATED MODULE: ./src/utils/EventImpl.js -class EventImpl { - constructor() { - this.listeners = new Set(); - } - hasListener(e) { - return this.listeners.has(e); - } - dispatchToListener(handler, ...args) { - try { - handler(...args); - } catch (exception) { - console.error("[VOT]", exception); - } - } - addListener(handler) { - if (this.hasListener(handler)) { - throw new Error("[VOT] The listener has already been added."); - } - this.listeners.add(handler); - } - removeListener(handler) { - if (!this.hasListener(handler)) { - throw new Error("[VOT] The listener has not been added yet."); - } - this.listeners.delete(handler); - } - dispatch(...args) { - for (const handler of Array.from(this.listeners)) { - this.dispatchToListener(handler, ...args); - } - } +;// CONCATENATED MODULE: ./src/utils/bannedvideoUtils.js + + +async function getVideoInfo(videoId) { + return await fetch(`https://api.banned.video/graphql`, { + method: "POST", + body: JSON.stringify({ + operationName: "GetVideo", + query: `query GetVideo($id: String!) { + getVideo(id: $id) { + ...DisplayVideoFields + videoUrl: directUrl + live + } + } + + fragment DisplayVideoFields on Video { + title + description: summary + duration: videoDuration + }`, + variables: { + id: videoId, + }, + }), + headers: { + "User-Agent": "bannedVideoFrontEnd", + "apollographql-client-name": "banned-web", + "apollographql-client-version": "1.3", + "content-type": "application/json", + }, + }) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + data: { + getVideo: {}, + }, + }; + }); } -;// CONCATENATED MODULE: ./src/utils/VideoObserver.js +async function bannedvideoUtils_getVideoData(videoId) { + const videoData = await getVideoInfo(videoId); + debug/* default */.A.log("banned.video video data:", videoData); + const { videoUrl, duration, live, description, title } = + videoData.data.getVideo; -function filterVideoNodes(e) { - return Array.from(e) - .map((e) => { - const result = []; - if (e instanceof HTMLVideoElement) { - result.push(e); - } - if (e instanceof HTMLElement) { - result.push(...Array.from(e.querySelectorAll("video"))); - } - if (e?.shadowRoot?.querySelectorAll) { - result.push(...Array.from(e.shadowRoot.querySelectorAll("video"))); - } - return result; - }) - .flat(); + // TODO: Add detect language from title + description + + return { + url: videoUrl, + duration, + live, + title, + description, + }; } -class VideoObserver { - constructor() { - this.onVideoAdded = new EventImpl(); - this.onVideoRemoved = new EventImpl(); - this.handleVideoAddedBound = this.handleVideoAdded.bind(this); - this.handleVideoRemovedBound = this.handleVideoRemoved.bind(this); - this.observer = new MutationObserver((mutationsList) => { - window.requestIdleCallback( - () => { - mutationsList.forEach((mutation) => { - if ("childList" !== mutation.type) return; +/* harmony default export */ const bannedvideoUtils = ({ + getVideoData: bannedvideoUtils_getVideoData, +}); - filterVideoNodes(mutation.addedNodes).forEach( - this.handleVideoAddedBound, - ); - filterVideoNodes(mutation.removedNodes).forEach( - this.handleVideoRemovedBound, - ); - }); +;// CONCATENATED MODULE: ./src/utils/crypto.js +async function getHmacSha1(hmacKey, salt) { + const utf8Encoder = new TextEncoder("utf-8"); + salt = utf8Encoder.encode(salt); + + return window.crypto.subtle + .importKey( + "raw", + utf8Encoder.encode(hmacKey), + { name: "HMAC", hash: { name: "SHA-1" } }, + false, + ["sign", "verify"], + ) + .then((key) => window.crypto.subtle.sign("HMAC", key, salt)) + .then((arrayBuffer) => + btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))), + ) + .catch((err) => { + console.error(err); + return false; + }); +} + +;// CONCATENATED MODULE: ./src/utils/weverseUtils.js + + + +const API_ORIGIN = "https://global.apis.naver.com/weverse/wevweb"; // find as REACT_APP_API_GW_ORIGIN in main..js +const API_APP_ID = "be4d79eb8fc7bd008ee82c8ec4ff6fd4"; // find as REACT_APP_API_APP_ID in main..js +const API_HMAC_KEY = "1b9cb6378d959b45714bec49971ade22e6e24e42"; // find as c.active near `createHmac("sha1"...` in main..js + +async function createHash(pathname) { + // pathname example: /post/v1.0/post-3-142049908/preview?fieldSet=postForPreview... + const timestamp = Date.now(); + + let salt = pathname.substring(0, Math.min(255, pathname.length)) + timestamp; + // example salt is /video/v1.1/vod/67134/inKey?gcc=RU&appId=be4d79eb8fc7bd008ee82c8ec4ff6fd4&language=en&os=WEB&platform=WEB&wpf=pc1707527163588 + + const sign = await getHmacSha1(API_HMAC_KEY, salt); + + return { + wmsgpad: timestamp, + wmd: sign, + }; +} + +function getURLData() { + return { + appId: API_APP_ID, + language: "en", + os: "WEB", + platform: "WEB", + wpf: "pc", + }; +} + +async function getVideoPreview(postId) { + const pathname = + `/post/v1.0/post-${postId}/preview?` + + new URLSearchParams({ + fieldSet: "postForPreview", + ...getURLData(), + }); // ! DON'T EDIT ME + + const hash = await createHash(pathname); + + return await fetch(API_ORIGIN + pathname + "&" + new URLSearchParams(hash)) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + extension: { + video: {}, }, - { timeout: 1e3 }, - ); + }; }); - } - enable() { - this.observer.observe(document, { - childList: true, - subtree: true, +} + +async function getVideoInKey(videoId) { + const pathname = + `/video/v1.1/vod/${videoId}/inKey?` + + new URLSearchParams({ + gcc: "RU", + ...getURLData(), + }); // ! DON'T EDIT ME + const hash = await createHash(pathname); + + return await fetch(API_ORIGIN + pathname + "&" + new URLSearchParams(hash), { + method: "POST", + }) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return {}; }); - document.querySelectorAll("video").forEach(this.handleVideoAddedBound); - } - disable() { - this.observer.disconnect(); +} + +async function weverseUtils_getVideoInfo(infraVideoId, inkey, serviceId) { + const timestamp = Date.now(); + return await fetch( + `https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${infraVideoId}?` + + new URLSearchParams({ + key: inkey, + sid: serviceId, + // pid: "863c411f-fbf0-4b67-868a-ef54427e5316", // возможно не нужен + nonce: timestamp, + devt: "html5_pc", + prv: "N", + aup: "N", + stpb: "N", + cpl: "en", + env: "prod", + lc: "en", + adi: [ + { + adSystem: null, + }, + ], + adu: "/", + }), + ) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + videos: { + list: [], + }, + }; + }); +} + +function extractVideoInfo(videoList) { + return videoList.find( + (video) => video.useP2P === false && video.source.includes(".mp4"), + ); +} + +async function weverseUtils_getVideoData() { + // ! When translating using a regular link (like this https://weverse.io/aespa/live/3-142049908), + // ! we will get an error, so we have to do this + + const postId = new URL(window.location).pathname.match( + /([^/]+)\/(live|media)\/([^/]+)/, + )?.[3]; + + const videoPreview = await getVideoPreview(postId); + debug/* default */.A.log("weverse video preview data:", videoPreview); + + const { videoId, serviceId, infraVideoId } = videoPreview.extension.video; + + if (!(videoId && serviceId && infraVideoId)) { + return false; } - handleVideoAdded(video) { - this.onVideoAdded.dispatch(video); + + const { inKey } = await getVideoInKey(videoId); + debug/* default */.A.log("weverse video inKey data:", videoPreview); + if (!inKey) { + return false; } - handleVideoRemoved(video) { - document.contains(video) || this.onVideoRemoved.dispatch(video); + + const videoData = await weverseUtils_getVideoInfo(infraVideoId, inKey, serviceId); + debug/* default */.A.log("weverse video data:", videoData); + + const videoSource = extractVideoInfo(videoData.videos.list); + if (!videoSource) { + return false; } + + const { source: url, duration } = videoSource; + return { + url, + duration, + }; } +/* harmony default export */ const weverseUtils = ({ + getVideoData: weverseUtils_getVideoData, +}); + ;// CONCATENATED MODULE: ./src/config/sites.js @@ -3814,12 +3877,24 @@ const sites = () => { selector: ".videoplayer_media", }, { - // TODO: video selector: ".vp-video-wrapper > .vp-video > .vp-telecine > video" host: "vimeo", url: "https://vimeo.com/", - match: /^(player.)?vimeo.com$/, + match: /^vimeo.com$/, + selector: ".player", + }, + { + additionalData: "embed", + host: "vimeo", + url: "https://player.vimeo.com/", + match: /^player.vimeo.com$/, selector: ".player", }, + { + host: "ok.ru", + url: "https://ok.ru/", + match: /^ok.ru$/, + selector: ".html5-vpl_vid", + }, { host: "nine_gag", url: "https://9gag.com/gag/", @@ -3836,7 +3911,7 @@ const sites = () => { host: "bitchute", url: "https://www.bitchute.com/video/", match: /^(www.)?bitchute.com$/, - selector: ".plyr__video-wrapper", + selector: "#player", }, { host: "rutube", @@ -3947,11 +4022,169 @@ const sites = () => { match: /^coursehunter.net$/, selector: "#oframeplayer > pjsdiv:nth-of-type(1)", }, + { + host: "googledrive", + url: "https://drive.google.com/file/d/", + match: /^youtube.googleapis.com$/, + selector: ".html5-video-container", + }, + { + host: "bannedvideo", + url: "https://banned.video/watch?id=", + match: /^(www.)?banned.video$/, + selector: ".vjs-v7", + }, + { + host: "facebook", + url: "https://facebook.com", // <-- there should be no slash because we take the whole pathname + match: (url) => + url.host.includes("facebook.com") && url.pathname.includes("/videos/"), + selector: 'div[data-pagelet="WatchPermalinkVideo"]', + }, + { + additionalData: "reels", + host: "facebook", + url: "https://facebook.com", // <-- there should be no slash because we take the whole pathname + match: (url) => + url.host.includes("facebook.com") && url.pathname.includes("/reel/"), + selector: 'div[role="main"]', + }, + { + host: "weverse", + url: "https://weverse.io/", + match: /^weverse.io$/, + selector: ".webplayer-internal-source-wrapper", + }, + { + host: "newgrounds", + url: "https://www.newgrounds.com/", + match: /^www.newgrounds.com$/, + selector: ".ng-video-player", + }, + { + // TODO: Добавить поддержку tips и платных курсов + host: "egghead", + url: "https://egghead.io", + match: /^egghead.io$/, + selector: ".cueplayer-react-video-holder", + }, + { + host: "youku", + // Что-то перекрывает кнопку и не дает её нажать + url: "https://v.youku.com/", + match: /^v.youku.com$/, + selector: "#ykPlayer", + }, + // Нужно куда-то заливать данные о плейлисте + // { + // host: "epicgames", + // url: "https://dev.epicgames.com/community/learning/tutorials/", + // match: /^dev.epicgames.com$/, + // selector: "#vjs_video_3", + // }, ]; }; /* harmony default export */ const config_sites = (sites()); +// EXTERNAL MODULE: ./node_modules/requestidlecallback-polyfill/index.js +var requestidlecallback_polyfill = __webpack_require__("./node_modules/requestidlecallback-polyfill/index.js"); +;// CONCATENATED MODULE: ./src/utils/EventImpl.js +class EventImpl { + constructor() { + this.listeners = new Set(); + } + hasListener(e) { + return this.listeners.has(e); + } + dispatchToListener(handler, ...args) { + try { + handler(...args); + } catch (exception) { + console.error("[VOT]", exception); + } + } + addListener(handler) { + if (this.hasListener(handler)) { + throw new Error("[VOT] The listener has already been added."); + } + this.listeners.add(handler); + } + removeListener(handler) { + if (!this.hasListener(handler)) { + throw new Error("[VOT] The listener has not been added yet."); + } + this.listeners.delete(handler); + } + dispatch(...args) { + for (const handler of Array.from(this.listeners)) { + this.dispatchToListener(handler, ...args); + } + } +} + +;// CONCATENATED MODULE: ./src/utils/VideoObserver.js + + + +function filterVideoNodes(nodes) { + return Array.from(nodes).flatMap((node) => { + if (node instanceof HTMLVideoElement) { + return [node]; + } + if (node instanceof HTMLElement) { + return Array.from(node.querySelectorAll("video")); + } + return node.shadowRoot + ? Array.from(node.shadowRoot.querySelectorAll("video")) + : []; + }); +} + +class VideoObserver { + constructor() { + this.onVideoAdded = new EventImpl(); + this.onVideoRemoved = new EventImpl(); + this.handleVideoAddedBound = this.handleVideoAdded.bind(this); + this.handleVideoRemovedBound = this.handleVideoRemoved.bind(this); + this.observer = new MutationObserver((mutationsList) => { + window.requestIdleCallback( + () => { + mutationsList.forEach((mutation) => { + if (mutation.type !== "childList") return; + + filterVideoNodes(mutation.addedNodes).forEach( + this.handleVideoAddedBound, + ); + filterVideoNodes(mutation.removedNodes).forEach( + this.handleVideoRemovedBound, + ); + }); + }, + { timeout: 1000 }, + ); + }); + } + enable() { + this.observer.observe(document, { + childList: true, + subtree: true, + }); + document.querySelectorAll("video").forEach(this.handleVideoAddedBound); + } + disable() { + this.observer.disconnect(); + } + handleVideoAdded(video) { + this.onVideoAdded.dispatch(video); + } + handleVideoRemoved(video) { + if (!document.contains(video)) { + this.onVideoRemoved.dispatch(video); + } + } +} + ;// CONCATENATED MODULE: ./src/index.js @@ -3977,6 +4210,9 @@ const sites = () => { + + + @@ -3996,7 +4232,7 @@ const videoLipSyncEvents = [ function genOptionsByOBJ(obj, conditionString, validateLangs = false) { return obj.map((code) => ({ label: `${validateLangs && !actualTTS.includes(code) ? "❌ " : ""}${ - localizationProvider/* localizationProvider */.V.get("langs")[code] ?? code.toUpperCase() + localizationProvider.get("langs")[code] ?? code.toUpperCase() }`, value: code, selected: conditionString === code, @@ -4013,11 +4249,11 @@ function translateVideo( translationHelp, callback, ) { - debug/* default */.Z.log( + debug/* default */.A.log( `Translate video (url: ${url}, duration: ${duration}, requestLang: ${requestLang}, responseLang: ${responseLang})`, ); - debug/* default */.Z.log("translationHelp:", translationHelp); + debug/* default */.A.log("translationHelp:", translationHelp); if (false) {} @@ -4032,9 +4268,9 @@ function translateVideo( (success, response) => { translationPanding = false; - debug/* default */.Z.log("[exec callback] Requesting video translation"); + debug/* default */.A.log("[exec callback] Requesting video translation"); if (!success) { - callback(false, localizationProvider/* localizationProvider */.V.get("requestTranslationFailed")); + callback(false, localizationProvider.get("requestTranslationFailed")); return; } @@ -4050,15 +4286,15 @@ function translateVideo( callback( !!translateResponse.url, translateResponse.url || - localizationProvider/* localizationProvider */.V.get("audioNotReceived"), + localizationProvider.get("audioNotReceived"), ); break; case 2: callback( false, translateResponse.remainingTime - ? (0,utils/* secsToStrTime */.PG)(translateResponse.remainingTime) - : localizationProvider/* localizationProvider */.V.get("translationTakeFewMinutes"), + ? secsToStrTime(translateResponse.remainingTime) + : localizationProvider.get("translationTakeFewMinutes"), ); break; case 3: @@ -4077,7 +4313,7 @@ function translateVideo( Он появляется при первом запросе с 17=1, но не исключено, что может появится и просто так */ - callback(false, localizationProvider/* localizationProvider */.V.get("videoBeingTranslated")); + callback(false, localizationProvider.get("videoBeingTranslated")); break; } }, @@ -4085,7 +4321,7 @@ function translateVideo( } function translateStream(url, requestLang, responseLang, callback) { - debug/* default */.Z.log( + debug/* default */.A.log( `Translate stream (url: ${url}, requestLang: ${requestLang}, responseLang: ${responseLang})`, ); @@ -4094,9 +4330,9 @@ function translateStream(url, requestLang, responseLang, callback) { requestLang, responseLang, (success, response) => { - debug/* default */.Z.log("[exec callback] Requesting stream translation"); + debug/* default */.A.log("[exec callback] Requesting stream translation"); if (!success) { - callback(false, localizationProvider/* localizationProvider */.V.get("requestTranslationFailed")); + callback(false, localizationProvider.get("requestTranslationFailed")); return; } @@ -4108,14 +4344,14 @@ function translateStream(url, requestLang, responseLang, callback) { callback( false, streamResponse.interval, - localizationProvider/* localizationProvider */.V.get("translationTakeFewMinutes"), + localizationProvider.get("translationTakeFewMinutes"), ); break; case 20: callback( true, streamResponse.interval, - streamResponse || localizationProvider/* localizationProvider */.V.get("audioNotReceived"), + streamResponse || localizationProvider.get("audioNotReceived"), ); break; case 0: @@ -4123,7 +4359,7 @@ function translateStream(url, requestLang, responseLang, callback) { callback( false, streamResponse.interval, - localizationProvider/* localizationProvider */.V.get("streamNoConnectionToServer"), + localizationProvider.get("streamNoConnectionToServer"), ); break; } @@ -4134,7 +4370,7 @@ function translateStream(url, requestLang, responseLang, callback) { class VideoHandler { // translate properties translateFromLang = "en"; // default language of video - translateToLang = utils/* lang */.KQ; // default language of audio response + translateToLang = lang; // default language of audio response timer; @@ -4142,7 +4378,11 @@ class VideoHandler { videoData = ""; firstPlay = true; audio = new Audio(); - hls = (0,utils/* initHls */.QZ)(); // debug enabled only in dev mode + hls = initHls(); // debug enabled only in dev mode + + videoTranslations = []; + videoTranslationTTL = 7200; + downloadTranslationUrl = null; downloadSubtitlesUrl = null; @@ -4158,7 +4398,7 @@ class VideoHandler { videoLastSrcObject = null; constructor(video, container, site) { - debug/* default */.Z.log( + debug/* default */.A.log( "[VideoHandler] add video:", video, "container:", @@ -4169,16 +4409,7 @@ class VideoHandler { this.container = container; this.site = site; this.handleSrcChangedBound = this.handleSrcChanged.bind(this); - this.srcObserver = new MutationObserver(this.handleSrcChangedBound); - this.srcObserver.observe(this.video, { - attributeFilter: ["src", "currentSrc"], - }); - this.srcObjectInterval = setInterval(async () => { - if (this.videoLastSrcObject !== this.video.srcObject) { - this.videoLastSrcObject = this.video.srcObject; - await this.handleSrcChanged(); - } - }, 100); + this.video.addEventListener("loadedmetadata", this.handleSrcChangedBound); this.stopTranslationBound = this.stopTranslation.bind(this); this.handleVideoEventBound = this.handleVideoEvent.bind(this); this.changeOpacityOnEventBound = this.changeOpacityOnEvent.bind(this); @@ -4189,52 +4420,46 @@ class VideoHandler { async init() { if (this.initialized) return; - this.data = { - autoTranslate: await storage/* votStorage */.i.get("autoTranslate", 0, true), - dontTranslateLanguage: await storage/* votStorage */.i.get( - "dontTranslateLanguage", - utils/* lang */.KQ, - ), - dontTranslateYourLang: await storage/* votStorage */.i.get( - "dontTranslateYourLang", - 1, - true, - ), - autoSetVolumeYandexStyle: await storage/* votStorage */.i.get( + const audioProxyDefault = + lang === "uk" && undefined === "cloudflare" ? 0 : 0; + + const dataPromises = { + autoTranslate: votStorage.get("autoTranslate", 0, true), + dontTranslateLanguage: votStorage.get("dontTranslateLanguage", lang), + dontTranslateYourLang: votStorage.get("dontTranslateYourLang", 1, true), + autoSetVolumeYandexStyle: votStorage.get( "autoSetVolumeYandexStyle", 1, true, ), - autoVolume: - (await storage/* votStorage */.i.get("autoVolume", config/* defaultAutoVolume */.sN, true)) / 100, - showVideoSlider: await storage/* votStorage */.i.get("showVideoSlider", 1, true), - syncVolume: await storage/* votStorage */.i.get("syncVolume", 0, true), - subtitlesMaxLength: await storage/* votStorage */.i.get("subtitlesMaxLength", 300, true), - highlightWords: await storage/* votStorage */.i.get("highlightWords", 0, true), - responseLanguage: await storage/* votStorage */.i.get("responseLanguage", utils/* lang */.KQ), - defaultVolume: await storage/* votStorage */.i.get("defaultVolume", 100, true), - udemyData: await storage/* votStorage */.i.get("udemyData", { - accessToken: "", - expires: 0, - }), - audioProxy: await storage/* votStorage */.i.get( - "audioProxy", - utils/* lang */.KQ === "uk" && undefined === "cloudflare" ? 0 : 0, - true, - ), - showPiPButton: await storage/* votStorage */.i.get("showPiPButton", 0, true), - translateAPIErrors: await storage/* votStorage */.i.get("translateAPIErrors", 1, true), - translationService: await storage/* votStorage */.i.get( + autoVolume: votStorage.get("autoVolume", config/* defaultAutoVolume */.JD, true), + showVideoSlider: votStorage.get("showVideoSlider", 1, true), + syncVolume: votStorage.get("syncVolume", 0, true), + subtitlesMaxLength: votStorage.get("subtitlesMaxLength", 300, true), + highlightWords: votStorage.get("highlightWords", 0, true), + responseLanguage: votStorage.get("responseLanguage", lang), + defaultVolume: votStorage.get("defaultVolume", 100, true), + udemyData: votStorage.get("udemyData", { accessToken: "", expires: 0 }), + audioProxy: votStorage.get("audioProxy", audioProxyDefault, true), + showPiPButton: votStorage.get("showPiPButton", 0, true), + translateAPIErrors: votStorage.get("translateAPIErrors", 1, true), + translationService: votStorage.get( "translationService", - config/* defaultTranslationService */.kF, - ), - detectService: await storage/* votStorage */.i.get( - "detectService", - config/* defaultDetectService */.EY, + config/* defaultTranslationService */.mE, ), - m3u8ProxyHost: await storage/* votStorage */.i.get("m3u8ProxyHost", config/* m3u8ProxyHost */.e6), - proxyWorkerHost: await storage/* votStorage */.i.get("proxyWorkerHost", config/* proxyWorkerHost */.ez), + detectService: votStorage.get("detectService", config/* defaultDetectService */.K2), + m3u8ProxyHost: votStorage.get("m3u8ProxyHost", config/* m3u8ProxyHost */.se), + proxyWorkerHost: votStorage.get("proxyWorkerHost", config/* proxyWorkerHost */.Pm), }; + + const dataEntries = await Promise.all( + Object.entries(dataPromises).map(async ([key, promise]) => [ + key, + await promise, + ]), + ); + this.data = Object.fromEntries(dataEntries); + this.videoData = await this.getVideoData(); console.log("[db] data from db: ", this.data); @@ -4250,10 +4475,12 @@ class VideoHandler { this.initUI(); this.initUIEvents(); - const hide = + const videoHasNoSource = !this.video.src && !this.video.currentSrc && !this.video.srcObject; - this.votButton.container.hidden = hide; - hide && (this.votMenu.container.hidden = hide); + this.votButton.container.hidden = videoHasNoSource; + if (videoHasNoSource) { + this.votMenu.container.hidden = true; + } await this.updateSubtitles(); await this.changeSubtitlesLang("disabled"); @@ -4277,14 +4504,14 @@ class VideoHandler { // VOT Button { this.votButton = ui.createVOTButton( - localizationProvider/* localizationProvider */.V.get("translateVideo"), + localizationProvider.get("translateVideo"), ); this.container.appendChild(this.votButton.container); this.votButton.pipButton.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data?.showPiPButton; + !isPiPAvailable() || !this.data?.showPiPButton; this.votButton.separator2.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data?.showPiPButton; + !isPiPAvailable() || !this.data?.showPiPButton; this.votButton.container.addEventListener("click", (e) => { e.preventDefault(); @@ -4295,7 +4522,7 @@ class VideoHandler { // VOT Menu { - this.votMenu = ui.createVOTMenu(localizationProvider/* localizationProvider */.V.get("VOTSettings")); + this.votMenu = ui.createVOTMenu(localizationProvider.get("VOTSettings")); this.container.appendChild(this.votMenu.container); this.votDownloadButton = ui.createIconButton( @@ -4317,18 +4544,18 @@ class VideoHandler { this.votTranslationLanguageSelect = ui.createVOTLanguageSelect({ fromTitle: - localizationProvider/* localizationProvider */.V.get("langs")[this.video.detectedLanguage], - fromDialogTitle: localizationProvider/* localizationProvider */.V.get("videoLanguage"), + localizationProvider.get("langs")[this.video.detectedLanguage], + fromDialogTitle: localizationProvider.get("videoLanguage"), fromItems: [ { - label: localizationProvider/* localizationProvider */.V.get("langs")["auto"], + label: localizationProvider.get("langs")["auto"], value: "auto", selected: "", }, ...genOptionsByOBJ(availableLangs, this.videoData.detectedLanguage), ], fromOnSelectCB: async (e) => { - debug/* default */.Z.log( + debug/* default */.A.log( "[fromOnSelectCB] select from language", e.target.dataset.votValue, ); @@ -4338,8 +4565,8 @@ class VideoHandler { this.videoData.responseLanguage, ); }, - toTitle: localizationProvider/* localizationProvider */.V.get("langs")[this.video.responseLanguage], - toDialogTitle: localizationProvider/* localizationProvider */.V.get("translationLanguage"), + toTitle: localizationProvider.get("langs")[this.video.responseLanguage], + toDialogTitle: localizationProvider.get("translationLanguage"), toItems: [ ...genOptionsByOBJ( availableLangs, @@ -4359,10 +4586,10 @@ class VideoHandler { ], toOnSelectCB: async (e) => { const newLang = e.target.dataset.votValue; - debug/* default */.Z.log("[toOnSelectCB] select to language", newLang); + debug/* default */.A.log("[toOnSelectCB] select to language", newLang); this.data.responseLanguage = this.translateToLang = newLang; - await storage/* votStorage */.i.set("responseLanguage", this.data.responseLanguage); - debug/* default */.Z.log( + await votStorage.set("responseLanguage", this.data.responseLanguage); + debug/* default */.A.log( "Response Language value changed. New value: ", this.data.responseLanguage, ); @@ -4379,11 +4606,11 @@ class VideoHandler { ); this.votSubtitlesSelect = ui.createVOTSelect( - localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), - localizationProvider/* localizationProvider */.V.get("VOTSubtitles"), + localizationProvider.get("VOTSubtitlesDisabled"), + localizationProvider.get("VOTSubtitles"), [ { - label: localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), + label: localizationProvider.get("VOTSubtitlesDisabled"), value: "disabled", selected: true, disabled: false, @@ -4394,7 +4621,7 @@ class VideoHandler { await this.changeSubtitlesLang(e.target.dataset.votValue); }, labelElement: ui.createVOTSelectLabel( - localizationProvider/* localizationProvider */.V.get("VOTSubtitles"), + localizationProvider.get("VOTSubtitles"), ), }, ); @@ -4402,7 +4629,7 @@ class VideoHandler { this.votMenu.bodyContainer.appendChild(this.votSubtitlesSelect.container); this.votVideoVolumeSlider = ui.createSlider( - `${localizationProvider/* localizationProvider */.V.get("VOTVolume")}: ${ + `${localizationProvider.get("VOTVolume")}: ${ this.getVideoVolume() * 100 }%`, this.getVideoVolume() * 100, @@ -4415,7 +4642,7 @@ class VideoHandler { ); this.votVideoTranslationVolumeSlider = ui.createSlider( - `${localizationProvider/* localizationProvider */.V.get("VOTVolumeTranslation")}: ${ + `${localizationProvider.get("VOTVolumeTranslation")}: ${ this.data?.defaultVolume ?? 100 }%`, this.data?.defaultVolume ?? 100, @@ -4436,19 +4663,19 @@ class VideoHandler { // VOT Settings { this.votSettingsDialog = ui.createDialog( - localizationProvider/* localizationProvider */.V.get("VOTSettings"), + localizationProvider.get("VOTSettings"), ); document.documentElement.appendChild(this.votSettingsDialog.container); this.votTranslationHeader = ui.createHeader( - localizationProvider/* localizationProvider */.V.get("translationSettings"), + localizationProvider.get("translationSettings"), ); this.votSettingsDialog.bodyContainer.appendChild( this.votTranslationHeader, ); this.votAutoTranslateCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTAutoTranslate"), + localizationProvider.get("VOTAutoTranslate"), this.data?.autoTranslate ?? false, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4456,24 +4683,24 @@ class VideoHandler { ); this.votDontTranslateYourLangSelect = ui.createVOTSelect( - localizationProvider/* localizationProvider */.V.get("langs")[ - storage/* votStorage */.i.syncGet("dontTranslateLanguage", utils/* lang */.KQ) + localizationProvider.get("langs")[ + votStorage.syncGet("dontTranslateLanguage", lang) ], - localizationProvider/* localizationProvider */.V.get("VOTDontTranslateYourLang"), + localizationProvider.get("VOTDontTranslateYourLang"), genOptionsByOBJ( availableLangs, - storage/* votStorage */.i.syncGet("dontTranslateLanguage", utils/* lang */.KQ), + votStorage.syncGet("dontTranslateLanguage", lang), ), { onSelectCb: async (e) => { this.data.dontTranslateLanguage = e.target.dataset.votValue; - await storage/* votStorage */.i.set( + await votStorage.set( "dontTranslateLanguage", this.data.dontTranslateLanguage, ); }, labelElement: ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTDontTranslateYourLang"), + localizationProvider.get("VOTDontTranslateYourLang"), this.data?.dontTranslateYourLang ?? true, ).container, }, @@ -4484,17 +4711,15 @@ class VideoHandler { ); this.votAutoSetVolumeCheckbox = ui.createCheckbox( - `${localizationProvider/* localizationProvider */.V.get("VOTAutoSetVolume")}`, + `${localizationProvider.get("VOTAutoSetVolume")}`, this.data?.autoSetVolumeYandexStyle ?? true, ); this.votSettingsDialog.bodyContainer.appendChild( this.votAutoSetVolumeCheckbox.container, ); this.votAutoSetVolumeSlider = ui.createSlider( - `${ - (this.data?.autoVolume ?? config/* defaultAutoVolume */.sN) * 100 - }%`, - (this.data?.autoVolume ?? config/* defaultAutoVolume */.sN) * 100, + `${(this.data?.autoVolume ?? config/* defaultAutoVolume */.JD) * 100}%`, + (this.data?.autoVolume ?? config/* defaultAutoVolume */.JD) * 100, 0, 100, ); @@ -4503,7 +4728,7 @@ class VideoHandler { ); this.votShowVideoSliderCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTShowVideoSlider"), + localizationProvider.get("VOTShowVideoSlider"), this.data?.showVideoSlider ?? false, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4512,7 +4737,7 @@ class VideoHandler { // udemy only this.votUdemyDataTextfield = ui.createTextfield( - localizationProvider/* localizationProvider */.V.get("VOTUdemyData"), + localizationProvider.get("VOTUdemyData"), this.data?.udemyData?.accessToken ?? "", ); this.votUdemyDataTextfield.container.hidden = this.site.host !== "udemy"; @@ -4522,56 +4747,57 @@ class VideoHandler { // youtube only this.votSyncVolumeCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTSyncVolume"), + localizationProvider.get("VOTSyncVolume"), this.data?.syncVolume ?? false, ); this.votSyncVolumeCheckbox.container.hidden = - this.site.host !== "youtube" || this.site.additionalData === "mobile"; + !["youtube", "googledrive"].includes(this.site.host) || + this.site.additionalData === "mobile"; this.votSettingsDialog.bodyContainer.appendChild( this.votSyncVolumeCheckbox.container, ); this.votTranslationServiceSelect = ui.createVOTSelect( - storage/* votStorage */.i.syncGet("translationService", config/* defaultTranslationService */.kF), - localizationProvider/* localizationProvider */.V.get("VOTTranslationService"), + votStorage.syncGet("translationService", config/* defaultTranslationService */.mE), + localizationProvider.get("VOTTranslationService"), genOptionsByOBJ( translateServices, - storage/* votStorage */.i.syncGet("translationService", config/* defaultTranslationService */.kF), + votStorage.syncGet("translationService", config/* defaultTranslationService */.mE), ), { onSelectCb: async (e) => { this.data.translationService = e.target.dataset.votValue; - await storage/* votStorage */.i.set( + await votStorage.set( "translationService", this.data.translationService, ); }, labelElement: ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTTranslateAPIErrors"), + localizationProvider.get("VOTTranslateAPIErrors"), this.data.translateAPIErrors ?? true, ).container, }, ); this.votTranslationServiceSelect.container.hidden = - localizationProvider/* localizationProvider */.V.lang === "ru"; + localizationProvider.lang === "ru"; this.votSettingsDialog.bodyContainer.appendChild( this.votTranslationServiceSelect.container, ); this.votDetectServiceSelect = ui.createVOTSelect( - storage/* votStorage */.i.syncGet("detectService", config/* defaultDetectService */.EY), - localizationProvider/* localizationProvider */.V.get("VOTDetectService"), + votStorage.syncGet("detectService", config/* defaultDetectService */.K2), + localizationProvider.get("VOTDetectService"), genOptionsByOBJ( detectServices, - storage/* votStorage */.i.syncGet("detectService", config/* defaultDetectService */.EY), + votStorage.syncGet("detectService", config/* defaultDetectService */.K2), ), { onSelectCb: async (e) => { this.data.detectService = e.target.dataset.votValue; - await storage/* votStorage */.i.set("detectService", this.data.detectService); + await votStorage.set("detectService", this.data.detectService); }, labelElement: ui.createVOTSelectLabel( - localizationProvider/* localizationProvider */.V.get("VOTDetectService"), + localizationProvider.get("VOTDetectService"), ), }, ); @@ -4582,12 +4808,12 @@ class VideoHandler { // SUBTITLES this.votSubtitlesHeader = ui.createHeader( - localizationProvider/* localizationProvider */.V.get("subtitlesSettings"), + localizationProvider.get("subtitlesSettings"), ); this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader); this.votSubtitlesMaxLengthSlider = ui.createSlider( - `${localizationProvider/* localizationProvider */.V.get("VOTSubtitlesMaxLength")}: ${ + `${localizationProvider.get("VOTSubtitlesMaxLength")}: ${ this.data?.subtitlesMaxLength ?? 300 }`, this.data?.subtitlesMaxLength ?? 300, @@ -4599,7 +4825,7 @@ class VideoHandler { ); this.votSubtitlesHighlightWordsCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTHighlightWords"), + localizationProvider.get("VOTHighlightWords"), this.data?.highlightWords ?? false, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4609,14 +4835,14 @@ class VideoHandler { // PROXY this.votProxyHeader = ui.createHeader( - localizationProvider/* localizationProvider */.V.get("proxySettings"), + localizationProvider.get("proxySettings"), ); this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader); this.votM3u8ProxyHostTextfield = ui.createTextfield( - localizationProvider/* localizationProvider */.V.get("VOTM3u8ProxyHost"), + localizationProvider.get("VOTM3u8ProxyHost"), this.data?.m3u8ProxyHost, - config/* m3u8ProxyHost */.e6, + config/* m3u8ProxyHost */.se, ); this.votSettingsDialog.bodyContainer.appendChild( this.votM3u8ProxyHostTextfield.container, @@ -4624,9 +4850,9 @@ class VideoHandler { // cf version only this.votProxyWorkerHostTextfield = ui.createTextfield( - localizationProvider/* localizationProvider */.V.get("VOTProxyWorkerHost"), + localizationProvider.get("VOTProxyWorkerHost"), this.data?.proxyWorkerHost, - config/* proxyWorkerHost */.ez, + config/* proxyWorkerHost */.Pm, ); this.votProxyWorkerHostTextfield.container.hidden = undefined !== "cloudflare"; @@ -4636,7 +4862,7 @@ class VideoHandler { // cf version only this.votAudioProxyCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTAudioProxy"), + localizationProvider.get("VOTAudioProxy"), this.data?.audioProxy ?? false, ); this.votAudioProxyCheckbox.container.hidden = undefined !== "cloudflare"; @@ -4646,27 +4872,27 @@ class VideoHandler { // ABOUT - this.votAboutHeader = ui.createHeader(localizationProvider/* localizationProvider */.V.get("about")); + this.votAboutHeader = ui.createHeader(localizationProvider.get("about")); this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader); this.votLanguageSelect = ui.createVOTSelect( - localizationProvider/* localizationProvider */.V.get("langs")[ - storage/* votStorage */.i.syncGet("locale-lang-override", "auto") + localizationProvider.get("langs")[ + votStorage.syncGet("locale-lang-override", "auto") ], - localizationProvider/* localizationProvider */.V.get("VOTMenuLanguage"), + localizationProvider.get("VOTMenuLanguage"), genOptionsByOBJ( - localizationProvider/* availableLocales */.Z, - storage/* votStorage */.i.syncGet("locale-lang-override", "auto"), + availableLocales, + votStorage.syncGet("locale-lang-override", "auto"), ), { onSelectCb: async (e) => { - await storage/* votStorage */.i.set( + await votStorage.set( "locale-lang-override", e.target.dataset.votValue, ); }, labelElement: ui.createVOTSelectLabel( - localizationProvider/* localizationProvider */.V.get("VOTMenuLanguage"), + localizationProvider.get("VOTMenuLanguage"), ), }, ); @@ -4676,16 +4902,16 @@ class VideoHandler { ); this.votShowPiPButtonCheckbox = ui.createCheckbox( - localizationProvider/* localizationProvider */.V.get("VOTShowPiPButton"), + localizationProvider.get("VOTShowPiPButton"), this.data?.showPiPButton ?? false, ); - this.votShowPiPButtonCheckbox.container.hidden = !(0,utils/* isPiPAvailable */.qq)(); + this.votShowPiPButtonCheckbox.container.hidden = !isPiPAvailable(); this.votSettingsDialog.bodyContainer.appendChild( this.votShowPiPButtonCheckbox.container, ); this.votVersionInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTVersion")}:`, + `${localizationProvider.get("VOTVersion")}:`, false ? 0 : GM_info.script.version, @@ -4695,7 +4921,7 @@ class VideoHandler { ); this.votAuthorsInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTAuthors")}:`, + `${localizationProvider.get("VOTAuthors")}:`, GM_info.script.author, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4703,7 +4929,7 @@ class VideoHandler { ); this.votLoaderInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTLoader")}:`, + `${localizationProvider.get("VOTLoader")}:`, `${GM_info.scriptHandler} v${GM_info.version}`, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4711,7 +4937,7 @@ class VideoHandler { ); this.votBrowserInfo = ui.createInformation( - `${localizationProvider/* localizationProvider */.V.get("VOTBrowser")}:`, + `${localizationProvider.get("VOTBrowser")}:`, `${browserInfo.browser.name} ${browserInfo.browser.version} (${browserInfo.os.name} ${browserInfo.os.version})`, ); this.votSettingsDialog.bodyContainer.appendChild( @@ -4719,7 +4945,7 @@ class VideoHandler { ); this.votResetSettingsButton = ui.createButton( - localizationProvider/* localizationProvider */.V.get("resetSettings"), + localizationProvider.get("resetSettings"), ); this.votSettingsDialog.bodyContainer.appendChild( this.votResetSettingsButton, @@ -4730,38 +4956,47 @@ class VideoHandler { initUIEvents() { // VOT Button { - this.votButton.translateButton.addEventListener("click", async () => { - if (this.audio.src) { - debug/* default */.Z.log("[click translationBtn] audio.src is not empty"); - this.stopTraslate(); - return; - } - - try { - debug/* default */.Z.log("[click translationBtn] trying execute translation"); - const VIDEO_ID = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); + this.votButton.translateButton.addEventListener("click", () => { + (async () => { + if (this.audio.src) { + debug/* default */.A.log("[click translationBtn] audio.src is not empty"); + this.stopTranslate(); + return; + } - if (!VIDEO_ID) { - throw new VOTLocalizedError("VOTNoVideoIDFound"); + if (this.hls.url) { + debug/* default */.A.log("[click translationBtn] hls is not empty"); + this.stopTranslate(); + return; } - await this.translateExecutor(VIDEO_ID); - } catch (err) { - console.error("[VOT]", err); - if (err?.name === "VOTLocalizedError") { - this.transformBtn("error", err.localizedMessage); - } else { - this.transformBtn("error", err); + try { + debug/* default */.A.log("[click translationBtn] trying execute translation"); + + if (!this.videoData.videoId) { + throw new VOTLocalizedError("VOTNoVideoIDFound"); + } + + await this.translateExecutor(this.videoData.videoId); + } catch (err) { + console.error("[VOT]", err); + if (err?.name === "VOTLocalizedError") { + this.transformBtn("error", err.localizedMessage); + } else { + this.transformBtn("error", err); + } } - } + })(); }); - this.votButton.pipButton.addEventListener("click", async () => { - if (this.video !== document.pictureInPictureElement) { - await this.video.requestPictureInPicture(); - } else { - await document.exitPictureInPicture(); - } + this.votButton.pipButton.addEventListener("click", () => { + (async () => { + if (this.video !== document.pictureInPictureElement) { + await this.video.requestPictureInPicture(); + } else { + await document.exitPictureInPicture(); + } + })(); }); this.votButton.menuButton.addEventListener("click", () => { @@ -4787,9 +5022,8 @@ class VideoHandler { this.votSettingsButton.addEventListener("click", () => { this.votSettingsDialog.container.hidden = !this.votSettingsDialog.container.hidden; - if (document.fullscreen === undefined || document.fullscreen) { + if (document.fullscreenElement || document.webkitFullscreenElement) { document.webkitExitFullscreen && document.webkitExitFullscreen(); - document.mozCancelFullscreen && document.mozCancelFullscreen(); document.exitFullscreen && document.exitFullscreen(); } }); @@ -4823,128 +5057,139 @@ class VideoHandler { this.votVideoTranslationVolumeSlider.input.addEventListener( "input", - async (e) => { - this.data.defaultVolume = Number(e.target.value); - await storage/* votStorage */.i.set("defaultVolume", this.data.defaultVolume); - this.votVideoTranslationVolumeSlider.label.querySelector( - "strong", - ).innerHTML = `${this.data.defaultVolume}%`; - this.audio.volume = this.data.defaultVolume / 100; - if (this.data.syncVolume === 1) { - this.syncTranslationWithVideo(this.data.defaultVolume); - } + (e) => { + (async () => { + this.data.defaultVolume = Number(e.target.value); + await votStorage.set("defaultVolume", this.data.defaultVolume); + this.votVideoTranslationVolumeSlider.label.querySelector( + "strong", + ).innerHTML = `${this.data.defaultVolume}%`; + this.audio.volume = this.data.defaultVolume / 100; + if (this.data.syncVolume === 1) { + this.syncTranslationWithVideo(this.data.defaultVolume); + } + })(); }, ); } // VOT Settings { - this.votAutoTranslateCheckbox.input.addEventListener( - "change", - async (e) => { + this.votAutoTranslateCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.autoTranslate = Number(e.target.checked); - await storage/* votStorage */.i.set("autoTranslate", this.data.autoTranslate); - debug/* default */.Z.log( + await votStorage.set("autoTranslate", this.data.autoTranslate); + debug/* default */.A.log( "autoTranslate value changed. New value: ", this.data.autoTranslate, ); - }, - ); + })(); + }); this.votDontTranslateYourLangSelect.labelElement.addEventListener( "change", - async (e) => { - this.data.dontTranslateYourLang = Number(e.target.checked); - await storage/* votStorage */.i.set( - "dontTranslateYourLang", - this.data.dontTranslateYourLang, - ); - debug/* default */.Z.log( - "dontTranslateYourLang value changed. New value: ", - this.data.dontTranslateYourLang, - ); + (e) => { + (async () => { + this.data.dontTranslateYourLang = Number(e.target.checked); + await votStorage.set( + "dontTranslateYourLang", + this.data.dontTranslateYourLang, + ); + debug/* default */.A.log( + "dontTranslateYourLang value changed. New value: ", + this.data.dontTranslateYourLang, + ); + })(); }, ); - this.votAutoSetVolumeCheckbox.input.addEventListener( - "change", - async (e) => { + this.votAutoSetVolumeCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.autoSetVolumeYandexStyle = Number(e.target.checked); - await storage/* votStorage */.i.set( + await votStorage.set( "autoSetVolumeYandexStyle", this.data.autoSetVolumeYandexStyle, ); - debug/* default */.Z.log( + debug/* default */.A.log( "autoSetVolumeYandexStyle value changed. New value: ", this.data.autoSetVolumeYandexStyle, ); - }, - ); + })(); + }); - this.votAutoSetVolumeSlider.input.addEventListener("input", async (e) => { - const presetAutoVolume = Number(e.target.value); - this.data.autoVolume = presetAutoVolume / 100; - await storage/* votStorage */.i.set("autoVolume", presetAutoVolume); - this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML = - `${presetAutoVolume}%`; + this.votAutoSetVolumeSlider.input.addEventListener("input", (e) => { + (async () => { + const presetAutoVolume = Number(e.target.value); + this.data.autoVolume = (presetAutoVolume / 100).toFixed(2); + await votStorage.set("autoVolume", this.data.autoVolume); + this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML = + `${presetAutoVolume}%`; + })(); }); - this.votShowVideoSliderCheckbox.input.addEventListener( - "change", - async (e) => { + this.votShowVideoSliderCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.showVideoSlider = Number(e.target.checked); - await storage/* votStorage */.i.set("showVideoSlider", this.data.showVideoSlider); - debug/* default */.Z.log( + await votStorage.set("showVideoSlider", this.data.showVideoSlider); + debug/* default */.A.log( "showVideoSlider value changed. New value: ", this.data.showVideoSlider, ); this.votVideoVolumeSlider.container.hidden = this.data.showVideoSlider !== 1 || this.votButton.container.dataset.status !== "success"; - }, - ); + })(); + }); - this.votUdemyDataTextfield.input.addEventListener("change", async (e) => { - this.data.udemyData = { - accessToken: e.target.value, - expires: new Date().getTime(), - }; - await storage/* votStorage */.i.set("udemyData", this.data.udemyData); - debug/* default */.Z.log("udemyData value changed. New value: ", this.data.udemyData); - window.location.reload(); + this.votUdemyDataTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.udemyData = { + accessToken: e.target.value, + expires: new Date().getTime(), + }; + await votStorage.set("udemyData", this.data.udemyData); + debug/* default */.A.log( + "udemyData value changed. New value: ", + this.data.udemyData, + ); + window.location.reload(); + })(); }); - this.votSyncVolumeCheckbox.input.addEventListener("change", async (e) => { - this.data.syncVolume = Number(e.target.checked); - await storage/* votStorage */.i.set("syncVolume", this.data.syncVolume); - debug/* default */.Z.log( - "syncVolume value changed. New value: ", - this.data.syncVolume, - ); + this.votSyncVolumeCheckbox.input.addEventListener("change", (e) => { + (async () => { + this.data.syncVolume = Number(e.target.checked); + await votStorage.set("syncVolume", this.data.syncVolume); + debug/* default */.A.log( + "syncVolume value changed. New value: ", + this.data.syncVolume, + ); + })(); }); this.votTranslationServiceSelect.labelElement.addEventListener( "change", - async (e) => { - this.data.translateAPIErrors = Number(e.target.checked); - await storage/* votStorage */.i.set( - "translateAPIErrors", - this.data.translateAPIErrors, - ); - debug/* default */.Z.log( - "translateAPIErrors value changed. New value: ", - this.data.translateAPIErrors, - ); + (e) => { + (async () => { + this.data.translateAPIErrors = Number(e.target.checked); + await votStorage.set( + "translateAPIErrors", + this.data.translateAPIErrors, + ); + debug/* default */.A.log( + "translateAPIErrors value changed. New value: ", + this.data.translateAPIErrors, + ); + })(); }, ); // SUBTITLES - this.votSubtitlesMaxLengthSlider.input.addEventListener( - "input", - async (e) => { + this.votSubtitlesMaxLengthSlider.input.addEventListener("input", (e) => { + (async () => { this.data.subtitlesMaxLength = Number(e.target.value); - await storage/* votStorage */.i.set( + await votStorage.set( "subtitlesMaxLength", this.data.subtitlesMaxLength, ); @@ -4952,81 +5197,84 @@ class VideoHandler { "strong", ).innerHTML = `${this.data.subtitlesMaxLength}`; this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength); - }, - ); + })(); + }); this.votSubtitlesHighlightWordsCheckbox.input.addEventListener( "change", - async (e) => { - this.data.highlightWords = Number(e.target.checked); - await storage/* votStorage */.i.set("highlightWords", this.data.highlightWords); - debug/* default */.Z.log( - "highlightWords value changed. New value: ", - this.data.highlightWords, - ); - this.subtitlesWidget.setHighlightWords(this.data.highlightWords); + (e) => { + (async () => { + this.data.highlightWords = Number(e.target.checked); + await votStorage.set("highlightWords", this.data.highlightWords); + debug/* default */.A.log( + "highlightWords value changed. New value: ", + this.data.highlightWords, + ); + this.subtitlesWidget.setHighlightWords(this.data.highlightWords); + })(); }, ); - this.votShowPiPButtonCheckbox.input.addEventListener( - "change", - async (e) => { + this.votShowPiPButtonCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.showPiPButton = Number(e.target.checked); - await storage/* votStorage */.i.set("showPiPButton", this.data.showPiPButton); - debug/* default */.Z.log( + await votStorage.set("showPiPButton", this.data.showPiPButton); + debug/* default */.A.log( "showPiPButton value changed. New value: ", this.data.showPiPButton, ); this.votButton.pipButton.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data.showPiPButton; + !isPiPAvailable() || !this.data.showPiPButton; this.votButton.separator2.hidden = - !(0,utils/* isPiPAvailable */.qq)() || !this.data.showPiPButton; - }, - ); + !isPiPAvailable() || !this.data.showPiPButton; + })(); + }); // PROXY - this.votM3u8ProxyHostTextfield.input.addEventListener( - "change", - async (e) => { - this.data.m3u8ProxyHost = e.target.value || config/* m3u8ProxyHost */.e6; - await storage/* votStorage */.i.set("m3u8ProxyHost", this.data.m3u8ProxyHost); - debug/* default */.Z.log( + this.votM3u8ProxyHostTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.m3u8ProxyHost = e.target.value || config/* m3u8ProxyHost */.se; + await votStorage.set("m3u8ProxyHost", this.data.m3u8ProxyHost); + debug/* default */.A.log( "m3u8ProxyHost value changed. New value: ", this.data.m3u8ProxyHost, ); - }, - ); + })(); + }); - this.votProxyWorkerHostTextfield.input.addEventListener( - "change", - async (e) => { - this.data.proxyWorkerHost = e.target.value || config/* proxyWorkerHost */.ez; - await storage/* votStorage */.i.set("proxyWorkerHost", this.data.proxyWorkerHost); - debug/* default */.Z.log( + this.votProxyWorkerHostTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.proxyWorkerHost = e.target.value || config/* proxyWorkerHost */.Pm; + await votStorage.set("proxyWorkerHost", this.data.proxyWorkerHost); + debug/* default */.A.log( "proxyWorkerHost value changed. New value: ", this.data.proxyWorkerHost, ); window.location.reload(); - }, - ); + })(); + }); - this.votAudioProxyCheckbox.input.addEventListener("change", async (e) => { - this.data.audioProxy = Number(e.target.checked); - await storage/* votStorage */.i.set("audioProxy", this.data.audioProxy); - debug/* default */.Z.log( - "audioProxy value changed. New value: ", - this.data.audioProxy, - ); + this.votAudioProxyCheckbox.input.addEventListener("change", (e) => { + (async () => { + this.data.audioProxy = Number(e.target.checked); + await votStorage.set("audioProxy", this.data.audioProxy); + debug/* default */.A.log( + "audioProxy value changed. New value: ", + this.data.audioProxy, + ); + })(); }); - this.votResetSettingsButton.addEventListener("click", async () => { - localizationProvider/* localizationProvider */.V.reset(); - const valuesForClear = await storage/* votStorage */.i.list(); - valuesForClear - .filter((v) => !localizationProvider/* localizationProvider */.V.gmValues.includes(v)) - .forEach((v) => storage/* votStorage */.i.syncDelete(v)); - window.location.reload(); + this.votResetSettingsButton.addEventListener("click", () => { + (async () => { + localizationProvider.reset(); + const valuesForClear = await votStorage.list(); + valuesForClear + .filter((v) => !localizationProvider.gmValues.includes(v)) + .forEach((v) => votStorage.syncDelete(v)); + window.location.reload(); + })(); }); } } @@ -5034,7 +5282,10 @@ class VideoHandler { releaseExtraEvents() { clearInterval(this.resizeInterval); this.resizeObserver?.disconnect(); - if (this.site.host === "youtube" && this.site.additionalData !== "mobile") { + if ( + ["youtube", "googledrive"].includes(this.site.host) && + this.site.additionalData !== "mobile" + ) { this.syncVolumeObserver?.disconnect(); } @@ -5083,7 +5334,10 @@ class VideoHandler { ); }, 500); // Sync volume slider with original video (youtube only) - if (this.site.host === "youtube" && this.site.additionalData !== "mobile") { + if ( + ["youtube", "googledrive"].includes(this.site.host) && + this.site.additionalData !== "mobile" + ) { this.syncVolumeObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if ( @@ -5121,7 +5375,7 @@ class VideoHandler { const isSettings = settings.contains(e); const isTempDialog = tempDialog?.contains(e) ?? false; - debug/* default */.Z.log( + debug/* default */.A.log( `[document click] ${isButton} ${isMenu} ${isVideo} ${isSettings} ${isTempDialog}`, ); if (!(!isButton && !isMenu && !isSettings && !isTempDialog)) return; @@ -5183,25 +5437,26 @@ class VideoHandler { this.container.draggable = false; } - addExtraEventListener(this.video, "abort", () => { - debug/* default */.Z.log("lipsync mode is abort"); + addExtraEventListener(this.video, "emptied", () => { + debug/* default */.A.log("lipsync mode is emptied"); this.stopTranslation(); - this.videoData = ""; }); addExtraEventListener(this.video, "progress", async () => { - if (!(this.firstPlay && this.data.autoTranslate === 1)) { + if ( + !(this.firstPlay && this.data.autoTranslate === 1) || + getVideoId(this.site.host, this.video) !== this.videoData.videoId + ) { return; } - const VIDEO_ID = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); - if (!VIDEO_ID) { + if (!this.videoData.videoId) { throw new VOTLocalizedError("VOTNoVideoIDFound"); } try { - await this.translateExecutor(VIDEO_ID); this.firstPlay = false; + await this.translateExecutor(this.videoData.videoId); } catch (err) { console.error("[VOT]", err); if (err?.name === "VOTLocalizedError") { @@ -5224,7 +5479,7 @@ class VideoHandler { this.logout(1); this.timer = setTimeout(() => { this.logout(0); - }, 2000); + }, 1000); } changeOpacityOnEvent(event) { @@ -5234,11 +5489,11 @@ class VideoHandler { } async changeSubtitlesLang(subs) { - debug/* default */.Z.log("[onchange] subtitles", subs); + debug/* default */.A.log("[onchange] subtitles", subs); this.votSubtitlesSelect.setSelected(subs); if (subs === "disabled") { this.votSubtitlesSelect.setTitle( - localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), + localizationProvider.get("VOTSubtitlesDisabled"), ); this.subtitlesWidget.setContent(null); this.votDownloadSubtitlesButton.hidden = true; @@ -5256,24 +5511,24 @@ class VideoHandler { async updateSubtitlesLangSelect() { const updatedOptions = [ { - label: localizationProvider/* localizationProvider */.V.get("VOTSubtitlesDisabled"), + label: localizationProvider.get("VOTSubtitlesDisabled"), value: "disabled", selected: true, disabled: false, }, ...this.subtitlesList.map((s, idx) => ({ label: - (localizationProvider/* localizationProvider */.V.get("langs")[s.language] ?? + (localizationProvider.get("langs")[s.language] ?? s.language.toUpperCase()) + (s.translatedFromLanguage - ? ` ${localizationProvider/* localizationProvider */.V.get("VOTTranslatedFrom")} ${ - localizationProvider/* localizationProvider */.V.get("langs")[s.translatedFromLanguage] ?? + ? ` ${localizationProvider.get("VOTTranslatedFrom")} ${ + localizationProvider.get("langs")[s.translatedFromLanguage] ?? s.translatedFromLanguage.toUpperCase() }` : "") + (s.source !== "yandex" ? ` ${s.source}` : "") + (s.isAutoGenerated - ? ` (${localizationProvider/* localizationProvider */.V.get("VOTAutogenerated")})` + ? ` (${localizationProvider.get("VOTAutogenerated")})` : ""), value: idx, selected: false, @@ -5289,11 +5544,9 @@ class VideoHandler { async updateSubtitles() { await this.changeSubtitlesLang("disabled"); - const VIDEO_ID = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); - - if (!VIDEO_ID) { + if (!this.videoData.videoId) { console.error( - `[VOT] ${localizationProvider/* localizationProvider */.V.getDefault("VOTNoVideoIDFound")}`, + `[VOT] ${localizationProvider.getDefault("VOTNoVideoIDFound")}`, ); this.subtitlesList = []; this.subtitlesListVideoId = null; @@ -5301,27 +5554,19 @@ class VideoHandler { return; } - if (this.subtitlesListVideoId === VIDEO_ID) { + if (this.subtitlesListVideoId === this.videoData.videoId) { return; } - if (!this.videoData.detectedLanguage) { - this.videoData = await this.getVideoData(); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.videoData.responseLanguage, - ); - } - this.subtitlesList = await subtitles_getSubtitles( this.site, - VIDEO_ID, + this.videoData.videoId, this.videoData.detectedLanguage, ); if (!this.subtitlesList) { await this.changeSubtitlesLang("disabled"); } else { - this.subtitlesListVideoId = VIDEO_ID; + this.subtitlesListVideoId = this.videoData.videoId; } await this.updateSubtitlesLangSelect(); } @@ -5329,7 +5574,7 @@ class VideoHandler { // Get video volume in 0.00-1.00 format getVideoVolume() { let videoVolume = this.video?.volume; - if (this.site.host === "youtube") { + if (["youtube", "googledrive"].includes(this.site.host)) { videoVolume = youtubeUtils.getVideoVolume() || videoVolume; } return videoVolume; @@ -5337,7 +5582,7 @@ class VideoHandler { // Set video volume in 0.00-1.00 format setVideoVolume(volume) { - if (this.site.host === "youtube") { + if (["youtube", "googledrive"].includes(this.site.host)) { const videoVolume = youtubeUtils.setVideoVolume(volume); if (videoVolume) { return; @@ -5362,10 +5607,10 @@ class VideoHandler { setSelectMenuValues(from, to) { this.votTranslationLanguageSelect.fromSelect.setTitle( - localizationProvider/* localizationProvider */.V.get("langs")[from], + localizationProvider.get("langs")[from], ); this.votTranslationLanguageSelect.toSelect.setTitle( - localizationProvider/* localizationProvider */.V.get("langs")[to], + localizationProvider.get("langs")[to], ); this.votTranslationLanguageSelect.fromSelect.setSelected(from); this.votTranslationLanguageSelect.toSelect.setSelected(to); @@ -5399,17 +5644,16 @@ class VideoHandler { } async getVideoData() { - const videoData = {}; - - // ! should be null for ALL websites except coursera and udemy ! - // else use direct link: `{url: xxx.mp4}` - videoData.translationHelp = null; - - videoData.isStream = false; // by default, we request the translation of the video - videoData.duration = this.video?.duration || 343; // ! if 0 - we get 400 error - videoData.videoId = (0,utils/* getVideoId */.gJ)(this.site.host, this.video); - videoData.detectedLanguage = this.translateFromLang; - videoData.responseLanguage = this.translateToLang; + const videoData = { + // ! should be null for ALL websites except coursera and udemy ! + // else use direct link: `{url: xxx.mp4}` + translationHelp: null, + isStream: false, // by default, we request the translation of the video + duration: this.video?.duration || 343, // ! if 0 - we get 400 error + videoId: getVideoId(this.site.host, this.video), + detectedLanguage: this.translateFromLang, + responseLanguage: this.translateToLang, + }; if (!videoData.videoId) { this.ytData = {}; @@ -5425,11 +5669,15 @@ class VideoHandler { } } else if ( window.location.hostname.includes("rutube") || + window.location.hostname.includes("ok.ru") || window.location.hostname.includes("my.mail.ru") ) { videoData.detectedLanguage = "ru"; - } else if (window.location.hostname.includes("bilibili.com")) { + } else if (["bilibili", "youku"].includes(this.site.host)) { videoData.detectedLanguage = "zh"; + } else if (["vk"].includes(this.site.host)) { + const trackLang = document.getElementsByTagName("track")?.[0]?.srclang; + videoData.detectedLanguage = trackLang || "auto"; } else if (window.location.hostname.includes("coursera.org")) { const courseraData = await courseraUtils.getVideoData( this.translateToLang, @@ -5444,6 +5692,25 @@ class VideoHandler { url: coursehunterData.url, }; videoData.duration = coursehunterData.duration || videoData.duration; + } else if (window.location.hostname.includes("banned.video")) { + const bannedvideoData = await bannedvideoUtils.getVideoData( + videoData.videoId, + ); + videoData.translationHelp = { + url: bannedvideoData.url, + }; + + videoData.duration = bannedvideoData.duration || videoData.duration; + videoData.isStream = bannedvideoData.live; + } else if (window.location.hostname.includes("weverse.io")) { + const weverseData = await weverseUtils.getVideoData(); + videoData.detectedLanguage = "ko"; + if (weverseData) { + videoData.translationHelp = { + url: weverseData.url, + }; + videoData.duration = weverseData.duration || videoData.duration; + } } else if (window.location.hostname.includes("udemy.com")) { const udemyData = await udemyUtils.getVideoData( this.data.udemyData, @@ -5453,25 +5720,25 @@ class VideoHandler { videoData.detectedLanguage = udemyData.detectedLanguage; videoData.translationHelp = udemyData.translationHelp; } else if ( - this.site.host === "vk" || - this.site.host === "piped" || - this.site.host === "invidious" || - this.site.host === "bitchute" || - this.site.host === "rumble" || - this.site.host === "peertube" || - this.site.host === "dailymotion" || - this.site.host === "trovo" || - this.site.host === "yandexdisk" || - this.site.host === "coursehunter" + [ + "piped", + "invidious", + "bitchute", + "rumble", + "peertube", + "dailymotion", + "trovo", + "yandexdisk", + "coursehunter", + ].includes(this.site.host) ) { videoData.detectedLanguage = "auto"; } return videoData; } - videoValidator() { - if (this.site.host === "youtube") { - debug/* default */.Z.log("VideoValidator videoData: ", this.videoData); + if (["youtube", "ok.ru", "vk"].includes(this.site.host)) { + debug/* default */.A.log("VideoValidator videoData: ", this.videoData); if ( this.data.dontTranslateYourLang === 1 && this.videoData.detectedLanguage === this.data.dontTranslateLanguage && @@ -5485,7 +5752,7 @@ class VideoHandler { // if (this.ytData.isLive) { // throw new VOTLocalizedError("VOTLiveNotSupported"); // } - if (this.videoData.duration > 14_400) { + if (!this.videoData.isStream && this.videoData.duration > 14_400) { throw new VOTLocalizedError("VOTVideoIsTooLong"); } } @@ -5493,7 +5760,7 @@ class VideoHandler { } lipSync(mode = false) { - debug/* default */.Z.log("lipsync video", this.video); + debug/* default */.A.log("lipsync video", this.video); if (!this.video) { return; } @@ -5501,12 +5768,12 @@ class VideoHandler { this.audio.playbackRate = this.video.playbackRate; if (!mode) { - debug/* default */.Z.log("lipsync mode is not set"); + debug/* default */.A.log("lipsync mode is not set"); return; } - if (mode === "play") { - debug/* default */.Z.log("lipsync mode is play"); + if (mode == "play") { + debug/* default */.A.log("lipsync mode is play"); const audioPromise = this.audio.play(); if (audioPromise !== undefined) { audioPromise.catch((e) => { @@ -5514,15 +5781,15 @@ class VideoHandler { if (e.name === "NotAllowedError") { this.transformBtn( "error", - localizationProvider/* localizationProvider */.V.get("grantPermissionToAutoPlay"), + localizationProvider.get("grantPermissionToAutoPlay"), ); throw new VOTLocalizedError("grantPermissionToAutoPlay"); } else if (e.name === "NotSupportedError") { this.transformBtn( "error", sitesChromiumBlocked.includes(window.location.hostname) - ? localizationProvider/* localizationProvider */.V.get("neededAdditionalExtension") - : localizationProvider/* localizationProvider */.V.get("audioFormatNotSupported"), + ? localizationProvider.get("neededAdditionalExtension") + : localizationProvider.get("audioFormatNotSupported"), ); throw sitesChromiumBlocked.includes(window.location.hostname) ? new VOTLocalizedError("neededAdditionalExtension") @@ -5532,69 +5799,49 @@ class VideoHandler { } return; } - if (mode === "pause") { - debug/* default */.Z.log("lipsync mode is pause"); - this.audio.pause(); - } - if (mode === "stop") { - debug/* default */.Z.log("lipsync mode is stop"); - this.audio.pause(); - } - if (mode === "waiting") { - debug/* default */.Z.log("lipsync mode is waiting"); + // video is inactive + if (["pause", "stop", "waiting"].includes(mode)) { + debug/* default */.A.log(`lipsync mode is ${mode}`); this.audio.pause(); } - if (mode === "playing") { - debug/* default */.Z.log("lipsync mode is playing"); + + if (mode == "playing") { + debug/* default */.A.log("lipsync mode is playing"); this.audio.play(); } } // Define a function to handle common events handleVideoEvent(event) { - debug/* default */.Z.log(`video ${event.type}`); + debug/* default */.A.log(`video ${event.type}`); this.lipSync(event.type); } // Default actions on stop translate - stopTraslate() { + stopTranslate() { videoLipSyncEvents.forEach((e) => this.video.removeEventListener(e, this.handleVideoEventBound), ); this.audio.pause(); - //! video.removeEventListener(".translate", stopTraslate, false); // why??? this.audio.src = ""; this.audio.removeAttribute("src"); this.votVideoVolumeSlider.container.hidden = true; this.votVideoTranslationVolumeSlider.container.hidden = true; this.votDownloadButton.hidden = true; this.downloadTranslationUrl = null; - this.transformBtn("none", localizationProvider/* localizationProvider */.V.get("translateVideo")); + this.transformBtn("none", localizationProvider.get("translateVideo")); + debug/* default */.A.log(`Volume on start: ${this.volumeOnStart}`); if (this.volumeOnStart) { - debug/* default */.Z.log(`Volume on start: ${this.volumeOnStart}`); - if (this.site.host === "youtube") { - youtubeUtils.setVideoVolume(this.volumeOnStart); - } else { - this.video.volume = this.volumeOnStart; - } + this.setVideoVolume(this.volumeOnStart); } + this.volumeOnStart = ""; clearInterval(this.streamPing); this.hls?.destroy(); - this.hls = (0,utils/* initHls */.QZ)(); + this.hls = initHls(); } async translateExecutor(VIDEO_ID) { - if (!this.videoData.detectedLanguage) { - this.videoData = await this.getVideoData(); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.videoData.responseLanguage, - ); - } - debug/* default */.Z.log("Run videoValidator"); - this.videoValidator(); - - debug/* default */.Z.log("Run translateFunc"); + debug/* default */.A.log("Run translateFunc"); this.translateFunc( VIDEO_ID, this.videoData.isStream, @@ -5604,6 +5851,84 @@ class VideoHandler { ); } + async updateTranslationErrorMsg(errorMessage) { + const translationTake = localizationProvider.get("translationTake"); + const VOTTranslatingError = localizationProvider.get("VOTTranslatingError"); + const lang = localizationProvider.lang; + + if (errorMessage?.name === "VOTLocalizedError") { + this.transformBtn("error", errorMessage.localizedMessage); + } else if ( + this.data.translateAPIErrors === 1 && + !errorMessage.includes(translationTake) && + lang !== "ru" + ) { + const translatedMessage = await translate(errorMessage, "ru", lang); + this.transformBtn("error", VOTTranslatingError); + this.transformBtn("error", translatedMessage); + } else { + this.transformBtn("error", errorMessage); + } + } + + afterUpdateTranslation(audioUrl) { + this.votVideoVolumeSlider.container.hidden = + this.data.showVideoSlider !== 1 || + this.votButton.container.dataset.status !== "success"; + this.votVideoTranslationVolumeSlider.container.hidden = + this.votButton.container.dataset.status !== "success"; + + if (this.data.autoSetVolumeYandexStyle === 1) { + this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; + this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = + `${this.data.autoVolume * 100}%`; + ui.updateSlider(this.votVideoVolumeSlider.input); + } + + this.votDownloadButton.hidden = false; + this.downloadTranslationUrl = audioUrl; + } + + // update translation audio src + updateTranslation(audioUrl) { + // ! Don't use this function for streams + this.audio.src = audioUrl; + + // cf version only + if ( + false + ) {} + + this.volumeOnStart = this.getVideoVolume(); + if (typeof this.data.defaultVolume === "number") { + this.audio.volume = this.data.defaultVolume / 100; + } + if ( + typeof this.data.autoSetVolumeYandexStyle === "number" && + this.data.autoSetVolumeYandexStyle + ) { + this.setVideoVolume(this.data.autoVolume); + } + + switch (this.site.host) { + case "twitter": + document + .querySelector('div[data-testid="app-bar-back"][role="button"]') + .addEventListener("click", this.stopTranslationBound); + break; + case "invidious": + case "piped": + break; + } + + if (this.video && !this.video.paused) this.lipSync("play"); + videoLipSyncEvents.forEach((e) => + this.video.addEventListener(e, this.handleVideoEventBound), + ); + this.transformBtn("success", localizationProvider.get("disableTranslate")); + this.afterUpdateTranslation(audioUrl); + } + // Define a function to translate a video and handle the callback translateFunc( VIDEO_ID, @@ -5618,42 +5943,20 @@ class VideoHandler { : `${this.site.url}${VIDEO_ID}`; // fix enabling the old requested voiceover when changing the language to the native language (#) + debug/* default */.A.log("Run videoValidator"); this.videoValidator(); if (isStream) { - debug/* default */.Z.log("Executed stream translation"); - // if (BUILD_MODE === "cloudflare") { - // // Temporarily stream translation is only available in the main version - // throw new VOTLocalizedError("VOTCloudflareDoesntSupportStreams"); - // } - + debug/* default */.A.log("Executed stream translation"); translateStream( videoURL, requestLang, responseLang, async (success, reqInterval, resOrError) => { - debug/* default */.Z.log("[exec callback] translateStream callback"); - if ((0,utils/* getVideoId */.gJ)(this.site.host, this.video) !== VIDEO_ID) return; + debug/* default */.A.log("[exec callback] translateStream callback"); + if (getVideoId(this.site.host, this.video) !== VIDEO_ID) return; if (!success || !resOrError.translatedInfo) { - if (resOrError?.name === "VOTLocalizedError") { - this.transformBtn("error", resOrError.localizedMessage); - } else { - if ( - this.data.translateAPIErrors === 1 && - localizationProvider/* localizationProvider */.V.lang !== "ru" - ) { - this.transformBtn( - "error", - `${localizationProvider/* localizationProvider */.V.get("VOTTranslatingError")}...`, - ); - this.transformBtn( - "error", - await translate(resOrError, "ru", localizationProvider/* localizationProvider */.V.lang), - ); - } else { - this.transformBtn("error", resOrError); - } - } + await this.updateTranslationErrorMsg(resOrError); if (reqInterval === 10) { // if wait translating @@ -5676,22 +5979,22 @@ class VideoHandler { this.transformBtn( "success", - localizationProvider/* localizationProvider */.V.get("disableTranslate"), + localizationProvider.get("disableTranslate"), ); console.log(resOrError); const pingId = resOrError.pingId; - debug/* default */.Z.log(`Stream pingId: ${pingId}`); + debug/* default */.A.log(`Stream pingId: ${pingId}`); // if you don't make ping requests, then the translation of the stream dies this.streamPing = setInterval( async () => await rsp(pingId, (result) => - debug/* default */.Z.log("Stream ping result: ", result), + debug/* default */.A.log("Stream ping result: ", result), ), reqInterval * 1000, ); - debug/* default */.Z.log(resOrError.translatedInfo.url); + debug/* default */.A.log(resOrError.translatedInfo.url); const streamURL = `https://${ this.data.m3u8ProxyHost }/?all=yes&origin=${encodeURIComponent( @@ -5699,22 +6002,22 @@ class VideoHandler { )}&referer=${encodeURIComponent( "https://strm.yandex.ru", )}&url=${encodeURIComponent(resOrError.translatedInfo.url)}`; - debug/* default */.Z.log(streamURL); + debug/* default */.A.log(streamURL); if (this.hls) { this.hls.on(Hls.Events.MEDIA_ATTACHED, function () { - debug/* default */.Z.log("audio and hls.js are now bound together !"); + debug/* default */.A.log("audio and hls.js are now bound together !"); }); - this.hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { - debug/* default */.Z.log( + this.hls.on(Hls.Events.MANIFEST_PARSED, function (data) { + debug/* default */.A.log( "manifest loaded, found " + - data.levels.length + + data?.levels?.length + " quality level", ); }); this.hls.loadSource(streamURL); this.hls.attachMedia(this.audio); - this.hls.on(Hls.Events.ERROR, function (event, data) { + this.hls.on(Hls.Events.ERROR, function (data) { if (data.fatal) { switch (data.type) { case Hls.ErrorTypes.MEDIA_ERROR: @@ -5737,7 +6040,7 @@ class VideoHandler { } } }); - debug/* default */.Z.log(this.hls); + debug/* default */.A.log(this.hls); } else if (this.audio.canPlayType("application/vnd.apple.mpegurl")) { // safari this.audio.src = streamURL; @@ -5746,7 +6049,9 @@ class VideoHandler { throw new VOTLocalizedError("audioFormatNotSupported"); } - youtubeUtils.videoSeek(this.video, 10); // 10 is the most successful number for streaming. With it, the audio is not so far behind the original + if (this.site.host === "youtube") { + youtubeUtils.videoSeek(this.video, 10); // 10 is the most successful number for streaming. With it, the audio is not so far behind the original + } this.volumeOnStart = this.getVideoVolume(); if (typeof this.data.defaultVolume === "number") { @@ -5774,21 +6079,7 @@ class VideoHandler { this.video.addEventListener(e, this.handleVideoEventBound), ); - this.votVideoVolumeSlider.container.hidden = - this.data.showVideoSlider !== 1 || - this.votButton.container.dataset.status !== "success"; - this.votVideoTranslationVolumeSlider.container.hidden = - this.votButton.container.dataset.status !== "success"; - - if (this.data.autoSetVolumeYandexStyle === 1) { - this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; - this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = - `${this.data.autoVolume * 100}%`; - ui.updateSlider(this.votVideoVolumeSlider.input); - } - - this.votDownloadButton.hidden = false; - this.downloadTranslationUrl = streamURL; + this.afterUpdateTranslation(streamURL); }, ); @@ -5799,6 +6090,20 @@ class VideoHandler { throw new VOTLocalizedError("VOTTranslationHelpNull"); } + const cachedTranslation = this.videoTranslations.find( + (t) => + t.videoId === VIDEO_ID && + t.expires > Date.now() / 1000 && + t.from === requestLang && + t.to === responseLang, + ); + + if (cachedTranslation) { + this.updateTranslation(cachedTranslation.url); + debug/* default */.A.log("[translateFunc] A cached translate was received"); + return; + } + translateVideo( videoURL, this.videoData.duration, @@ -5806,34 +6111,14 @@ class VideoHandler { responseLang, translationHelp, async (success, urlOrError) => { - debug/* default */.Z.log("[exec callback] translateVideo callback"); - if ((0,utils/* getVideoId */.gJ)(this.site.host, this.video) !== VIDEO_ID) return; + debug/* default */.A.log("[exec callback] translateVideo callback"); + if (getVideoId(this.site.host, this.video) !== VIDEO_ID) return; if (!success) { - if (urlOrError?.name === "VOTLocalizedError") { - this.transformBtn("error", urlOrError.localizedMessage); - } else { - if ( - this.data.translateAPIErrors === 1 && - !urlOrError.includes( - localizationProvider/* localizationProvider */.V.get("translationTake"), - ) && - localizationProvider/* localizationProvider */.V.lang !== "ru" - ) { - this.transformBtn( - "error", - localizationProvider/* localizationProvider */.V.get("VOTTranslatingError"), - ); - this.transformBtn( - "error", - await translate(urlOrError, "ru", localizationProvider/* localizationProvider */.V.lang), - ); - } else { - this.transformBtn("error", urlOrError); - } - } + await this.updateTranslationErrorMsg(urlOrError); + // if the error line contains information that the translation is being performed, then we wait if ( - urlOrError.includes(localizationProvider/* localizationProvider */.V.get("translationTake")) + urlOrError.includes(localizationProvider.get("translationTake")) ) { clearTimeout(this.autoRetry); this.autoRetry = setTimeout( @@ -5852,146 +6137,40 @@ class VideoHandler { return; } - this.audio.src = urlOrError; - - // cf version only - if ( - false - ) {} - - this.volumeOnStart = this.getVideoVolume(); - if (typeof this.data.defaultVolume === "number") { - this.audio.volume = this.data.defaultVolume / 100; - } - if ( - typeof this.data.autoSetVolumeYandexStyle === "number" && - this.data.autoSetVolumeYandexStyle - ) { - this.setVideoVolume(this.data.autoVolume); - } - - switch (this.site.host) { - case "twitter": - document - .querySelector('div[data-testid="app-bar-back"][role="button"]') - .addEventListener("click", this.stopTranslationBound); - break; - case "invidious": - case "piped": - break; - } - - if ( - !this.video.src && - !this.video.currentSrc && - !this.video.srcObject - ) { - this.stopTranslation(); - return; - } - - const siteHostnames = [ - "twitch", - "vimeo", - "facebook", - "rutube", - "twitter", - "bilibili", - "mail_ru", - "rumble", - "eporner", - ]; - for (let i = 0; i < siteHostnames.length; i++) { - if (this.site.host === siteHostnames[i]) { - const mutationObserver = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if ( - mutation.type === "attributes" && - mutation.attributeName === "src" && - mutation.target === this.video && - mutation.target.src !== "" - ) { - this.stopTranslation(); - this.firstPlay = true; - } - }); - }); - mutationObserver.observe(this.container, { - attributes: true, - childList: false, - subtree: true, - attributeOldValue: true, - }); - break; - } - } - - if (this.video && !this.video.paused) this.lipSync("play"); - videoLipSyncEvents.forEach((e) => - this.video.addEventListener(e, this.handleVideoEventBound), - ); - this.transformBtn( - "success", - localizationProvider/* localizationProvider */.V.get("disableTranslate"), - ); - - this.votVideoVolumeSlider.container.hidden = - this.data.showVideoSlider !== 1 || - this.votButton.container.dataset.status !== "success"; - this.votVideoTranslationVolumeSlider.container.hidden = - this.votButton.container.dataset.status !== "success"; - - if (this.data.autoSetVolumeYandexStyle === 1) { - this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; - this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = - `${this.data.autoVolume * 100}%`; - ui.updateSlider(this.votVideoVolumeSlider.input); - } + this.updateTranslation(urlOrError); - this.votDownloadButton.hidden = false; - this.downloadTranslationUrl = urlOrError; + this.videoTranslations.push({ + videoId: VIDEO_ID, + from: requestLang, + to: responseLang, + url: urlOrError, + expires: Date.now() / 1000 + this.videoTranslationTTL, + }); }, ); } // Define a function to stop translation and clean up stopTranslation() { - this.stopTraslate(); + this.stopTranslate(); this.syncVideoVolumeSlider(); } - async waitInitialization() { - let resolved = false; - return await Promise.race([ - new Promise(async (resolve) => { - await (0,utils/* sleep */._v)(1000); - if (!resolved) { - console.error("[VOT] Initialization timeout"); - } - resolved = true; - resolve(false); - }), - new Promise(async (resolve) => { - while (!this.initialized) { - await (0,utils/* sleep */._v)(100); - } - resolved = true; - resolve(true); - }), - ]); - } - async handleSrcChanged() { - debug/* default */.Z.log("[VideoHandler] src changed", this); - - if (!(await this.waitInitialization())) return; + debug/* default */.A.log("[VideoHandler] src changed", this); this.stopTranslation(); - this.videoData = await this.getVideoData(); - this.firstPlay = true; + this.videoData = await this.getVideoData(); + if (this.videoData.detectedLanguage) { + this.setSelectMenuValues( + this.videoData.detectedLanguage, + this.videoData.responseLanguage, + ); + } + const hide = !this.video.src && !this.video.currentSrc && !this.video.srcObject; this.votButton.container.hidden = hide; @@ -6008,24 +6187,16 @@ class VideoHandler { await this.updateSubtitles(); await this.changeSubtitlesLang("disabled"); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.data.responseLanguage ?? "ru", - ); this.translateToLang = this.data.responseLanguage ?? "ru"; } async release() { - debug/* default */.Z.log("[VideoHandler] release"); + debug/* default */.A.log("[VideoHandler] release"); - if (!(await this.waitInitialization())) return; this.initialized = false; - this.stopTranslation(); this.releaseExtraEvents(); this.subtitlesWidget.release(); - this.srcObserver.disconnect(); - clearInterval(this.srcObjectInterval); this.votButton.container.remove(); this.votMenu.container.remove(); } @@ -6055,11 +6226,11 @@ const videoObserver = new VideoObserver(); const videosWrappers = new WeakMap(); async function src_main() { - debug/* default */.Z.log("Loading extension..."); + debug/* default */.A.log("Loading extension..."); - await localizationProvider/* localizationProvider */.V.update(); + await localizationProvider.update(); - debug/* default */.Z.log(`Selected menu language: ${localizationProvider/* localizationProvider */.V.lang}`); + debug/* default */.A.log(`Selected menu language: ${localizationProvider.lang}`); if ( true && @@ -6067,18 +6238,14 @@ async function src_main() { cfOnlyExtensions.includes(GM_info.scriptHandler) ) { console.error( - `[VOT] ${localizationProvider/* localizationProvider */.V - .getDefault("unSupportedExtensionError") - .format(GM_info.scriptHandler)}`, + `[VOT] ${localizationProvider.getDefault("unSupportedExtensionError").replace("{0}", GM_info.scriptHandler)}`, ); return alert( - `[VOT] ${localizationProvider/* localizationProvider */.V - .get("unSupportedExtensionError") - .format(GM_info.scriptHandler)}`, + `[VOT] ${localizationProvider.get("unSupportedExtensionError").replace("{0}", GM_info.scriptHandler)}`, ); } - debug/* default */.Z.log("Extension compatibility passed..."); + debug/* default */.A.log("Extension compatibility passed..."); videoObserver.onVideoAdded.addListener((video) => { for (const site of getSites()) { @@ -6151,6 +6318,19 @@ src_main().catch((e) => { console.error("[VOT]", e); }); +// if (import.meta.webpackHot) { +// import.meta.webpackHot.monkeyReload(); +// import.meta.webpackHot.dispose(() => { +// for (const selector of [ +// ".vot-menu", +// ".vot-segmented-button", +// ".vot-subtitles-widget", +// ]) { +// document.querySelector(selector)?.remove(); +// } +// }); +// } + })(); /******/ })() diff --git a/img/example.jpg b/img/example.jpg deleted file mode 100644 index 3859a7ea..00000000 Binary files a/img/example.jpg and /dev/null differ diff --git a/img/example.png b/img/example.png new file mode 100644 index 00000000..523071d0 Binary files /dev/null and b/img/example.png differ diff --git a/img/example_en.jpg b/img/example_en.jpg deleted file mode 100644 index 89992fb3..00000000 Binary files a/img/example_en.jpg and /dev/null differ diff --git a/img/example_en.png b/img/example_en.png new file mode 100644 index 00000000..1d700e0a Binary files /dev/null and b/img/example_en.png differ diff --git a/package-lock.json b/package-lock.json index 68795a9a..d9bc6ad0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,22 +13,22 @@ "requestidlecallback-polyfill": "^1.0.2" }, "devDependencies": { - "css-loader": "^6.8.1", - "eslint": "^8.56.0", + "css-loader": "^6.10.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-prettier": "^5.1.3", "eslint-webpack-plugin": "^4.0.1", - "husky": "^8.0.3", - "lint-staged": "^15.2.0", - "prettier": "^3.1.1", - "sass": "^1.69.6", - "sass-loader": "^13.3.3", - "style-loader": "^3.3.3", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "prettier": "^3.2.5", + "sass": "^1.71.1", + "sass-loader": "^14.1.1", + "style-loader": "^3.3.4", "tslib": "^2.6.2", - "webpack": "^5.89.0", + "webpack": "^5.90.3", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", - "webpack-userscript": "^3.2.2" + "webpack-dev-server": "^5.0.2", + "webpack-monkey": "^0.2.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -97,22 +97,22 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -133,11 +133,107 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -168,9 +264,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", + "integrity": "sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw==", "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -182,9 +278,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -216,9 +312,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", + "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -266,6 +362,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgr/core": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.0.tgz", @@ -295,9 +401,9 @@ } }, "node_modules/@types/bonjour": { - "version": "3.5.12", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.12.tgz", - "integrity": "sha512-ky0kWSqXVxSqgqJvPIkgFkcn4C8MnRog308Ou8xBBIVo39OmUFy+jqNe0nPwLCDFxUpmT9EvT91YzOJgkDRcFg==", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -313,9 +419,9 @@ } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.2.tgz", - "integrity": "sha512-gX2j9x+NzSh4zOhnRPSdPPmTepS4DfxES0AvIFv3jGv5QyeAJf6u6dY5/BAoAJU9Qq1uTvwOku8SSC2GnCRl6Q==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, "dependencies": { "@types/express-serve-static-core": "*", @@ -343,15 +449,15 @@ } }, "node_modules/@types/estree": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.3.tgz", - "integrity": "sha512-CS2rOaoQ/eAgAfcTfq6amKG7bsN+EMcgGY4FAFQdvSj2y1ixvOZTUA9mOtCai7E1SYu283XNw7urKK30nP3wkQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/express": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", - "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -432,6 +538,15 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.9", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", @@ -445,9 +560,9 @@ "dev": true }, "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "dev": true }, "node_modules/@types/send": { @@ -461,18 +576,18 @@ } }, "node_modules/@types/serve-index": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.3.tgz", - "integrity": "sha512-4KG+yMEuvDPRrYq5fyVm/I2uqAJSAwZK9VSa+Zf+zUq9/oxSSvy3kkIqyL+jjStv6UCVi8/Aho0NHtB1Fwosrg==", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz", - "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", + "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", "dev": true, "dependencies": { "@types/http-errors": "*", @@ -481,24 +596,18 @@ } }, "node_modules/@types/sockjs": { - "version": "0.3.35", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.35.tgz", - "integrity": "sha512-tIF57KB+ZvOBpAQwSaACfEu7htponHXaFzP7RfKYgsOS0NoYnn+9+jzp7bbq4fWerizI3dTB4NfAZoyeQKWJLw==", + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, "dependencies": { "@types/node": "*" } }, - "node_modules/@types/validator": { - "version": "13.11.5", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.5.tgz", - "integrity": "sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q==", - "dev": true - }, "node_modules/@types/ws": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.8.tgz", - "integrity": "sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, "dependencies": { "@types/node": "*" @@ -916,21 +1025,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1001,13 +1095,11 @@ "dev": true }, "node_modules/bonjour-service": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", - "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } @@ -1039,6 +1131,15 @@ "node": ">=8" } }, + "node_modules/browser-extension-url-match": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/browser-extension-url-match/-/browser-extension-url-match-0.3.3.tgz", + "integrity": "sha512-x7uphFW6fxHF8/RfNqUQomZL4KsKgNb3f8ZrLsYsxSVTaOyeg9I3w/8iuQ2I51vVmrtiYiv37Tfq5gQyMN3j2Q==", + "dev": true, + "dependencies": { + "fancy-regex": "^0.4.3" + } + }, "node_modules/browserslist": { "version": "4.22.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", @@ -1077,6 +1178,21 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", @@ -1146,16 +1262,10 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1168,6 +1278,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -1208,23 +1321,6 @@ "node": ">=8" } }, - "node_modules/class-transformer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "dev": true - }, - "node_modules/class-validator": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", - "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", - "dev": true, - "dependencies": { - "@types/validator": "^13.7.10", - "libphonenumber-js": "^1.10.14", - "validator": "^13.7.0" - } - }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -1315,9 +1411,9 @@ } }, "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.0.0.tgz", - "integrity": "sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -1513,19 +1609,19 @@ } }, "node_modules/css-loader": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", "dev": true, "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.21", + "postcss": "^8.4.33", "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.3", - "postcss-modules-scope": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { "node": ">= 12.13.0" @@ -1535,7 +1631,16 @@ "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/cssesc": { @@ -1573,6 +1678,34 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -1600,12 +1733,15 @@ } }, "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/depd": { @@ -1633,12 +1769,6 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", - "dev": true - }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -1663,6 +1793,12 @@ "node": ">=6.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1749,16 +1885,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -2066,6 +2202,12 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/fancy-regex": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/fancy-regex/-/fancy-regex-0.4.3.tgz", + "integrity": "sha512-c9R6Q7cM8pX5i0ZF3sAjYWPFsjGOUthPWPnkuZgDP8i6bzRtTnSXX5PJeWc34w/C0tbGj/bO3GSmdnEEj4K5PQ==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2223,9 +2365,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "dev": true, "funding": [ { @@ -2242,6 +2384,34 @@ } } }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2260,12 +2430,6 @@ "node": ">= 0.6" } }, - "node_modules/fs-monkey": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", - "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", - "dev": true - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2608,15 +2772,15 @@ } }, "node_modules/husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", "dev": true, "bin": { - "husky": "lib/bin.js" + "husky": "bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/typicode" @@ -2764,15 +2928,15 @@ } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2808,6 +2972,36 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-network-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.0.1.tgz", + "integrity": "sha512-OwQXkwBJeESyhFw+OumbJVD58BFBJJI5OM5S1+eyrDKlgDZPX2XNT5gXS56GSD3NPbbwUuMlR1Q71SRp5SobuQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2863,15 +3057,18 @@ } }, "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, "dependencies": { - "is-docker": "^2.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isarray": { @@ -2895,6 +3092,24 @@ "node": ">=0.10.0" } }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", @@ -3019,12 +3234,6 @@ "node": ">= 0.8.0" } }, - "node_modules/libphonenumber-js": { - "version": "1.10.48", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.48.tgz", - "integrity": "sha512-Vvcgt4+o8+puIBJZLdMshPYx9nRN3/kTT7HPtOyfYrSQuN9PGBF1KUv0g07fjNzt4E4GuA7FnsLb+WeAMzyRQg==", - "dev": true - }, "node_modules/lilconfig": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", @@ -3035,9 +3244,9 @@ } }, "node_modules/lint-staged": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.0.tgz", - "integrity": "sha512-TFZzUEV00f+2YLaVPWBWGAMq7So6yQx+GG8YRMDeOEIf95Zn5RyiLMsEiX4KTNl9vq/w+NqRJkLA1kPIo15ufQ==", + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", + "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", "dev": true, "dependencies": { "chalk": "5.3.0", @@ -3045,7 +3254,7 @@ "debug": "4.3.4", "execa": "8.0.1", "lilconfig": "3.0.0", - "listr2": "8.0.0", + "listr2": "8.0.1", "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", @@ -3217,9 +3426,9 @@ } }, "node_modules/listr2": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.0.tgz", - "integrity": "sha512-u8cusxAcyqAiQ2RhYvV7kRKNLgUvtObIbhOX2NCXqvp1UU32xIg5CT22ykS2TPKJXZWJwtK3IKLiqAGlGNE+Zg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", + "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", @@ -3263,18 +3472,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true - }, "node_modules/log-update": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", @@ -3386,15 +3595,19 @@ } }, "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.7.7.tgz", + "integrity": "sha512-x9qc6k88J/VVwnfTkJV8pRRswJ2156Rc4w5rciRqKceFDZ0y1MqsNL9pkg5sE0GOcDzZYbonreALhaHzg1siFw==", "dev": true, "dependencies": { - "fs-monkey": "^1.0.4" + "tslib": "^2.0.0" }, "engines": { "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, "node_modules/merge-descriptors": { @@ -3500,6 +3713,12 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3520,9 +3739,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -3558,26 +3777,6 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -3675,17 +3874,18 @@ } }, "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/open/-/open-10.0.3.tgz", + "integrity": "sha512-dtbI5oW7987hwC9qjJTyABldTaa19SuyJse1QboWv3b0qCcrrLNVDqBx1XgELAjh9QTVQaP/C5b1nhQebd1H2A==", "dev": true, "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3739,16 +3939,20 @@ } }, "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, "dependencies": { - "@types/retry": "0.12.0", + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -3814,6 +4018,31 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -3915,9 +4144,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", "dev": true, "funding": [ { @@ -3934,7 +4163,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -3955,9 +4184,9 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", + "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", "dev": true, "dependencies": { "icss-utils": "^5.0.0", @@ -3972,9 +4201,9 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", + "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", "dev": true, "dependencies": { "postcss-selector-parser": "^6.0.4" @@ -4002,9 +4231,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -4030,9 +4259,9 @@ } }, "node_modules/prettier": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.1.tgz", - "integrity": "sha512-qSUWshj1IobVbKc226Gw2pync27t0Kf0EdufZa9j7uBSJay1CC+B3K5lAAZoqgX3ASiKuWsk6OmzKRetXNObWg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -4208,12 +4437,6 @@ "node": ">= 10.13.0" } }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true - }, "node_modules/requestidlecallback-polyfill": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/requestidlecallback-polyfill/-/requestidlecallback-polyfill-1.0.2.tgz", @@ -4317,9 +4540,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, "node_modules/rimraf": { @@ -4337,6 +4560,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4387,9 +4622,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.69.7", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz", - "integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==", + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -4404,29 +4639,29 @@ } }, "node_modules/sass-loader": { - "version": "13.3.3", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz", - "integrity": "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", + "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", "dev": true, "dependencies": { "neo-async": "^2.6.2" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "fibers": ">= 3.1.0", + "@rspack/core": "0.x || 1.x", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "fibers": { + "@rspack/core": { "optional": true }, "node-sass": { @@ -4437,6 +4672,9 @@ }, "sass-embedded": { "optional": true + }, + "webpack": { + "optional": true } } }, @@ -4500,11 +4738,12 @@ "dev": true }, "node_modules/selfsigned": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", - "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, "dependencies": { + "@types/node-forge": "^1.3.0", "node-forge": "^1" }, "engines": { @@ -4756,23 +4995,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -4842,18 +5064,6 @@ "wbuf": "^1.7.3" } }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -4895,6 +5105,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4907,6 +5132,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -4929,9 +5167,9 @@ } }, "node_modules/style-loader": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz", - "integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", + "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", "dev": true, "engines": { "node": ">= 12.13.0" @@ -4984,44 +5222,6 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/table": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", - "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -5032,9 +5232,9 @@ } }, "node_modules/terser": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", - "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", + "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -5050,16 +5250,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.9", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", - "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.8" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -5163,12 +5363,6 @@ "node": ">=0.6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -5290,15 +5484,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/validator": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", - "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -5330,26 +5515,20 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.11.5", "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -5363,7 +5542,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -5438,77 +5617,82 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.0.0.tgz", + "integrity": "sha512-tZ5hqsWwww/8DislmrzXE3x+4f+v10H1z57mA2dWFrILb4i3xX+dPhTkcdR0DLyQztrhF2AUmO5nN085UYjd/Q==", "dev": true, "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", + "memfs": "^4.6.0", "mime-types": "^2.1.31", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, "node_modules/webpack-dev-server": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.2.tgz", + "integrity": "sha512-IVj3qsQhiLJR82zVg3QdPtngMD05CYP/Am+9NG5QSl+XwUR/UPtFwllRBKrMwM9ttzFsC6Zj3DMgniPyn/Z0hQ==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", + "html-entities": "^2.4.0", "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" + "webpack-dev-middleware": "^7.0.0", + "ws": "^8.16.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { "webpack": { @@ -5519,6 +5703,70 @@ } } }, + "node_modules/webpack-dev-server/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-dev-server/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", @@ -5533,6 +5781,35 @@ "node": ">=10.0.0" } }, + "node_modules/webpack-monkey": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/webpack-monkey/-/webpack-monkey-0.2.1.tgz", + "integrity": "sha512-BFhOyl/2DGE9HzlOzTlqM8GUhb6CDsNY4d8lnhM85DQzzDV+USijD/Y+BKEP//I5IxRedBUTdSZBUnp12CighQ==", + "dev": true, + "workspaces": [ + "examples/*" + ], + "dependencies": { + "browser-extension-url-match": "^0.3.3", + "lodash": "^4.17.21", + "mitt": "^3.0.1", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "colorette": "^2.0.0", + "terser-webpack-plugin": "^5.0.0", + "webpack": "^5.0.0", + "webpack-dev-server": "^5.0.0" + }, + "peerDependenciesMeta": { + "colorette": { + "optional": true + }, + "terser-webpack-plugin": { + "optional": true + } + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -5542,26 +5819,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack-userscript": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/webpack-userscript/-/webpack-userscript-3.2.2.tgz", - "integrity": "sha512-XZHdxbHJ6bA7PWQRULST6qI5agiyoBDq//6vtHou9aAeCAyrIzeVSldSLdYBx2Fbrn+1sbjn8HXOFs5wq5EKtw==", - "dev": true, - "dependencies": { - "class-transformer": "0.5.1", - "class-validator": "^0.14.0", - "node-fetch": "^2.6.9", - "p-limit": "^3.1.0", - "reflect-metadata": "^0.1.13", - "ssri": "^10.0.1", - "table": "^6.8.1", - "tapable": "^2.2.1", - "tslib": "^2.0.0" - }, - "peerDependencies": { - "webpack": "5" - } - }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -5625,16 +5882,6 @@ "node": ">=0.8.0" } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5673,6 +5920,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -5704,9 +5969,9 @@ "dev": true }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.0.0.tgz", - "integrity": "sha512-GPQHj7row82Hjo9hKZieKcHIhaAIKOJvFSIZXuCU9OASVZrMNUaZuz++SPVrBjnLsnk4k+z9f2EIypgxf2vNFw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, "dependencies": { "emoji-regex": "^10.3.0", @@ -5742,9 +6007,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index 9baf8335..e49516ad 100644 --- a/package.json +++ b/package.json @@ -16,22 +16,22 @@ "voice-over-translation" ], "devDependencies": { - "css-loader": "^6.8.1", - "eslint": "^8.56.0", + "css-loader": "^6.10.0", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.2", + "eslint-plugin-prettier": "^5.1.3", "eslint-webpack-plugin": "^4.0.1", - "husky": "^8.0.3", - "lint-staged": "^15.2.0", - "prettier": "^3.1.1", - "sass": "^1.69.6", - "sass-loader": "^13.3.3", - "style-loader": "^3.3.3", + "husky": "^9.0.11", + "lint-staged": "^15.2.2", + "prettier": "^3.2.5", + "sass": "^1.71.1", + "sass-loader": "^14.1.1", + "style-loader": "^3.3.4", "tslib": "^2.6.2", - "webpack": "^5.89.0", + "webpack": "^5.90.3", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", - "webpack-userscript": "^3.2.2" + "webpack-dev-server": "^5.0.2", + "webpack-monkey": "^0.2.1" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", diff --git a/src/config/config.js b/src/config/config.js index 6e2f83b9..640944ee 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -1,10 +1,7 @@ -import { lang } from "../utils/utils.js"; - // CONFIGURATION const workerHost = "api.browser.yandex.ru"; -const m3u8ProxyHost = "m3u8proxy.toil-dump.workers.dev"; -const proxyWorkerHost = - lang === "uk" ? "vot-new.toil-dump.workers.dev" : "vot-worker.onrender.com"; // used for cloudflare version (vot-new.toil-dump.workers.dev || vot-worker.onrender.com) +const m3u8ProxyHost = "m3u8-proxy.toil.cc"; // used for striming +const proxyWorkerHost = "vot.toil.cc"; // used for cloudflare version (vot-new.toil-dump.workers.dev || vot-worker.onrender.com) const yandexHmacKey = "xtGCyGdTY2Jy6OMEKdTuXev3Twhkamgm"; const yandexUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 YaBrowser/23.7.1.1140 Yowser/2.5 Safari/537.36"; diff --git a/src/config/sites.js b/src/config/sites.js index 1eda7b47..f187ef62 100644 --- a/src/config/sites.js +++ b/src/config/sites.js @@ -94,12 +94,24 @@ const sites = () => { selector: ".videoplayer_media", }, { - // TODO: video selector: ".vp-video-wrapper > .vp-video > .vp-telecine > video" host: "vimeo", url: "https://vimeo.com/", - match: /^(player.)?vimeo.com$/, + match: /^vimeo.com$/, selector: ".player", }, + { + additionalData: "embed", + host: "vimeo", + url: "https://player.vimeo.com/", + match: /^player.vimeo.com$/, + selector: ".player", + }, + { + host: "ok.ru", + url: "https://ok.ru/", + match: /^ok.ru$/, + selector: ".html5-vpl_vid", + }, { host: "nine_gag", url: "https://9gag.com/gag/", @@ -116,7 +128,7 @@ const sites = () => { host: "bitchute", url: "https://www.bitchute.com/video/", match: /^(www.)?bitchute.com$/, - selector: ".plyr__video-wrapper", + selector: "#player", }, { host: "rutube", @@ -227,6 +239,66 @@ const sites = () => { match: /^coursehunter.net$/, selector: "#oframeplayer > pjsdiv:nth-of-type(1)", }, + { + host: "googledrive", + url: "https://drive.google.com/file/d/", + match: /^youtube.googleapis.com$/, + selector: ".html5-video-container", + }, + { + host: "bannedvideo", + url: "https://banned.video/watch?id=", + match: /^(www.)?banned.video$/, + selector: ".vjs-v7", + }, + { + host: "facebook", + url: "https://facebook.com", // <-- there should be no slash because we take the whole pathname + match: (url) => + url.host.includes("facebook.com") && url.pathname.includes("/videos/"), + selector: 'div[data-pagelet="WatchPermalinkVideo"]', + }, + { + additionalData: "reels", + host: "facebook", + url: "https://facebook.com", // <-- there should be no slash because we take the whole pathname + match: (url) => + url.host.includes("facebook.com") && url.pathname.includes("/reel/"), + selector: 'div[role="main"]', + }, + { + host: "weverse", + url: "https://weverse.io/", + match: /^weverse.io$/, + selector: ".webplayer-internal-source-wrapper", + }, + { + host: "newgrounds", + url: "https://www.newgrounds.com/", + match: /^www.newgrounds.com$/, + selector: ".ng-video-player", + }, + { + // TODO: Добавить поддержку tips и платных курсов + host: "egghead", + url: "https://egghead.io", + match: /^egghead.io$/, + selector: ".cueplayer-react-video-holder", + }, + { + host: "youku", + // Что-то перекрывает кнопку и не дает её нажать + url: "https://v.youku.com/", + match: /^v.youku.com$/, + selector: "#ykPlayer", + }, + // Нужно куда-то заливать данные о плейлисте + // { + // host: "epicgames", + // url: "https://dev.epicgames.com/community/learning/tutorials/", + // match: /^dev.epicgames.com$/, + // selector: "#vjs_video_3", + // }, ]; }; diff --git a/src/headers.json b/src/headers.json index 9d7ac009..2a069d74 100644 --- a/src/headers.json +++ b/src/headers.json @@ -1,7 +1,7 @@ { "name": "[VOT] - Voice Over Translation", "description": "A small extension that adds a Yandex Browser video translation to other browsers", - "version": "1.5.0.5", + "version": "1.5.1", "author": "sodapng, mynovelhost, Toil, SashaXser, MrSoczekXD", "namespace": "vot", "icon": "https://translate.yandex.ru/icons/favicon.ico", @@ -95,21 +95,20 @@ "*://tube.la-dina.net/*", "*://peertube.tmp.rcp.tf/*", "*://geo.dailymotion.com/*", + "*://*.ok.ru/*", "*://trovo.live/*", "*://disk.yandex.ru/i/*", - "*://coursehunter.net/*" + "*://coursehunter.net/*", + "*://youtube.googleapis.com/embed/*", + "*://*.banned.video/*", + "*://*.weverse.io/*", + "*://*.newgrounds.com/*", + "*://*.egghead.io/*", + "*://*.youku.com/*" ], "require": [ "https://cdn.jsdelivr.net/npm/protobufjs/dist/light/protobuf.min.js", - "https://cdn.jsdelivr.net/npm/hls.js@1" - ], - "grant": [ - "GM_xmlhttpRequest", - "GM_info", - "GM_setValue", - "GM_getValue", - "GM_deleteValue", - "GM_listValues" + "https://cdn.jsdelivr.net/npm/hls.js/dist/hls.light.min.js" ], "connect": ["api.browser.yandex.ru"] } diff --git a/src/index.js b/src/index.js index f0b2fb89..ae5bf57d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,53 +1,55 @@ -import "./styles/main.scss"; -import { VOTLocalizedError } from "./utils/VOTLocalizedError.js"; -import { youtubeUtils } from "./utils/youtubeUtils.js"; -import { yandexProtobuf } from "./yandexProtobuf.js"; -import { - getVideoId, - secsToStrTime, - lang, - isPiPAvailable, - sleep, - initHls, -} from "./utils/utils.js"; +import { sitesInvidious, sitesPiped } from "./config/alternativeUrls.js"; import { defaultAutoVolume, - defaultTranslationService, defaultDetectService, + defaultTranslationService, m3u8ProxyHost, proxyWorkerHost, } from "./config/config.js"; -import { sitesInvidious, sitesPiped } from "./config/alternativeUrls.js"; import { - availableLangs, - additionalTTS, actualTTS, + additionalTTS, + availableLangs, cfOnlyExtensions, } from "./config/constants.js"; import { - localizationProvider, availableLocales, + localizationProvider, } from "./localization/localizationProvider.js"; +import "./styles/main.scss"; import ui from "./ui.js"; -import { syncVolume } from "./utils/volume.js"; +import { VOTLocalizedError } from "./utils/VOTLocalizedError.js"; import debug from "./utils/debug.js"; +import { + getVideoId, + initHls, + isPiPAvailable, + lang, + secsToStrTime, +} from "./utils/utils.js"; +import { syncVolume } from "./utils/volume.js"; +import { yandexProtobuf } from "./yandexProtobuf.js"; import Bowser from "bowser"; -import requestVideoTranslation from "./rvt.js"; -import requestStreamTranslation from "./rst.js"; import requestStreamPing from "./rsp.js"; -import { getSubtitles, fetchSubtitles, SubtitlesWidget } from "./subtitles.js"; -import { coursehunterUtils } from "./utils/coursehunterUtils.js"; -import { courseraUtils } from "./utils/courseraUtils.js"; -import { udemyUtils } from "./utils/udemyUtils.js"; +import requestStreamTranslation from "./rst.js"; +import requestVideoTranslation from "./rvt.js"; +import { SubtitlesWidget, fetchSubtitles, getSubtitles } from "./subtitles.js"; + +import youtubeUtils from "./utils/youtubeUtils.js"; +import coursehunterUtils from "./utils/coursehunterUtils.js"; +import courseraUtils from "./utils/courseraUtils.js"; +import udemyUtils from "./utils/udemyUtils.js"; +import bannedvideoUtils from "./utils/bannedvideoUtils.js"; +import weverseUtils from "./utils/weverseUtils.js"; -import { VideoObserver } from "./utils/VideoObserver.js"; import sites from "./config/sites.js"; +import { VideoObserver } from "./utils/VideoObserver.js"; import { votStorage } from "./utils/storage.js"; import { - translate, detectServices, + translate, translateServices, } from "./utils/translateApis.js"; @@ -218,6 +220,10 @@ class VideoHandler { firstPlay = true; audio = new Audio(); hls = initHls(); // debug enabled only in dev mode + + videoTranslations = []; + videoTranslationTTL = 7200; + downloadTranslationUrl = null; downloadSubtitlesUrl = null; @@ -244,16 +250,7 @@ class VideoHandler { this.container = container; this.site = site; this.handleSrcChangedBound = this.handleSrcChanged.bind(this); - this.srcObserver = new MutationObserver(this.handleSrcChangedBound); - this.srcObserver.observe(this.video, { - attributeFilter: ["src", "currentSrc"], - }); - this.srcObjectInterval = setInterval(async () => { - if (this.videoLastSrcObject !== this.video.srcObject) { - this.videoLastSrcObject = this.video.srcObject; - await this.handleSrcChanged(); - } - }, 100); + this.video.addEventListener("loadedmetadata", this.handleSrcChangedBound); this.stopTranslationBound = this.stopTranslation.bind(this); this.handleVideoEventBound = this.handleVideoEvent.bind(this); this.changeOpacityOnEventBound = this.changeOpacityOnEvent.bind(this); @@ -264,52 +261,46 @@ class VideoHandler { async init() { if (this.initialized) return; - this.data = { - autoTranslate: await votStorage.get("autoTranslate", 0, true), - dontTranslateLanguage: await votStorage.get( - "dontTranslateLanguage", - lang, - ), - dontTranslateYourLang: await votStorage.get( - "dontTranslateYourLang", - 1, - true, - ), - autoSetVolumeYandexStyle: await votStorage.get( + const audioProxyDefault = + lang === "uk" && BUILD_MODE === "cloudflare" ? 1 : 0; + + const dataPromises = { + autoTranslate: votStorage.get("autoTranslate", 0, true), + dontTranslateLanguage: votStorage.get("dontTranslateLanguage", lang), + dontTranslateYourLang: votStorage.get("dontTranslateYourLang", 1, true), + autoSetVolumeYandexStyle: votStorage.get( "autoSetVolumeYandexStyle", 1, true, ), - autoVolume: - (await votStorage.get("autoVolume", defaultAutoVolume, true)) / 100, - showVideoSlider: await votStorage.get("showVideoSlider", 1, true), - syncVolume: await votStorage.get("syncVolume", 0, true), - subtitlesMaxLength: await votStorage.get("subtitlesMaxLength", 300, true), - highlightWords: await votStorage.get("highlightWords", 0, true), - responseLanguage: await votStorage.get("responseLanguage", lang), - defaultVolume: await votStorage.get("defaultVolume", 100, true), - udemyData: await votStorage.get("udemyData", { - accessToken: "", - expires: 0, - }), - audioProxy: await votStorage.get( - "audioProxy", - lang === "uk" && BUILD_MODE === "cloudflare" ? 1 : 0, - true, - ), - showPiPButton: await votStorage.get("showPiPButton", 0, true), - translateAPIErrors: await votStorage.get("translateAPIErrors", 1, true), - translationService: await votStorage.get( + autoVolume: votStorage.get("autoVolume", defaultAutoVolume, true), + showVideoSlider: votStorage.get("showVideoSlider", 1, true), + syncVolume: votStorage.get("syncVolume", 0, true), + subtitlesMaxLength: votStorage.get("subtitlesMaxLength", 300, true), + highlightWords: votStorage.get("highlightWords", 0, true), + responseLanguage: votStorage.get("responseLanguage", lang), + defaultVolume: votStorage.get("defaultVolume", 100, true), + udemyData: votStorage.get("udemyData", { accessToken: "", expires: 0 }), + audioProxy: votStorage.get("audioProxy", audioProxyDefault, true), + showPiPButton: votStorage.get("showPiPButton", 0, true), + translateAPIErrors: votStorage.get("translateAPIErrors", 1, true), + translationService: votStorage.get( "translationService", defaultTranslationService, ), - detectService: await votStorage.get( - "detectService", - defaultDetectService, - ), - m3u8ProxyHost: await votStorage.get("m3u8ProxyHost", m3u8ProxyHost), - proxyWorkerHost: await votStorage.get("proxyWorkerHost", proxyWorkerHost), + detectService: votStorage.get("detectService", defaultDetectService), + m3u8ProxyHost: votStorage.get("m3u8ProxyHost", m3u8ProxyHost), + proxyWorkerHost: votStorage.get("proxyWorkerHost", proxyWorkerHost), }; + + const dataEntries = await Promise.all( + Object.entries(dataPromises).map(async ([key, promise]) => [ + key, + await promise, + ]), + ); + this.data = Object.fromEntries(dataEntries); + this.videoData = await this.getVideoData(); console.log("[db] data from db: ", this.data); @@ -325,10 +316,12 @@ class VideoHandler { this.initUI(); this.initUIEvents(); - const hide = + const videoHasNoSource = !this.video.src && !this.video.currentSrc && !this.video.srcObject; - this.votButton.container.hidden = hide; - hide && (this.votMenu.container.hidden = hide); + this.votButton.container.hidden = videoHasNoSource; + if (videoHasNoSource) { + this.votMenu.container.hidden = true; + } await this.updateSubtitles(); await this.changeSubtitlesLang("disabled"); @@ -566,9 +559,7 @@ class VideoHandler { this.votAutoSetVolumeCheckbox.container, ); this.votAutoSetVolumeSlider = ui.createSlider( - `${ - (this.data?.autoVolume ?? defaultAutoVolume) * 100 - }%`, + `${(this.data?.autoVolume ?? defaultAutoVolume) * 100}%`, (this.data?.autoVolume ?? defaultAutoVolume) * 100, 0, 100, @@ -601,7 +592,8 @@ class VideoHandler { this.data?.syncVolume ?? false, ); this.votSyncVolumeCheckbox.container.hidden = - this.site.host !== "youtube" || this.site.additionalData === "mobile"; + !["youtube", "googledrive"].includes(this.site.host) || + this.site.additionalData === "mobile"; this.votSettingsDialog.bodyContainer.appendChild( this.votSyncVolumeCheckbox.container, ); @@ -805,38 +797,47 @@ class VideoHandler { initUIEvents() { // VOT Button { - this.votButton.translateButton.addEventListener("click", async () => { - if (this.audio.src) { - debug.log("[click translationBtn] audio.src is not empty"); - this.stopTraslate(); - return; - } - - try { - debug.log("[click translationBtn] trying execute translation"); - const VIDEO_ID = getVideoId(this.site.host, this.video); + this.votButton.translateButton.addEventListener("click", () => { + (async () => { + if (this.audio.src) { + debug.log("[click translationBtn] audio.src is not empty"); + this.stopTranslate(); + return; + } - if (!VIDEO_ID) { - throw new VOTLocalizedError("VOTNoVideoIDFound"); + if (this.hls.url) { + debug.log("[click translationBtn] hls is not empty"); + this.stopTranslate(); + return; } - await this.translateExecutor(VIDEO_ID); - } catch (err) { - console.error("[VOT]", err); - if (err?.name === "VOTLocalizedError") { - this.transformBtn("error", err.localizedMessage); - } else { - this.transformBtn("error", err); + try { + debug.log("[click translationBtn] trying execute translation"); + + if (!this.videoData.videoId) { + throw new VOTLocalizedError("VOTNoVideoIDFound"); + } + + await this.translateExecutor(this.videoData.videoId); + } catch (err) { + console.error("[VOT]", err); + if (err?.name === "VOTLocalizedError") { + this.transformBtn("error", err.localizedMessage); + } else { + this.transformBtn("error", err); + } } - } + })(); }); - this.votButton.pipButton.addEventListener("click", async () => { - if (this.video !== document.pictureInPictureElement) { - await this.video.requestPictureInPicture(); - } else { - await document.exitPictureInPicture(); - } + this.votButton.pipButton.addEventListener("click", () => { + (async () => { + if (this.video !== document.pictureInPictureElement) { + await this.video.requestPictureInPicture(); + } else { + await document.exitPictureInPicture(); + } + })(); }); this.votButton.menuButton.addEventListener("click", () => { @@ -862,9 +863,8 @@ class VideoHandler { this.votSettingsButton.addEventListener("click", () => { this.votSettingsDialog.container.hidden = !this.votSettingsDialog.container.hidden; - if (document.fullscreen === undefined || document.fullscreen) { + if (document.fullscreenElement || document.webkitFullscreenElement) { document.webkitExitFullscreen && document.webkitExitFullscreen(); - document.mozCancelFullscreen && document.mozCancelFullscreen(); document.exitFullscreen && document.exitFullscreen(); } }); @@ -898,52 +898,54 @@ class VideoHandler { this.votVideoTranslationVolumeSlider.input.addEventListener( "input", - async (e) => { - this.data.defaultVolume = Number(e.target.value); - await votStorage.set("defaultVolume", this.data.defaultVolume); - this.votVideoTranslationVolumeSlider.label.querySelector( - "strong", - ).innerHTML = `${this.data.defaultVolume}%`; - this.audio.volume = this.data.defaultVolume / 100; - if (this.data.syncVolume === 1) { - this.syncTranslationWithVideo(this.data.defaultVolume); - } + (e) => { + (async () => { + this.data.defaultVolume = Number(e.target.value); + await votStorage.set("defaultVolume", this.data.defaultVolume); + this.votVideoTranslationVolumeSlider.label.querySelector( + "strong", + ).innerHTML = `${this.data.defaultVolume}%`; + this.audio.volume = this.data.defaultVolume / 100; + if (this.data.syncVolume === 1) { + this.syncTranslationWithVideo(this.data.defaultVolume); + } + })(); }, ); } // VOT Settings { - this.votAutoTranslateCheckbox.input.addEventListener( - "change", - async (e) => { + this.votAutoTranslateCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.autoTranslate = Number(e.target.checked); await votStorage.set("autoTranslate", this.data.autoTranslate); debug.log( "autoTranslate value changed. New value: ", this.data.autoTranslate, ); - }, - ); + })(); + }); this.votDontTranslateYourLangSelect.labelElement.addEventListener( "change", - async (e) => { - this.data.dontTranslateYourLang = Number(e.target.checked); - await votStorage.set( - "dontTranslateYourLang", - this.data.dontTranslateYourLang, - ); - debug.log( - "dontTranslateYourLang value changed. New value: ", - this.data.dontTranslateYourLang, - ); + (e) => { + (async () => { + this.data.dontTranslateYourLang = Number(e.target.checked); + await votStorage.set( + "dontTranslateYourLang", + this.data.dontTranslateYourLang, + ); + debug.log( + "dontTranslateYourLang value changed. New value: ", + this.data.dontTranslateYourLang, + ); + })(); }, ); - this.votAutoSetVolumeCheckbox.input.addEventListener( - "change", - async (e) => { + this.votAutoSetVolumeCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.autoSetVolumeYandexStyle = Number(e.target.checked); await votStorage.set( "autoSetVolumeYandexStyle", @@ -953,20 +955,21 @@ class VideoHandler { "autoSetVolumeYandexStyle value changed. New value: ", this.data.autoSetVolumeYandexStyle, ); - }, - ); + })(); + }); - this.votAutoSetVolumeSlider.input.addEventListener("input", async (e) => { - const presetAutoVolume = Number(e.target.value); - this.data.autoVolume = presetAutoVolume / 100; - await votStorage.set("autoVolume", presetAutoVolume); - this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML = - `${presetAutoVolume}%`; + this.votAutoSetVolumeSlider.input.addEventListener("input", (e) => { + (async () => { + const presetAutoVolume = Number(e.target.value); + this.data.autoVolume = (presetAutoVolume / 100).toFixed(2); + await votStorage.set("autoVolume", this.data.autoVolume); + this.votAutoSetVolumeSlider.label.querySelector("strong").innerHTML = + `${presetAutoVolume}%`; + })(); }); - this.votShowVideoSliderCheckbox.input.addEventListener( - "change", - async (e) => { + this.votShowVideoSliderCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.showVideoSlider = Number(e.target.checked); await votStorage.set("showVideoSlider", this.data.showVideoSlider); debug.log( @@ -976,48 +979,56 @@ class VideoHandler { this.votVideoVolumeSlider.container.hidden = this.data.showVideoSlider !== 1 || this.votButton.container.dataset.status !== "success"; - }, - ); + })(); + }); - this.votUdemyDataTextfield.input.addEventListener("change", async (e) => { - this.data.udemyData = { - accessToken: e.target.value, - expires: new Date().getTime(), - }; - await votStorage.set("udemyData", this.data.udemyData); - debug.log("udemyData value changed. New value: ", this.data.udemyData); - window.location.reload(); + this.votUdemyDataTextfield.input.addEventListener("change", (e) => { + (async () => { + this.data.udemyData = { + accessToken: e.target.value, + expires: new Date().getTime(), + }; + await votStorage.set("udemyData", this.data.udemyData); + debug.log( + "udemyData value changed. New value: ", + this.data.udemyData, + ); + window.location.reload(); + })(); }); - this.votSyncVolumeCheckbox.input.addEventListener("change", async (e) => { - this.data.syncVolume = Number(e.target.checked); - await votStorage.set("syncVolume", this.data.syncVolume); - debug.log( - "syncVolume value changed. New value: ", - this.data.syncVolume, - ); + this.votSyncVolumeCheckbox.input.addEventListener("change", (e) => { + (async () => { + this.data.syncVolume = Number(e.target.checked); + await votStorage.set("syncVolume", this.data.syncVolume); + debug.log( + "syncVolume value changed. New value: ", + this.data.syncVolume, + ); + })(); }); this.votTranslationServiceSelect.labelElement.addEventListener( "change", - async (e) => { - this.data.translateAPIErrors = Number(e.target.checked); - await votStorage.set( - "translateAPIErrors", - this.data.translateAPIErrors, - ); - debug.log( - "translateAPIErrors value changed. New value: ", - this.data.translateAPIErrors, - ); + (e) => { + (async () => { + this.data.translateAPIErrors = Number(e.target.checked); + await votStorage.set( + "translateAPIErrors", + this.data.translateAPIErrors, + ); + debug.log( + "translateAPIErrors value changed. New value: ", + this.data.translateAPIErrors, + ); + })(); }, ); // SUBTITLES - this.votSubtitlesMaxLengthSlider.input.addEventListener( - "input", - async (e) => { + this.votSubtitlesMaxLengthSlider.input.addEventListener("input", (e) => { + (async () => { this.data.subtitlesMaxLength = Number(e.target.value); await votStorage.set( "subtitlesMaxLength", @@ -1027,25 +1038,26 @@ class VideoHandler { "strong", ).innerHTML = `${this.data.subtitlesMaxLength}`; this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength); - }, - ); + })(); + }); this.votSubtitlesHighlightWordsCheckbox.input.addEventListener( "change", - async (e) => { - this.data.highlightWords = Number(e.target.checked); - await votStorage.set("highlightWords", this.data.highlightWords); - debug.log( - "highlightWords value changed. New value: ", - this.data.highlightWords, - ); - this.subtitlesWidget.setHighlightWords(this.data.highlightWords); + (e) => { + (async () => { + this.data.highlightWords = Number(e.target.checked); + await votStorage.set("highlightWords", this.data.highlightWords); + debug.log( + "highlightWords value changed. New value: ", + this.data.highlightWords, + ); + this.subtitlesWidget.setHighlightWords(this.data.highlightWords); + })(); }, ); - this.votShowPiPButtonCheckbox.input.addEventListener( - "change", - async (e) => { + this.votShowPiPButtonCheckbox.input.addEventListener("change", (e) => { + (async () => { this.data.showPiPButton = Number(e.target.checked); await votStorage.set("showPiPButton", this.data.showPiPButton); debug.log( @@ -1056,26 +1068,24 @@ class VideoHandler { !isPiPAvailable() || !this.data.showPiPButton; this.votButton.separator2.hidden = !isPiPAvailable() || !this.data.showPiPButton; - }, - ); + })(); + }); // PROXY - this.votM3u8ProxyHostTextfield.input.addEventListener( - "change", - async (e) => { + this.votM3u8ProxyHostTextfield.input.addEventListener("change", (e) => { + (async () => { this.data.m3u8ProxyHost = e.target.value || m3u8ProxyHost; await votStorage.set("m3u8ProxyHost", this.data.m3u8ProxyHost); debug.log( "m3u8ProxyHost value changed. New value: ", this.data.m3u8ProxyHost, ); - }, - ); + })(); + }); - this.votProxyWorkerHostTextfield.input.addEventListener( - "change", - async (e) => { + this.votProxyWorkerHostTextfield.input.addEventListener("change", (e) => { + (async () => { this.data.proxyWorkerHost = e.target.value || proxyWorkerHost; await votStorage.set("proxyWorkerHost", this.data.proxyWorkerHost); debug.log( @@ -1083,25 +1093,29 @@ class VideoHandler { this.data.proxyWorkerHost, ); window.location.reload(); - }, - ); + })(); + }); - this.votAudioProxyCheckbox.input.addEventListener("change", async (e) => { - this.data.audioProxy = Number(e.target.checked); - await votStorage.set("audioProxy", this.data.audioProxy); - debug.log( - "audioProxy value changed. New value: ", - this.data.audioProxy, - ); + this.votAudioProxyCheckbox.input.addEventListener("change", (e) => { + (async () => { + this.data.audioProxy = Number(e.target.checked); + await votStorage.set("audioProxy", this.data.audioProxy); + debug.log( + "audioProxy value changed. New value: ", + this.data.audioProxy, + ); + })(); }); - this.votResetSettingsButton.addEventListener("click", async () => { - localizationProvider.reset(); - const valuesForClear = await votStorage.list(); - valuesForClear - .filter((v) => !localizationProvider.gmValues.includes(v)) - .forEach((v) => votStorage.syncDelete(v)); - window.location.reload(); + this.votResetSettingsButton.addEventListener("click", () => { + (async () => { + localizationProvider.reset(); + const valuesForClear = await votStorage.list(); + valuesForClear + .filter((v) => !localizationProvider.gmValues.includes(v)) + .forEach((v) => votStorage.syncDelete(v)); + window.location.reload(); + })(); }); } } @@ -1109,7 +1123,10 @@ class VideoHandler { releaseExtraEvents() { clearInterval(this.resizeInterval); this.resizeObserver?.disconnect(); - if (this.site.host === "youtube" && this.site.additionalData !== "mobile") { + if ( + ["youtube", "googledrive"].includes(this.site.host) && + this.site.additionalData !== "mobile" + ) { this.syncVolumeObserver?.disconnect(); } @@ -1158,7 +1175,10 @@ class VideoHandler { ); }, 500); // Sync volume slider with original video (youtube only) - if (this.site.host === "youtube" && this.site.additionalData !== "mobile") { + if ( + ["youtube", "googledrive"].includes(this.site.host) && + this.site.additionalData !== "mobile" + ) { this.syncVolumeObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if ( @@ -1258,25 +1278,26 @@ class VideoHandler { this.container.draggable = false; } - addExtraEventListener(this.video, "abort", () => { - debug.log("lipsync mode is abort"); + addExtraEventListener(this.video, "emptied", () => { + debug.log("lipsync mode is emptied"); this.stopTranslation(); - this.videoData = ""; }); addExtraEventListener(this.video, "progress", async () => { - if (!(this.firstPlay && this.data.autoTranslate === 1)) { + if ( + !(this.firstPlay && this.data.autoTranslate === 1) || + getVideoId(this.site.host, this.video) !== this.videoData.videoId + ) { return; } - const VIDEO_ID = getVideoId(this.site.host, this.video); - if (!VIDEO_ID) { + if (!this.videoData.videoId) { throw new VOTLocalizedError("VOTNoVideoIDFound"); } try { - await this.translateExecutor(VIDEO_ID); this.firstPlay = false; + await this.translateExecutor(this.videoData.videoId); } catch (err) { console.error("[VOT]", err); if (err?.name === "VOTLocalizedError") { @@ -1299,7 +1320,7 @@ class VideoHandler { this.logout(1); this.timer = setTimeout(() => { this.logout(0); - }, 2000); + }, 1000); } changeOpacityOnEvent(event) { @@ -1364,9 +1385,7 @@ class VideoHandler { async updateSubtitles() { await this.changeSubtitlesLang("disabled"); - const VIDEO_ID = getVideoId(this.site.host, this.video); - - if (!VIDEO_ID) { + if (!this.videoData.videoId) { console.error( `[VOT] ${localizationProvider.getDefault("VOTNoVideoIDFound")}`, ); @@ -1376,27 +1395,19 @@ class VideoHandler { return; } - if (this.subtitlesListVideoId === VIDEO_ID) { + if (this.subtitlesListVideoId === this.videoData.videoId) { return; } - if (!this.videoData.detectedLanguage) { - this.videoData = await this.getVideoData(); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.videoData.responseLanguage, - ); - } - this.subtitlesList = await getSubtitles( this.site, - VIDEO_ID, + this.videoData.videoId, this.videoData.detectedLanguage, ); if (!this.subtitlesList) { await this.changeSubtitlesLang("disabled"); } else { - this.subtitlesListVideoId = VIDEO_ID; + this.subtitlesListVideoId = this.videoData.videoId; } await this.updateSubtitlesLangSelect(); } @@ -1404,7 +1415,7 @@ class VideoHandler { // Get video volume in 0.00-1.00 format getVideoVolume() { let videoVolume = this.video?.volume; - if (this.site.host === "youtube") { + if (["youtube", "googledrive"].includes(this.site.host)) { videoVolume = youtubeUtils.getVideoVolume() || videoVolume; } return videoVolume; @@ -1412,7 +1423,7 @@ class VideoHandler { // Set video volume in 0.00-1.00 format setVideoVolume(volume) { - if (this.site.host === "youtube") { + if (["youtube", "googledrive"].includes(this.site.host)) { const videoVolume = youtubeUtils.setVideoVolume(volume); if (videoVolume) { return; @@ -1474,17 +1485,16 @@ class VideoHandler { } async getVideoData() { - const videoData = {}; - - // ! should be null for ALL websites except coursera and udemy ! - // else use direct link: `{url: xxx.mp4}` - videoData.translationHelp = null; - - videoData.isStream = false; // by default, we request the translation of the video - videoData.duration = this.video?.duration || 343; // ! if 0 - we get 400 error - videoData.videoId = getVideoId(this.site.host, this.video); - videoData.detectedLanguage = this.translateFromLang; - videoData.responseLanguage = this.translateToLang; + const videoData = { + // ! should be null for ALL websites except coursera and udemy ! + // else use direct link: `{url: xxx.mp4}` + translationHelp: null, + isStream: false, // by default, we request the translation of the video + duration: this.video?.duration || 343, // ! if 0 - we get 400 error + videoId: getVideoId(this.site.host, this.video), + detectedLanguage: this.translateFromLang, + responseLanguage: this.translateToLang, + }; if (!videoData.videoId) { this.ytData = {}; @@ -1500,11 +1510,15 @@ class VideoHandler { } } else if ( window.location.hostname.includes("rutube") || + window.location.hostname.includes("ok.ru") || window.location.hostname.includes("my.mail.ru") ) { videoData.detectedLanguage = "ru"; - } else if (window.location.hostname.includes("bilibili.com")) { + } else if (["bilibili", "youku"].includes(this.site.host)) { videoData.detectedLanguage = "zh"; + } else if (["vk"].includes(this.site.host)) { + const trackLang = document.getElementsByTagName("track")?.[0]?.srclang; + videoData.detectedLanguage = trackLang || "auto"; } else if (window.location.hostname.includes("coursera.org")) { const courseraData = await courseraUtils.getVideoData( this.translateToLang, @@ -1519,6 +1533,25 @@ class VideoHandler { url: coursehunterData.url, }; videoData.duration = coursehunterData.duration || videoData.duration; + } else if (window.location.hostname.includes("banned.video")) { + const bannedvideoData = await bannedvideoUtils.getVideoData( + videoData.videoId, + ); + videoData.translationHelp = { + url: bannedvideoData.url, + }; + + videoData.duration = bannedvideoData.duration || videoData.duration; + videoData.isStream = bannedvideoData.live; + } else if (window.location.hostname.includes("weverse.io")) { + const weverseData = await weverseUtils.getVideoData(); + videoData.detectedLanguage = "ko"; + if (weverseData) { + videoData.translationHelp = { + url: weverseData.url, + }; + videoData.duration = weverseData.duration || videoData.duration; + } } else if (window.location.hostname.includes("udemy.com")) { const udemyData = await udemyUtils.getVideoData( this.data.udemyData, @@ -1528,24 +1561,24 @@ class VideoHandler { videoData.detectedLanguage = udemyData.detectedLanguage; videoData.translationHelp = udemyData.translationHelp; } else if ( - this.site.host === "vk" || - this.site.host === "piped" || - this.site.host === "invidious" || - this.site.host === "bitchute" || - this.site.host === "rumble" || - this.site.host === "peertube" || - this.site.host === "dailymotion" || - this.site.host === "trovo" || - this.site.host === "yandexdisk" || - this.site.host === "coursehunter" + [ + "piped", + "invidious", + "bitchute", + "rumble", + "peertube", + "dailymotion", + "trovo", + "yandexdisk", + "coursehunter", + ].includes(this.site.host) ) { videoData.detectedLanguage = "auto"; } return videoData; } - videoValidator() { - if (this.site.host === "youtube") { + if (["youtube", "ok.ru", "vk"].includes(this.site.host)) { debug.log("VideoValidator videoData: ", this.videoData); if ( this.data.dontTranslateYourLang === 1 && @@ -1560,7 +1593,7 @@ class VideoHandler { // if (this.ytData.isLive) { // throw new VOTLocalizedError("VOTLiveNotSupported"); // } - if (this.videoData.duration > 14_400) { + if (!this.videoData.isStream && this.videoData.duration > 14_400) { throw new VOTLocalizedError("VOTVideoIsTooLong"); } } @@ -1580,7 +1613,7 @@ class VideoHandler { return; } - if (mode === "play") { + if (mode == "play") { debug.log("lipsync mode is play"); const audioPromise = this.audio.play(); if (audioPromise !== undefined) { @@ -1607,19 +1640,13 @@ class VideoHandler { } return; } - if (mode === "pause") { - debug.log("lipsync mode is pause"); - this.audio.pause(); - } - if (mode === "stop") { - debug.log("lipsync mode is stop"); - this.audio.pause(); - } - if (mode === "waiting") { - debug.log("lipsync mode is waiting"); + // video is inactive + if (["pause", "stop", "waiting"].includes(mode)) { + debug.log(`lipsync mode is ${mode}`); this.audio.pause(); } - if (mode === "playing") { + + if (mode == "playing") { debug.log("lipsync mode is playing"); this.audio.play(); } @@ -1632,12 +1659,11 @@ class VideoHandler { } // Default actions on stop translate - stopTraslate() { + stopTranslate() { videoLipSyncEvents.forEach((e) => this.video.removeEventListener(e, this.handleVideoEventBound), ); this.audio.pause(); - //! video.removeEventListener(".translate", stopTraslate, false); // why??? this.audio.src = ""; this.audio.removeAttribute("src"); this.votVideoVolumeSlider.container.hidden = true; @@ -1645,30 +1671,17 @@ class VideoHandler { this.votDownloadButton.hidden = true; this.downloadTranslationUrl = null; this.transformBtn("none", localizationProvider.get("translateVideo")); + debug.log(`Volume on start: ${this.volumeOnStart}`); if (this.volumeOnStart) { - debug.log(`Volume on start: ${this.volumeOnStart}`); - if (this.site.host === "youtube") { - youtubeUtils.setVideoVolume(this.volumeOnStart); - } else { - this.video.volume = this.volumeOnStart; - } + this.setVideoVolume(this.volumeOnStart); } + this.volumeOnStart = ""; clearInterval(this.streamPing); this.hls?.destroy(); this.hls = initHls(); } async translateExecutor(VIDEO_ID) { - if (!this.videoData.detectedLanguage) { - this.videoData = await this.getVideoData(); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.videoData.responseLanguage, - ); - } - debug.log("Run videoValidator"); - this.videoValidator(); - debug.log("Run translateFunc"); this.translateFunc( VIDEO_ID, @@ -1679,6 +1692,94 @@ class VideoHandler { ); } + async updateTranslationErrorMsg(errorMessage) { + const translationTake = localizationProvider.get("translationTake"); + const VOTTranslatingError = localizationProvider.get("VOTTranslatingError"); + const lang = localizationProvider.lang; + + if (errorMessage?.name === "VOTLocalizedError") { + this.transformBtn("error", errorMessage.localizedMessage); + } else if ( + this.data.translateAPIErrors === 1 && + !errorMessage.includes(translationTake) && + lang !== "ru" + ) { + const translatedMessage = await translate(errorMessage, "ru", lang); + this.transformBtn("error", VOTTranslatingError); + this.transformBtn("error", translatedMessage); + } else { + this.transformBtn("error", errorMessage); + } + } + + afterUpdateTranslation(audioUrl) { + this.votVideoVolumeSlider.container.hidden = + this.data.showVideoSlider !== 1 || + this.votButton.container.dataset.status !== "success"; + this.votVideoTranslationVolumeSlider.container.hidden = + this.votButton.container.dataset.status !== "success"; + + if (this.data.autoSetVolumeYandexStyle === 1) { + this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; + this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = + `${this.data.autoVolume * 100}%`; + ui.updateSlider(this.votVideoVolumeSlider.input); + } + + this.votDownloadButton.hidden = false; + this.downloadTranslationUrl = audioUrl; + } + + // update translation audio src + updateTranslation(audioUrl) { + // ! Don't use this function for streams + this.audio.src = audioUrl; + + // cf version only + if ( + BUILD_MODE === "cloudflare" && + this.data.audioProxy === 1 && + audioUrl.startsWith("https://vtrans.s3-private.mds.yandex.net/tts/prod/") + ) { + const audioPath = audioUrl.replace( + "https://vtrans.s3-private.mds.yandex.net/tts/prod/", + "", + ); + const proxiedAudioUrl = `https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${audioPath}`; + console.log(`[VOT] Audio proxied via ${proxiedAudioUrl}`); + this.audio.src = proxiedAudioUrl; + } + + this.volumeOnStart = this.getVideoVolume(); + if (typeof this.data.defaultVolume === "number") { + this.audio.volume = this.data.defaultVolume / 100; + } + if ( + typeof this.data.autoSetVolumeYandexStyle === "number" && + this.data.autoSetVolumeYandexStyle + ) { + this.setVideoVolume(this.data.autoVolume); + } + + switch (this.site.host) { + case "twitter": + document + .querySelector('div[data-testid="app-bar-back"][role="button"]') + .addEventListener("click", this.stopTranslationBound); + break; + case "invidious": + case "piped": + break; + } + + if (this.video && !this.video.paused) this.lipSync("play"); + videoLipSyncEvents.forEach((e) => + this.video.addEventListener(e, this.handleVideoEventBound), + ); + this.transformBtn("success", localizationProvider.get("disableTranslate")); + this.afterUpdateTranslation(audioUrl); + } + // Define a function to translate a video and handle the callback translateFunc( VIDEO_ID, @@ -1693,15 +1794,11 @@ class VideoHandler { : `${this.site.url}${VIDEO_ID}`; // fix enabling the old requested voiceover when changing the language to the native language (#) + debug.log("Run videoValidator"); this.videoValidator(); if (isStream) { debug.log("Executed stream translation"); - // if (BUILD_MODE === "cloudflare") { - // // Temporarily stream translation is only available in the main version - // throw new VOTLocalizedError("VOTCloudflareDoesntSupportStreams"); - // } - translateStream( videoURL, requestLang, @@ -1710,25 +1807,7 @@ class VideoHandler { debug.log("[exec callback] translateStream callback"); if (getVideoId(this.site.host, this.video) !== VIDEO_ID) return; if (!success || !resOrError.translatedInfo) { - if (resOrError?.name === "VOTLocalizedError") { - this.transformBtn("error", resOrError.localizedMessage); - } else { - if ( - this.data.translateAPIErrors === 1 && - localizationProvider.lang !== "ru" - ) { - this.transformBtn( - "error", - `${localizationProvider.get("VOTTranslatingError")}...`, - ); - this.transformBtn( - "error", - await translate(resOrError, "ru", localizationProvider.lang), - ); - } else { - this.transformBtn("error", resOrError); - } - } + await this.updateTranslationErrorMsg(resOrError); if (reqInterval === 10) { // if wait translating @@ -1780,16 +1859,16 @@ class VideoHandler { this.hls.on(Hls.Events.MEDIA_ATTACHED, function () { debug.log("audio and hls.js are now bound together !"); }); - this.hls.on(Hls.Events.MANIFEST_PARSED, function (event, data) { + this.hls.on(Hls.Events.MANIFEST_PARSED, function (data) { debug.log( "manifest loaded, found " + - data.levels.length + + data?.levels?.length + " quality level", ); }); this.hls.loadSource(streamURL); this.hls.attachMedia(this.audio); - this.hls.on(Hls.Events.ERROR, function (event, data) { + this.hls.on(Hls.Events.ERROR, function (data) { if (data.fatal) { switch (data.type) { case Hls.ErrorTypes.MEDIA_ERROR: @@ -1821,7 +1900,9 @@ class VideoHandler { throw new VOTLocalizedError("audioFormatNotSupported"); } - youtubeUtils.videoSeek(this.video, 10); // 10 is the most successful number for streaming. With it, the audio is not so far behind the original + if (this.site.host === "youtube") { + youtubeUtils.videoSeek(this.video, 10); // 10 is the most successful number for streaming. With it, the audio is not so far behind the original + } this.volumeOnStart = this.getVideoVolume(); if (typeof this.data.defaultVolume === "number") { @@ -1849,21 +1930,7 @@ class VideoHandler { this.video.addEventListener(e, this.handleVideoEventBound), ); - this.votVideoVolumeSlider.container.hidden = - this.data.showVideoSlider !== 1 || - this.votButton.container.dataset.status !== "success"; - this.votVideoTranslationVolumeSlider.container.hidden = - this.votButton.container.dataset.status !== "success"; - - if (this.data.autoSetVolumeYandexStyle === 1) { - this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; - this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = - `${this.data.autoVolume * 100}%`; - ui.updateSlider(this.votVideoVolumeSlider.input); - } - - this.votDownloadButton.hidden = false; - this.downloadTranslationUrl = streamURL; + this.afterUpdateTranslation(streamURL); }, ); @@ -1874,6 +1941,20 @@ class VideoHandler { throw new VOTLocalizedError("VOTTranslationHelpNull"); } + const cachedTranslation = this.videoTranslations.find( + (t) => + t.videoId === VIDEO_ID && + t.expires > Date.now() / 1000 && + t.from === requestLang && + t.to === responseLang, + ); + + if (cachedTranslation) { + this.updateTranslation(cachedTranslation.url); + debug.log("[translateFunc] A cached translate was received"); + return; + } + translateVideo( videoURL, this.videoData.duration, @@ -1884,28 +1965,8 @@ class VideoHandler { debug.log("[exec callback] translateVideo callback"); if (getVideoId(this.site.host, this.video) !== VIDEO_ID) return; if (!success) { - if (urlOrError?.name === "VOTLocalizedError") { - this.transformBtn("error", urlOrError.localizedMessage); - } else { - if ( - this.data.translateAPIErrors === 1 && - !urlOrError.includes( - localizationProvider.get("translationTake"), - ) && - localizationProvider.lang !== "ru" - ) { - this.transformBtn( - "error", - localizationProvider.get("VOTTranslatingError"), - ); - this.transformBtn( - "error", - await translate(urlOrError, "ru", localizationProvider.lang), - ); - } else { - this.transformBtn("error", urlOrError); - } - } + await this.updateTranslationErrorMsg(urlOrError); + // if the error line contains information that the translation is being performed, then we wait if ( urlOrError.includes(localizationProvider.get("translationTake")) @@ -1927,156 +1988,40 @@ class VideoHandler { return; } - this.audio.src = urlOrError; - - // cf version only - if ( - BUILD_MODE === "cloudflare" && - this.data.audioProxy === 1 && - urlOrError.startsWith("https://") - ) { - const audioPath = urlOrError.replace( - "https://vtrans.s3-private.mds.yandex.net/tts/prod/", - "", - ); - const proxiedAudioUrl = `https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${audioPath}`; - console.log(`[VOT] Audio proxied via ${proxiedAudioUrl}`); - this.audio.src = proxiedAudioUrl; - } - - this.volumeOnStart = this.getVideoVolume(); - if (typeof this.data.defaultVolume === "number") { - this.audio.volume = this.data.defaultVolume / 100; - } - if ( - typeof this.data.autoSetVolumeYandexStyle === "number" && - this.data.autoSetVolumeYandexStyle - ) { - this.setVideoVolume(this.data.autoVolume); - } + this.updateTranslation(urlOrError); - switch (this.site.host) { - case "twitter": - document - .querySelector('div[data-testid="app-bar-back"][role="button"]') - .addEventListener("click", this.stopTranslationBound); - break; - case "invidious": - case "piped": - break; - } - - if ( - !this.video.src && - !this.video.currentSrc && - !this.video.srcObject - ) { - this.stopTranslation(); - return; - } - - const siteHostnames = [ - "twitch", - "vimeo", - "facebook", - "rutube", - "twitter", - "bilibili", - "mail_ru", - "rumble", - "eporner", - ]; - for (let i = 0; i < siteHostnames.length; i++) { - if (this.site.host === siteHostnames[i]) { - const mutationObserver = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if ( - mutation.type === "attributes" && - mutation.attributeName === "src" && - mutation.target === this.video && - mutation.target.src !== "" - ) { - this.stopTranslation(); - this.firstPlay = true; - } - }); - }); - mutationObserver.observe(this.container, { - attributes: true, - childList: false, - subtree: true, - attributeOldValue: true, - }); - break; - } - } - - if (this.video && !this.video.paused) this.lipSync("play"); - videoLipSyncEvents.forEach((e) => - this.video.addEventListener(e, this.handleVideoEventBound), - ); - this.transformBtn( - "success", - localizationProvider.get("disableTranslate"), - ); - - this.votVideoVolumeSlider.container.hidden = - this.data.showVideoSlider !== 1 || - this.votButton.container.dataset.status !== "success"; - this.votVideoTranslationVolumeSlider.container.hidden = - this.votButton.container.dataset.status !== "success"; - - if (this.data.autoSetVolumeYandexStyle === 1) { - this.votVideoVolumeSlider.input.value = this.data.autoVolume * 100; - this.votVideoVolumeSlider.label.querySelector("strong").innerHTML = - `${this.data.autoVolume * 100}%`; - ui.updateSlider(this.votVideoVolumeSlider.input); - } - - this.votDownloadButton.hidden = false; - this.downloadTranslationUrl = urlOrError; + this.videoTranslations.push({ + videoId: VIDEO_ID, + from: requestLang, + to: responseLang, + url: urlOrError, + expires: Date.now() / 1000 + this.videoTranslationTTL, + }); }, ); } // Define a function to stop translation and clean up stopTranslation() { - this.stopTraslate(); + this.stopTranslate(); this.syncVideoVolumeSlider(); } - async waitInitialization() { - let resolved = false; - return await Promise.race([ - new Promise(async (resolve) => { - await sleep(1000); - if (!resolved) { - console.error("[VOT] Initialization timeout"); - } - resolved = true; - resolve(false); - }), - new Promise(async (resolve) => { - while (!this.initialized) { - await sleep(100); - } - resolved = true; - resolve(true); - }), - ]); - } - async handleSrcChanged() { debug.log("[VideoHandler] src changed", this); - if (!(await this.waitInitialization())) return; - this.stopTranslation(); - this.videoData = await this.getVideoData(); - this.firstPlay = true; + this.videoData = await this.getVideoData(); + if (this.videoData.detectedLanguage) { + this.setSelectMenuValues( + this.videoData.detectedLanguage, + this.videoData.responseLanguage, + ); + } + const hide = !this.video.src && !this.video.currentSrc && !this.video.srcObject; this.votButton.container.hidden = hide; @@ -2093,24 +2038,16 @@ class VideoHandler { await this.updateSubtitles(); await this.changeSubtitlesLang("disabled"); - this.setSelectMenuValues( - this.videoData.detectedLanguage, - this.data.responseLanguage ?? "ru", - ); this.translateToLang = this.data.responseLanguage ?? "ru"; } async release() { debug.log("[VideoHandler] release"); - if (!(await this.waitInitialization())) return; this.initialized = false; - this.stopTranslation(); this.releaseExtraEvents(); this.subtitlesWidget.release(); - this.srcObserver.disconnect(); - clearInterval(this.srcObjectInterval); this.votButton.container.remove(); this.votMenu.container.remove(); } @@ -2152,14 +2089,10 @@ async function main() { cfOnlyExtensions.includes(GM_info.scriptHandler) ) { console.error( - `[VOT] ${localizationProvider - .getDefault("unSupportedExtensionError") - .format(GM_info.scriptHandler)}`, + `[VOT] ${localizationProvider.getDefault("unSupportedExtensionError").replace("{0}", GM_info.scriptHandler)}`, ); return alert( - `[VOT] ${localizationProvider - .get("unSupportedExtensionError") - .format(GM_info.scriptHandler)}`, + `[VOT] ${localizationProvider.get("unSupportedExtensionError").replace("{0}", GM_info.scriptHandler)}`, ); } @@ -2235,3 +2168,16 @@ async function main() { main().catch((e) => { console.error("[VOT]", e); }); + +// if (import.meta.webpackHot) { +// import.meta.webpackHot.monkeyReload(); +// import.meta.webpackHot.dispose(() => { +// for (const selector of [ +// ".vot-menu", +// ".vot-segmented-button", +// ".vot-subtitles-widget", +// ]) { +// document.querySelector(selector)?.remove(); +// } +// }); +// } diff --git a/src/styles/components/menu.scss b/src/styles/components/menu.scss index a047842b..cd74909f 100644 --- a/src/styles/components/menu.scss +++ b/src/styles/components/menu.scss @@ -42,7 +42,6 @@ &[hidden] { pointer-events: none; display: block !important; - pointer-events: none; visibility: hidden; opacity: 0; transform: translate(-50%) scale(0); diff --git a/src/subtitles.js b/src/subtitles.js index cab39e3b..fdaa97a9 100644 --- a/src/subtitles.js +++ b/src/subtitles.js @@ -1,5 +1,5 @@ -import { youtubeUtils } from "./utils/youtubeUtils.js"; -import { sleep, lang } from "./utils/utils.js"; +import youtubeUtils from "./utils/youtubeUtils.js"; +import { lang } from "./utils/utils.js"; import { yandexProtobuf } from "./yandexProtobuf.js"; import requestVideoSubtitles from "./rvs.js"; import debug from "./utils/debug.js"; @@ -8,17 +8,17 @@ function formatYandexSubtitlesTokens(line) { const lineEndMs = line.startMs + line.durationMs; return line.tokens.reduce((result, token, index) => { const nextToken = line.tokens[index + 1]; - const lastToken = result[result.length - 1]; + let lastToken; + if (result.length > 0) { + lastToken = result[result.length - 1]; + } const alignRangeEnd = lastToken?.alignRange?.end ?? 0; const newAlignRangeEnd = alignRangeEnd + token.text.length; - result.push( - Object.assign(Object.assign({}, token), { - alignRange: { - start: alignRangeEnd, - end: newAlignRangeEnd, - }, - }), - ); + token.alignRange = { + start: alignRangeEnd, + end: newAlignRangeEnd, + }; + result.push(token); if (nextToken) { const endMs = token.startMs + token.durationMs; const durationMs = nextToken.startMs @@ -39,33 +39,32 @@ function formatYandexSubtitlesTokens(line) { } function createSubtitlesTokens(line, previousLineLastToken) { - const tokens = line.text - .split(new RegExp("([\n \t])")) - .reduce((result, tokenText) => { - if (tokenText.length) { - const lastToken = result[result.length - 1] ?? previousLineLastToken; - const alignRangeStart = lastToken?.alignRange?.end ?? 0; - const alignRangeEnd = alignRangeStart + tokenText.length; - result.push({ - text: tokenText, - alignRange: { - start: alignRangeStart, - end: alignRangeEnd, - }, - }); - } - return result; - }, []); + const tokens = line.text.split(/([\n \t])/).reduce((result, tokenText) => { + if (tokenText.length) { + const lastToken = result[result.length - 1] ?? previousLineLastToken; + const alignRangeStart = lastToken?.alignRange?.end ?? 0; + const alignRangeEnd = alignRangeStart + tokenText.length; + result.push({ + text: tokenText, + alignRange: { + start: alignRangeStart, + end: alignRangeEnd, + }, + }); + } + return result; + }, []); const tokenDurationMs = Math.floor(line.durationMs / tokens.length); const lineEndMs = line.startMs + line.durationMs; return tokens.map((token, index) => { const isLastToken = index === tokens.length - 1; const startMs = line.startMs + tokenDurationMs * index; const durationMs = isLastToken ? lineEndMs - startMs : tokenDurationMs; - return Object.assign(Object.assign({}, token), { + return { + ...token, startMs, durationMs, - }); + }; }); } @@ -86,11 +85,10 @@ function getSubtitlesTokens(subtitles, source) { tokens = createSubtitlesTokens(line, lastToken); } lastToken = tokens[tokens.length - 1]; - result.push( - Object.assign(Object.assign({}, line), { - tokens, - }), - ); + result.push({ + ...line, + tokens, + }); } subtitles.containsTokens = true; return result; @@ -137,17 +135,17 @@ function formatYoutubeSubtitles(subtitles) { export async function fetchSubtitles(subtitlesObject) { let resolved = false; let subtitles = await Promise.race([ - new Promise(async (resolve) => { - await sleep(5000); - if (!resolved) { - console.error("[VOT] Failed to fetch subtitles. Reason: timeout"); - } - resolved = true; - resolve([]); + new Promise((resolve) => { + setTimeout(() => { + if (!resolved) { + console.error("[VOT] Failed to fetch subtitles. Reason: timeout"); + resolve([]); + } + }, 5000); }), - new Promise(async (resolve) => { + new Promise((resolve) => { debug.log("Fetching subtitles:", subtitlesObject); - await fetch(subtitlesObject.url) + fetch(subtitlesObject.url) .then((response) => response.json()) .then((json) => { resolved = true; @@ -176,13 +174,13 @@ export async function getSubtitles(site, videoId, requestLang) { site.host === "youtube" ? youtubeUtils.getSubtitles() : []; let resolved = false; const yaSubtitles = await Promise.race([ - new Promise(async (resolve) => { - await sleep(5000); - if (!resolved) { - console.error("[VOT] Failed get yandex subtitles. Reason: timeout"); - } - resolved = true; - resolve([]); + new Promise((resolve) => { + setTimeout(() => { + if (!resolved) { + console.error("[VOT] Failed get yandex subtitles. Reason: timeout"); + resolve([]); + } + }, 5000); }), new Promise((resolve) => { requestVideoSubtitles( @@ -354,25 +352,22 @@ export class SubtitlesWidget { if (top && bottom) { this.votSubtitlesContainer.style.top = `${y - this.containerRect.y}px`; + } else if (!top) { + this.votSubtitlesContainer.style.top = `${0}px`; } else { - if (!top) { - this.votSubtitlesContainer.style.top = `${0}px`; - } else { - this.votSubtitlesContainer.style.top = `${ - this.containerRect.height - this.subtitlesContainerRect.height - }px`; - } + this.votSubtitlesContainer.style.top = `${ + this.containerRect.height - this.subtitlesContainerRect.height + }px`; } + if (left && right) { this.votSubtitlesContainer.style.left = `${x - this.containerRect.x}px`; + } else if (!left) { + this.votSubtitlesContainer.style.left = `${0}px`; } else { - if (!left) { - this.votSubtitlesContainer.style.left = `${0}px`; - } else { - this.votSubtitlesContainer.style.left = `${ - this.containerRect.width - this.subtitlesContainerRect.width - }px`; - } + this.votSubtitlesContainer.style.left = `${ + this.containerRect.width - this.subtitlesContainerRect.width + }px`; } } } @@ -417,7 +412,7 @@ export class SubtitlesWidget { }); if (line) { if (highlightWords) { - let tokens = line.tokens; + let { tokens } = line; if (tokens.at(-1).alignRange.end > this.maxLength) { let chunks = []; let chunkStartIndex = 0; @@ -443,12 +438,12 @@ export class SubtitlesWidget { } chunkEndIndex = i; } - for (let i = 0; i < chunks.length; i++) { + for (const chunk of chunks) { if ( - chunks[i].startMs < time && - time < chunks[i].startMs + chunks[i].durationMs + chunk.startMs < time && + time < chunk.startMs + chunk.durationMs ) { - tokens = chunks[i].tokens; + tokens = chunk.tokens; break; } } @@ -462,22 +457,20 @@ export class SubtitlesWidget { : "" }>${token.text}`; } - } else { - if (line.text.length > this.maxLength) { - let chunks = line.text.match(this.maxLengthRegexp); - let chunkDurationMs = line.durationMs / chunks.length; - for (let i = 0; i < chunks.length; i++) { - if ( - line.startMs + chunkDurationMs * i < time && - time < line.startMs + chunkDurationMs * (i + 1) - ) { - content = chunks[i].trim(); - break; - } + } else if (line.text.length > this.maxLength) { + let chunks = line.text.match(this.maxLengthRegexp); + let chunkDurationMs = line.durationMs / chunks.length; + for (let i = 0; i < chunks.length; i++) { + if ( + line.startMs + chunkDurationMs * i < time && + time < line.startMs + chunkDurationMs * (i + 1) + ) { + content = chunks[i].trim(); + break; } - } else { - content = line.text; } + } else { + content = line.text; } } if (content !== this.lastContent) { diff --git a/src/utils/VideoObserver.js b/src/utils/VideoObserver.js index 6b8491be..648aced2 100644 --- a/src/utils/VideoObserver.js +++ b/src/utils/VideoObserver.js @@ -1,22 +1,18 @@ import "requestidlecallback-polyfill"; import { EventImpl } from "./EventImpl.js"; -function filterVideoNodes(e) { - return Array.from(e) - .map((e) => { - const result = []; - if (e instanceof HTMLVideoElement) { - result.push(e); - } - if (e instanceof HTMLElement) { - result.push(...Array.from(e.querySelectorAll("video"))); - } - if (e?.shadowRoot?.querySelectorAll) { - result.push(...Array.from(e.shadowRoot.querySelectorAll("video"))); - } - return result; - }) - .flat(); +function filterVideoNodes(nodes) { + return Array.from(nodes).flatMap((node) => { + if (node instanceof HTMLVideoElement) { + return [node]; + } + if (node instanceof HTMLElement) { + return Array.from(node.querySelectorAll("video")); + } + return node.shadowRoot + ? Array.from(node.shadowRoot.querySelectorAll("video")) + : []; + }); } export class VideoObserver { @@ -29,7 +25,7 @@ export class VideoObserver { window.requestIdleCallback( () => { mutationsList.forEach((mutation) => { - if ("childList" !== mutation.type) return; + if (mutation.type !== "childList") return; filterVideoNodes(mutation.addedNodes).forEach( this.handleVideoAddedBound, @@ -39,7 +35,7 @@ export class VideoObserver { ); }); }, - { timeout: 1e3 }, + { timeout: 1000 }, ); }); } @@ -57,6 +53,8 @@ export class VideoObserver { this.onVideoAdded.dispatch(video); } handleVideoRemoved(video) { - document.contains(video) || this.onVideoRemoved.dispatch(video); + if (!document.contains(video)) { + this.onVideoRemoved.dispatch(video); + } } } diff --git a/src/utils/bannedvideoUtils.js b/src/utils/bannedvideoUtils.js new file mode 100644 index 00000000..6ec9a40e --- /dev/null +++ b/src/utils/bannedvideoUtils.js @@ -0,0 +1,64 @@ +import debug from "./debug.js"; + +async function getVideoInfo(videoId) { + return await fetch(`https://api.banned.video/graphql`, { + method: "POST", + body: JSON.stringify({ + operationName: "GetVideo", + query: `query GetVideo($id: String!) { + getVideo(id: $id) { + ...DisplayVideoFields + videoUrl: directUrl + live + } + } + + fragment DisplayVideoFields on Video { + title + description: summary + duration: videoDuration + }`, + variables: { + id: videoId, + }, + }), + headers: { + "User-Agent": "bannedVideoFrontEnd", + "apollographql-client-name": "banned-web", + "apollographql-client-version": "1.3", + "content-type": "application/json", + }, + }) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + data: { + getVideo: {}, + }, + }; + }); +} + +async function getVideoData(videoId) { + const videoData = await getVideoInfo(videoId); + + debug.log("banned.video video data:", videoData); + + const { videoUrl, duration, live, description, title } = + videoData.data.getVideo; + + // TODO: Add detect language from title + description + + return { + url: videoUrl, + duration, + live, + title, + description, + }; +} + +export default { + getVideoData, +}; diff --git a/src/utils/coursehunterUtils.js b/src/utils/coursehunterUtils.js index 2d6030d1..d7e62b40 100644 --- a/src/utils/coursehunterUtils.js +++ b/src/utils/coursehunterUtils.js @@ -29,6 +29,6 @@ async function getVideoData() { }; } -export const coursehunterUtils = { +export default { getVideoData, }; diff --git a/src/utils/courseraUtils.js b/src/utils/courseraUtils.js index 82278c92..e35dd444 100644 --- a/src/utils/courseraUtils.js +++ b/src/utils/courseraUtils.js @@ -93,7 +93,7 @@ async function getVideoData(responseLang = "en") { return videoData; } -export const courseraUtils = { +export default { getPlayer, getPlayerData, getVideoData, diff --git a/src/utils/crypto.js b/src/utils/crypto.js new file mode 100644 index 00000000..8d14109f --- /dev/null +++ b/src/utils/crypto.js @@ -0,0 +1,21 @@ +export async function getHmacSha1(hmacKey, salt) { + const utf8Encoder = new TextEncoder("utf-8"); + salt = utf8Encoder.encode(salt); + + return window.crypto.subtle + .importKey( + "raw", + utf8Encoder.encode(hmacKey), + { name: "HMAC", hash: { name: "SHA-1" } }, + false, + ["sign", "verify"], + ) + .then((key) => window.crypto.subtle.sign("HMAC", key, salt)) + .then((arrayBuffer) => + btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))), + ) + .catch((err) => { + console.error(err); + return false; + }); +} diff --git a/src/utils/storage.js b/src/utils/storage.js index b048fa1c..511bfd80 100644 --- a/src/utils/storage.js +++ b/src/utils/storage.js @@ -28,9 +28,7 @@ export const votStorage = new (class { return await GM_getValue(name, def); } - return new Promise((resolve) => { - resolve(this.syncGet(name, def, toNumber)); - }); + return Promise.resolve(this.syncGet(name, def, toNumber)); } syncSet(name, value) { @@ -50,9 +48,7 @@ export const votStorage = new (class { return await GM_setValue(name, value); } - return new Promise((resolve) => { - resolve(this.syncSet(name, value)); - }); + return Promise.resolve(this.syncSet(name, value)); } syncDelete(name) { @@ -68,9 +64,7 @@ export const votStorage = new (class { return await GM_deleteValue(name); } - return new Promise((resolve) => { - resolve(this.syncDelete(name)); - }); + return Promise.resolve(this.syncDelete(name)); } syncList() { @@ -103,8 +97,6 @@ export const votStorage = new (class { return await GM_listValues(); } - return new Promise((resolve) => { - resolve(this.syncList()); - }); + return Promise.resolve(this.syncList()); } })(); diff --git a/src/utils/udemyUtils.js b/src/utils/udemyUtils.js index 0ff41170..18dc671a 100644 --- a/src/utils/udemyUtils.js +++ b/src/utils/udemyUtils.js @@ -162,7 +162,7 @@ async function getVideoData(udemyData, responseLang = "en") { return videoData; } -export const udemyUtils = { +export default { getPlayer, getPlayerData, getVideoData, diff --git a/src/utils/utils.js b/src/utils/utils.js index 25d97ea6..6a17aec2 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,61 +1,54 @@ import { localizationProvider } from "../localization/localizationProvider.js"; +import youtubeUtils from "./youtubeUtils.js"; const userlang = navigator.language || navigator.userLanguage; export const lang = userlang?.substr(0, 2)?.toLowerCase() ?? "en"; -if (!String.prototype.format) { - // https://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format - // syntax example: "is {0} function".format("format") - String.prototype.format = function () { - // store arguments in an array - var args = arguments; - // use replace to iterate over the string - // select the match and check if the related argument is present - // if yes, replace the match with the argument - return this.replace(/{(\d+)}/g, function (match, index) { - // check if the argument is present - return typeof args[index] != "undefined" ? args[index] : match; - }); - }; -} +// not used +// function waitForElm(selector) { +// // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists +// return new Promise((resolve) => { +// const element = document.querySelector(selector); +// if (element) { +// return resolve(element); +// } -function waitForElm(selector) { - // https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists - return new Promise((resolve) => { - const element = document.querySelector(selector); - if (element) { - return resolve(element); - } +// const observer = new MutationObserver(() => { +// const element = document.querySelector(selector); +// if (element) { +// resolve(element); +// observer.disconnect(); +// } +// }); - const observer = new MutationObserver(() => { - const element = document.querySelector(selector); - if (element) { - resolve(element); - observer.disconnect(); - } - }); +// observer.observe(document.body, { +// childList: true, +// subtree: true, +// once: true, +// }); +// }); +// } - observer.observe(document.body, { - childList: true, - subtree: true, - once: true, - }); - }); -} - -const sleep = (m) => new Promise((r) => setTimeout(r, m)); +// not used +// const sleep = (m) => new Promise((r) => setTimeout(r, m)); const getVideoId = (service, video) => { - const url = new URL(window.location.href); + let url = new URL(window.location.href); switch (service) { case "piped": case "invidious": - case "youtube": + case "youtube": { + if (url.searchParams.has("enablejsapi")) { + const videoUrl = youtubeUtils.getPlayer().getVideoUrl(); + url = new URL(videoUrl); + } + return ( url.pathname.match(/(?:watch|embed|shorts)\/([^/]+)/)?.[1] || url.searchParams.get("v") ); + } case "vk": if (url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)) { return url.pathname.match(/^\/video-?[0-9]{8,9}_[0-9]{9}$/)[0].slice(1); @@ -121,11 +114,14 @@ const getVideoId = (service, video) => { } return id; } - case "vimeo": - return ( + case "vimeo": { + const appId = url.searchParams.get("app_id"); + const videoId = url.pathname.match(/[^/]+\/[^/]+$/)?.[0] || - url.pathname.match(/[^/]+$/)?.[0] - ); + url.pathname.match(/[^/]+$/)?.[0]; + + return appId ? `${videoId}?app_id=${appId}` : videoId; + } case "xvideos": return url.pathname.match(/[^/]+\/[^/]+$/)?.[0]; case "pornhub": @@ -140,17 +136,7 @@ const getVideoId = (service, video) => { case "rumble": return url.pathname; case "facebook": - // ...watch?v=XXX - // CHANNEL_ID/videos/VIDEO_ID/ - // returning "Видео недоступно для перевода" - - // fb.watch/YYY - // returning "Возникла ошибка, попробуйте позже" - if (url.searchParams.get("v")) { - return url.searchParams.get("v"); - } - - return false; + return url.pathname; case "rutube": return url.pathname.match(/(?:video|embed)\/([^/]+)/)?.[1]; case "coub": @@ -201,29 +187,12 @@ const getVideoId = (service, video) => { case "dailymotion": { // we work in the context of the player // geo.dailymotion.com - - const plainPlayerConfig = Array.from(document.scripts).filter((s) => - s.innerText.trim().includes("window.__PLAYER_CONFIG__ = {"), - ); - if (!plainPlayerConfig.length) { - return false; - } - + const plainPlayerConfig = Array.from( + document.querySelectorAll("*"), + ).filter((s) => s.innerHTML.trim().includes(".m3u8")); try { - let clearPlainConfig = plainPlayerConfig[0].innerText - .trim() - .replace("window.__PLAYER_CONFIG__ = ", ""); - if (clearPlainConfig.endsWith("};")) { - clearPlainConfig = clearPlainConfig.substring( - 0, - clearPlainConfig.length - 1, - ); - } - const playerConfig = JSON.parse(clearPlainConfig); - const videoUrl = - playerConfig.context.embedder ?? playerConfig.context.http_referer; - console.log(videoUrl, playerConfig); - return videoUrl.match(/\/video\/([^/]+)/)?.[1]; + let videoUrl = plainPlayerConfig[1].lastChild.src; + return videoUrl.match(/\/video\/(\w+)\.m3u8/)?.[1]; } catch (e) { console.error("[VOT]", e); return false; @@ -247,11 +216,26 @@ const getVideoId = (service, video) => { return `${path}?vid=${vid}`; } case "yandexdisk": - return url.pathname.match(/\/[i|s|d]\/([^/]+)/)?.[1]; + return url.pathname.match(/\/i\/([^/]+)/)?.[1]; case "coursehunter": { const courseId = url.pathname.match(/\/course\/([^/]+)/)?.[1]; return courseId ? courseId + url.search : false; } + case "ok.ru": { + return url.pathname.match(/\/video\/(\d+)/)?.[0]; + } + case "googledrive": + return url.searchParams.get("docid"); + case "bannedvideo": + return url.searchParams.get("id"); + case "weverse": + return url.pathname.match(/([^/]+)\/(live|media)\/([^/]+)/)?.[0]; + case "newgrounds": + return url.pathname.match(/([^/]+)\/(view)\/([^/]+)/)?.[0]; + case "egghead": + return url.pathname; + case "youku": + return url.pathname.match(/v_show\/id_[\w=]+/)?.[0]; default: return false; } @@ -265,16 +249,15 @@ function secsToStrTime(secs) { } else if (minutes >= 10 && minutes % 10) { return localizationProvider .get("translationTakeApproximatelyMinutes") - .format(minutes); + .replace("{0}", minutes); } else if (minutes == 1 || (minutes == 0 && seconds > 0)) { return localizationProvider.get("translationTakeAboutMinute"); } else { return localizationProvider .get("translationTakeApproximatelyMinute") - .format(minutes); + .replace("{0}", minutes); } } - function langTo6391(lang) { // convert lang to ISO 639-1 return lang.toLowerCase().split(";")[0].trim().split("-")[0].split("_")[0]; @@ -296,12 +279,4 @@ function initHls() { : undefined; } -export { - waitForElm, - sleep, - getVideoId, - secsToStrTime, - langTo6391, - isPiPAvailable, - initHls, -}; +export { getVideoId, secsToStrTime, langTo6391, isPiPAvailable, initHls }; diff --git a/src/utils/weverseUtils.js b/src/utils/weverseUtils.js new file mode 100644 index 00000000..889d0dbf --- /dev/null +++ b/src/utils/weverseUtils.js @@ -0,0 +1,155 @@ +import debug from "./debug.js"; +import { getHmacSha1 } from "./crypto.js"; + +const API_ORIGIN = "https://global.apis.naver.com/weverse/wevweb"; // find as REACT_APP_API_GW_ORIGIN in main..js +const API_APP_ID = "be4d79eb8fc7bd008ee82c8ec4ff6fd4"; // find as REACT_APP_API_APP_ID in main..js +const API_HMAC_KEY = "1b9cb6378d959b45714bec49971ade22e6e24e42"; // find as c.active near `createHmac("sha1"...` in main..js + +async function createHash(pathname) { + // pathname example: /post/v1.0/post-3-142049908/preview?fieldSet=postForPreview... + const timestamp = Date.now(); + + let salt = pathname.substring(0, Math.min(255, pathname.length)) + timestamp; + // example salt is /video/v1.1/vod/67134/inKey?gcc=RU&appId=be4d79eb8fc7bd008ee82c8ec4ff6fd4&language=en&os=WEB&platform=WEB&wpf=pc1707527163588 + + const sign = await getHmacSha1(API_HMAC_KEY, salt); + + return { + wmsgpad: timestamp, + wmd: sign, + }; +} + +function getURLData() { + return { + appId: API_APP_ID, + language: "en", + os: "WEB", + platform: "WEB", + wpf: "pc", + }; +} + +async function getVideoPreview(postId) { + const pathname = + `/post/v1.0/post-${postId}/preview?` + + new URLSearchParams({ + fieldSet: "postForPreview", + ...getURLData(), + }); // ! DON'T EDIT ME + + const hash = await createHash(pathname); + + return await fetch(API_ORIGIN + pathname + "&" + new URLSearchParams(hash)) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + extension: { + video: {}, + }, + }; + }); +} + +async function getVideoInKey(videoId) { + const pathname = + `/video/v1.1/vod/${videoId}/inKey?` + + new URLSearchParams({ + gcc: "RU", + ...getURLData(), + }); // ! DON'T EDIT ME + const hash = await createHash(pathname); + + return await fetch(API_ORIGIN + pathname + "&" + new URLSearchParams(hash), { + method: "POST", + }) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return {}; + }); +} + +async function getVideoInfo(infraVideoId, inkey, serviceId) { + const timestamp = Date.now(); + return await fetch( + `https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${infraVideoId}?` + + new URLSearchParams({ + key: inkey, + sid: serviceId, + // pid: "863c411f-fbf0-4b67-868a-ef54427e5316", // возможно не нужен + nonce: timestamp, + devt: "html5_pc", + prv: "N", + aup: "N", + stpb: "N", + cpl: "en", + env: "prod", + lc: "en", + adi: [ + { + adSystem: null, + }, + ], + adu: "/", + }), + ) + .then((res) => res.json()) + .catch((err) => { + console.error(err); + return { + videos: { + list: [], + }, + }; + }); +} + +function extractVideoInfo(videoList) { + return videoList.find( + (video) => video.useP2P === false && video.source.includes(".mp4"), + ); +} + +async function getVideoData() { + // ! When translating using a regular link (like this https://weverse.io/aespa/live/3-142049908), + // ! we will get an error, so we have to do this + + const postId = new URL(window.location).pathname.match( + /([^/]+)\/(live|media)\/([^/]+)/, + )?.[3]; + + const videoPreview = await getVideoPreview(postId); + debug.log("weverse video preview data:", videoPreview); + + const { videoId, serviceId, infraVideoId } = videoPreview.extension.video; + + if (!(videoId && serviceId && infraVideoId)) { + return false; + } + + const { inKey } = await getVideoInKey(videoId); + debug.log("weverse video inKey data:", videoPreview); + if (!inKey) { + return false; + } + + const videoData = await getVideoInfo(infraVideoId, inKey, serviceId); + debug.log("weverse video data:", videoData); + + const videoSource = extractVideoInfo(videoData.videos.list); + if (!videoSource) { + return false; + } + + const { source: url, duration } = videoSource; + return { + url, + duration, + }; +} + +export default { + getVideoData, +}; diff --git a/src/utils/youtubeUtils.js b/src/utils/youtubeUtils.js index 3c8652da..10ebd28e 100644 --- a/src/utils/youtubeUtils.js +++ b/src/utils/youtubeUtils.js @@ -28,15 +28,13 @@ async function getLanguage(player, response, title, description) { } } - // the "delayed video upload" fix for YouTube (#387) - if (!(description && title)) { - return "en"; - } - // If there is no caption track, use detect to get the language code from the description const deletefilter = [ - /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g, // remove links + /(?:https?|ftp):\/\/[\S]+/g, //temp fix + /https?:\/\/\S+|www\.\S+/gm, + /\b\S+\.\S+/gm, + /#[^\s#]+/g, // hash tags /Auto-generated by YouTube/g, /Provided to YouTube by/g, /Released on/g, @@ -48,13 +46,14 @@ async function getLanguage(player, response, title, description) { const cleanedDescription = description .split("\n\n") .filter((line) => !deletefilter.some((regex) => regex.test(line))) - .join("\n\n") + .join("\n\n"); + + const cleanText = [title, cleanedDescription] + .join(" ") .replace(/[^\p{L}\s]/gu, " ") .trim() .replace(/\s+/g, " ") - .slice(0, 250); - - const cleanText = [cleanedDescription, title].join(" "); + .slice(0, 1000); return await detect(cleanText); } @@ -144,7 +143,7 @@ async function getVideoData() { const player = getPlayer(); const response = getPlayerResponse(); // null in /embed const data = getPlayerData(); - const { author, title } = data ?? {}; + const { title } = data ?? {}; const { shortDescription: description, isLive, @@ -157,7 +156,6 @@ async function getVideoData() { response, title, description, - author, ); if (!availableLangs.includes(detectedLanguage)) { detectedLanguage = "en"; @@ -167,7 +165,6 @@ async function getVideoData() { isPremiere, title, description, - author, detectedLanguage, }; debug.log("youtube video data:", videoData); @@ -175,7 +172,7 @@ async function getVideoData() { return videoData; } -export const youtubeUtils = { +export default { isMobile, getPlayer, getPlayerResponse, diff --git a/webpack.config.js b/webpack.config.js index 94da4c5a..3b2d43bf 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,31 +4,30 @@ import { fileURLToPath } from "url"; import webpack from "webpack"; -import { UserscriptPlugin } from "webpack-userscript"; +import { monkey } from "webpack-monkey"; +import { styleLoaderInsertStyleElement } from "webpack-monkey/lib/client/css.js"; import ESLintPlugin from "eslint-webpack-plugin"; -// const ESLintPlugin = require('eslint-webpack-plugin'); +import TerserPlugin from "terser-webpack-plugin"; const repo = "https://raw.githubusercontent.com/ilyhalight/voice-over-translation"; const dev = process.env.NODE_ENV === "development"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -let isBeta = getHeaders("headers.json").version.includes("beta"); +let isBeta = getHeaders().version.includes("beta"); console.log("development mode: ", dev); -function getHeaders(file) { - const headersPath = path.resolve(__dirname, "src", file); +function getHeaders(lang) { + const headersPath = path.resolve( + __dirname, + "src", + lang ? `locales/${lang}` : "", + "headers.json", + ); return JSON.parse(fs.readFileSync(headersPath).toString()); } -const ru_headers = getHeaders("locales/ru/headers.json"); -const zh_headers = getHeaders("locales/zh/headers.json"); -const de_headers = getHeaders("locales/de/headers.json"); -const es_headers = getHeaders("locales/es/headers.json"); -const fr_headers = getHeaders("locales/fr/headers.json"); -const it_headers = getHeaders("locales/it/headers.json"); - export default (env) => { const build_mode = env.build_mode; const build_type = env.build_type; @@ -45,7 +44,7 @@ export default (env) => { name += "-min"; } - return name + ".js"; + return name + ".user.js"; } function get_name_by_build_mode(name) { @@ -54,13 +53,10 @@ export default (env) => { ? name.replace("[VOT]", "[VOT Cloudflare]") : name; - if (dev) { - finalName = "[DEBUG] " + finalName; - } return finalName; } - return { + return monkey({ mode: dev ? "development" : "production", resolve: { extensions: [".js"], @@ -73,100 +69,72 @@ export default (env) => { entry: path.resolve(__dirname, "src", "index.js"), output: { path: path.resolve(__dirname, "dist"), - filename: get_filename(), - publicPath: "/", - }, - devServer: { - server: "http", - port: 11945, - allowedHosts: "all", - hot: true, - liveReload: false, - magicHtml: false, - headers: { - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Headers": "*", - }, - // client: { - // webSocketURL: "ws://localhost:11944/ws", - // progress: true, - // reconnect: false - // }, - client: false, + ...(() => { + if (!dev) { + return { filename: get_filename() }; + } + })(), }, - plugins: [ - new ESLintPlugin(), - new webpack.optimize.LimitChunkCountPlugin({ - maxChunks: 1, - }), - new UserscriptPlugin({ - headers: async () => { - const headers = getHeaders("headers.json"); - - let version = headers.version; - - const extFileName = get_filename().slice(0, -3); + monkey: { + debug: dev, + meta: { + resolve: "headers.json", + transform({ meta }) { + const extFileName = get_filename().slice(0, -8); const finalURL = `${repo}/${ isBeta ? "dev" : "master" }/dist/${extFileName}.user.js`; - headers["namespace"] = extFileName; - headers["updateURL"] = finalURL; - headers["downloadURL"] = finalURL; + + meta.namespace = extFileName; + meta.updateURL = meta.downloadURL = finalURL; if (build_mode === "cloudflare") { - headers["name"] = "[VOT Cloudflare] - Voice Over Translation"; - headers["inject-into"] = "page"; + meta.name = meta.name.replace("[VOT]", "[VOT Cloudflare]"); + meta["inject-into"] = "page"; } - if (dev) { - headers["version"] = `${version}-build.[buildNo]`; - headers["name"] = "[DEBUG] " + headers["name"]; + const files = fs.readdirSync( + path.resolve(__dirname, "src", "locales"), + ); + + meta.name = { + default: meta.name, + }; + + meta.description = { + default: meta.description, + }; + + for (const file of files) { + const localeHeaders = getHeaders(file); + const lang = file.substring(0, 2); + + meta.name[lang] = get_name_by_build_mode(localeHeaders.name); + meta.description[lang] = localeHeaders.description; } - return headers; + return meta; }, - proxyScript: { - filename: "[basename].proxy.user.js", - baseURL: "http://localhost:11945/", - }, - i18n: { - ru: (headers) => ({ - ...headers, - name: get_name_by_build_mode(ru_headers["name"]), - description: ru_headers["description"], - }), - zh: (headers) => ({ - ...headers, - name: get_name_by_build_mode(zh_headers["name"]), - description: zh_headers["description"], - }), - de: (headers) => ({ - ...headers, - name: get_name_by_build_mode(de_headers["name"]), - description: de_headers["description"], - }), - es: (headers) => ({ - ...headers, - name: get_name_by_build_mode(es_headers["name"]), - description: es_headers["description"], - }), - fr: (headers) => ({ - ...headers, - name: get_name_by_build_mode(fr_headers["name"]), - description: fr_headers["description"], - }), - it: (headers) => ({ - ...headers, - name: get_name_by_build_mode(it_headers["name"]), - description: it_headers["description"], - }), - }, - strict: true, + }, + }, + plugins: [ + new ESLintPlugin(), + new webpack.optimize.LimitChunkCountPlugin({ + maxChunks: 1, }), new webpack.DefinePlugin({ BUILD_MODE: JSON.stringify(build_mode), DEBUG_MODE: dev, IS_BETA_VERSION: isBeta, + ...(() => { + if (!dev) { + return { + __MK_GLOBAL__: { + styleLoaderInsertStyleElement, + }, + }; + } + })(), }), ], module: { @@ -181,6 +149,7 @@ export default (env) => { emitOnErrors: true, moduleIds: "named", minimize: build_type === "minify" ? true : false, + minimizer: [new TerserPlugin()], }, - }; + }); };