diff --git a/bun.lock b/bun.lock index feeb36ee..b9594a9a 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,7 @@ "@vot.js/shared": "^2.4.12", "bowser": "^2.14.1", "chaimu": "^1.0.6", + "lit": "^3.3.2", "lit-html": "^3.3.2", }, "devDependencies": { @@ -17,12 +18,11 @@ "@types/bun": "^1.3.11", "@vot.js/core": "^2.4.12", "crx3": "^2.0.0", - "lefthook": "^2.1.4", "lightningcss": "^1.32.0", "npm-run-all2": "^8.0.4", - "sass": "^1.98.0", - "typescript": "^5.9.3", - "vite": "^8.0.1", + "sass": "^1.99.0", + "typescript": "^6.0.2", + "vite": "^8.0.5", "zip-a-folder": "^6.1.0", }, }, @@ -36,45 +36,49 @@ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], + "@lit-labs/ssr-dom-shim": ["@lit-labs/ssr-dom-shim@1.5.1", "", {}, "sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA=="], + + "@lit/reactive-element": ["@lit/reactive-element@2.1.2", "", { "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0" } }, "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="], - "@oxc-project/types": ["@oxc-project/types@0.120.0", "", {}, "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg=="], + "@oxc-project/types": ["@oxc-project/types@0.122.0", "", {}, "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA=="], "@parcel/watcher": ["@parcel/watcher@2.5.0", "", { "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", "micromatch": "^4.0.5", "node-addon-api": "^7.0.0" }, "optionalDependencies": { "@parcel/watcher-win32-x64": "2.5.0" } }, ""], "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.0", "", { "os": "win32", "cpu": "x64" }, ""], - "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.10", "", { "os": "android", "cpu": "arm64" }, "sha512-jOHxwXhxmFKuXztiu1ORieJeTbx5vrTkcOkkkn2d35726+iwhrY1w/+nYY/AGgF12thg33qC3R1LMBF5tHTZHg=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.12", "", { "os": "android", "cpu": "arm64" }, "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA=="], - "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-gED05Teg/vtTZbIJBc4VNMAxAFDUPkuO/rAIyyxZjTj1a1/s6z5TII/5yMGZ0uLRCifEtwUQn8OlYzuYc0m70w=="], + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg=="], - "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-rI15NcM1mA48lqrIxVkHfAqcyFLcQwyXWThy+BQ5+mkKKPvSO26ir+ZDp36AgYoYVkqvMcdS8zOE6SeBsR9e8A=="], + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw=="], - "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-XZRXHdTa+4ME1MuDVp021+doQ+z6Ei4CCFmNc5/sKbqb8YmkiJdj8QKlV3rCI0AJtAeSB5n0WGPuJWNL9p/L2w=="], + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q=="], - "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.10", "", { "os": "linux", "cpu": "arm" }, "sha512-R0SQMRluISSLzFE20sPWYHVmJdDQnRyc/FzSCN72BqQmh2SOZUFG+N3/vBZpR4C6WpEUVYJLrYUXaj43sJsNLA=="], + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.12", "", { "os": "linux", "cpu": "arm" }, "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q=="], - "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y1reMrV/o+cwpduYhJuOE3OMKx32RMYCidf14y+HssARRmhDuWXJ4yVguDg2R/8SyyGNo+auzz64LnPK9Hq6jg=="], + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg=="], - "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-vELN+HNb2IzuzSBUOD4NHmP9yrGwl1DVM29wlQvx1OLSclL0NgVWnVDKl/8tEks79EFek/kebQKnNJkIAA4W2g=="], + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw=="], - "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ZqrufYTgzxbHwpqOjzSsb0UV/aV2TFIY5rP8HdsiPTv/CuAgCRjM6s9cYFwQ4CNH+hf9Y4erHW1GjZuZ7WoI7w=="], + "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g=="], - "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-gSlmVS1FZJSRicA6IyjoRoKAFK7IIHBs7xJuHRSmjImqk3mPPWbR7RhbnfH2G6bcmMEllCt2vQ/7u9e6bBnByg=="], + "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og=="], - "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.10", "", { "os": "linux", "cpu": "x64" }, "sha512-eOCKUpluKgfObT2pHjztnaWEIbUabWzk3qPZ5PuacuPmr4+JtQG4k2vGTY0H15edaTnicgU428XW/IH6AimcQw=="], + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.12", "", { "os": "linux", "cpu": "x64" }, "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg=="], - "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.10", "", { "os": "linux", "cpu": "x64" }, "sha512-Xdf2jQbfQowJnLcgYfD/m0Uu0Qj5OdxKallD78/IPPfzaiaI4KRAwZzHcKQ4ig1gtg1SuzC7jovNiM2TzQsBXA=="], + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.12", "", { "os": "linux", "cpu": "x64" }, "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig=="], - "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.10", "", { "os": "none", "cpu": "arm64" }, "sha512-o1hYe8hLi1EY6jgPFyxQgQ1wcycX+qz8eEbVmot2hFkgUzPxy9+kF0u0NIQBeDq+Mko47AkaFFaChcvZa9UX9Q=="], + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.12", "", { "os": "none", "cpu": "arm64" }, "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA=="], - "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.10", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-Ugv9o7qYJudqQO5Y5y2N2SOo6S4WiqiNOpuQyoPInnhVzCY+wi/GHltcLHypG9DEUYMB0iTB/huJrpadiAcNcA=="], + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.12", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg=="], - "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-7UODQb4fQUNT/vmgDZBl3XOBAIOutP5R3O/rkxg0aLfEGQ4opbCgU5vOw/scPe4xOqBwL9fw7/RP1vAMZ6QlAQ=="], + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q=="], - "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.10", "", { "os": "win32", "cpu": "x64" }, "sha512-PYxKHMVHOb5NJuDL53vBUl1VwUjymDcYI6rzpIni0C9+9mTiJedvUxSk7/RPp7OOAm3v+EjgMu9bIy3N6b408w=="], + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.12", "", { "os": "win32", "cpu": "x64" }, "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw=="], - "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.10", "", {}, "sha512-UkVDEFk1w3mveXeKgaTuYfKWtPbvgck1dT8TUG3bnccrH0XtLTuAyfCoks4Q/M5ZGToSVJTIQYCzy2g/atAOeg=="], + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.12", "", {}, "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw=="], "@toil/gm-types": ["@toil/gm-types@1.0.4", "", { "peerDependencies": { "typescript": "^5.8.2" } }, "sha512-DbqZsYYrVXaBB4usDN3/HbkIhk2M+ECKv06lEScSoCMJUZ1qbtpbYLIqioEk2GE9adwWjNpH+y/Bf0ij3wQxhw=="], @@ -132,28 +136,6 @@ "json-parse-even-better-errors": ["json-parse-even-better-errors@4.0.0", "", {}, "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA=="], - "lefthook": ["lefthook@2.1.4", "", { "optionalDependencies": { "lefthook-darwin-arm64": "2.1.4", "lefthook-darwin-x64": "2.1.4", "lefthook-freebsd-arm64": "2.1.4", "lefthook-freebsd-x64": "2.1.4", "lefthook-linux-arm64": "2.1.4", "lefthook-linux-x64": "2.1.4", "lefthook-openbsd-arm64": "2.1.4", "lefthook-openbsd-x64": "2.1.4", "lefthook-windows-arm64": "2.1.4", "lefthook-windows-x64": "2.1.4" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-JNfJ5gAn0KADvJ1I6/xMcx70+/6TL6U9gqGkKvPw5RNMfatC7jIg0Evl97HN846xmfz959BV70l8r3QsBJk30w=="], - - "lefthook-darwin-arm64": ["lefthook-darwin-arm64@2.1.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BUAAE9+rUrjr39a+wH/1zHmGrDdwUQ2Yq/z6BQbM/yUb9qtXBRcQ5eOXxApqWW177VhGBpX31aqIlfAZ5Q7wzw=="], - - "lefthook-darwin-x64": ["lefthook-darwin-x64@2.1.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-K1ncIMEe84fe+ss1hQNO7rIvqiKy2TJvTFpkypvqFodT7mJXZn7GLKYTIXdIuyPAYthRa9DwFnx5uMoHwD2F1Q=="], - - "lefthook-freebsd-arm64": ["lefthook-freebsd-arm64@2.1.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-PVUhjOhVN71YaYsVdQyNbFZ4a2jFB2Tg5hKrrn9kaWpx64aLz/XivLjwr8sEuTaP1GRlEWBpW6Bhrcsyo39qFw=="], - - "lefthook-freebsd-x64": ["lefthook-freebsd-x64@2.1.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ZWV9o/LeyWNEBoVO+BhLqxH3rGTba05nkm5NvMjEFSj7LbUNUDbQmupZwtHl1OMGJO66eZP0CalzRfUH6GhBxQ=="], - - "lefthook-linux-arm64": ["lefthook-linux-arm64@2.1.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-iWN0pGnTjrIvNIcSI1vQBJXUbybTqJ5CLMniPA0olabMXQfPDrdMKVQe+mgdwHK+E3/Y0H0ZNL3lnOj6Sk6szA=="], - - "lefthook-linux-x64": ["lefthook-linux-x64@2.1.4", "", { "os": "linux", "cpu": "x64" }, "sha512-96bTBE/JdYgqWYAJDh+/e/0MaxJ25XTOAk7iy/fKoZ1ugf6S0W9bEFbnCFNooXOcxNVTan5xWKfcjJmPIKtsJA=="], - - "lefthook-openbsd-arm64": ["lefthook-openbsd-arm64@2.1.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-oYUoK6AIJNEr9lUSpIMj6g7sWzotvtc3ryw7yoOyQM6uqmEduw73URV/qGoUcm4nqqmR93ZalZwR2r3Gd61zvw=="], - - "lefthook-openbsd-x64": ["lefthook-openbsd-x64@2.1.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/Dv9Jcm68y9cggr1PhyUhOabBGP9+hzQPoiyOhKks7y9qrJl79A8XfG6LHekSuYc2VpiSu5wdnnrE1cj2nfTg=="], - - "lefthook-windows-arm64": ["lefthook-windows-arm64@2.1.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-hSww7z+QX4YMnw2lK7DMrs3+w7NtxksuMKOkCKGyxUAC/0m1LAICo0ZbtdDtZ7agxRQQQ/SEbzFRhU5ysNcbjA=="], - - "lefthook-windows-x64": ["lefthook-windows-x64@2.1.4", "", { "os": "win32", "cpu": "x64" }, "sha512-eE68LwnogxwcPgGsbVGPGxmghyMGmU9SdGwcc+uhGnUxPz1jL89oECMWJNc36zjVK24umNeDAzB5KA3lw1MuWw=="], - "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], @@ -178,6 +160,10 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + "lit": ["lit@3.3.2", "", { "dependencies": { "@lit/reactive-element": "^2.1.0", "lit-element": "^4.2.0", "lit-html": "^3.3.0" } }, "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ=="], + + "lit-element": ["lit-element@4.2.2", "", { "dependencies": { "@lit-labs/ssr-dom-shim": "^1.5.0", "@lit/reactive-element": "^2.1.0", "lit-html": "^3.3.0" } }, "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w=="], + "lit-html": ["lit-html@3.3.2", "", { "dependencies": { "@types/trusted-types": "^2.0.2" } }, "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw=="], "lzma": ["lzma@2.3.2", "", { "bin": { "lzma.js": "bin/lzma.js" } }, "sha512-DcfiawQ1avYbW+hsILhF38IKAlnguc/fjHrychs9hdxe4qLykvhT5VTGNs5YRWgaNePh7NTxGD4uv4gKsRomCQ=="], @@ -216,9 +202,9 @@ "resolve-protobuf-schema": ["resolve-protobuf-schema@2.1.0", "", { "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ=="], - "rolldown": ["rolldown@1.0.0-rc.10", "", { "dependencies": { "@oxc-project/types": "=0.120.0", "@rolldown/pluginutils": "1.0.0-rc.10" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.10", "@rolldown/binding-darwin-arm64": "1.0.0-rc.10", "@rolldown/binding-darwin-x64": "1.0.0-rc.10", "@rolldown/binding-freebsd-x64": "1.0.0-rc.10", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.10", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.10", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.10", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.10", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.10", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.10", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.10", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.10", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.10", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.10", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.10" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-q7j6vvarRFmKpgJUT8HCAUljkgzEp4LAhPlJUvQhA5LA1SUL36s5QCysMutErzL3EbNOZOkoziSx9iZC4FddKA=="], + "rolldown": ["rolldown@1.0.0-rc.12", "", { "dependencies": { "@oxc-project/types": "=0.122.0", "@rolldown/pluginutils": "1.0.0-rc.12" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-x64": "1.0.0-rc.12", "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A=="], - "sass": ["sass@1.98.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A=="], + "sass": ["sass@1.99.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, ""], @@ -234,11 +220,11 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], "undici-types": ["undici-types@5.26.5", "", {}, ""], - "vite": ["vite@8.0.1", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.3", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.10", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-wt+Z2qIhfFt85uiyRt5LPU4oVEJBXj8hZNWKeqFG4gRG/0RaRGJ7njQCwzFVjO+v4+Ipmf5CY7VdmZRAYYBPHw=="], + "vite": ["vite@8.0.5", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.12", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-nmu43Qvq9UopTRfMx2jOYW5l16pb3iDC1JH6yMuPkpVbzK0k+L7dfsEDH4jRgYFmsg0sTAqkojoZgzLMlwHsCQ=="], "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], @@ -252,6 +238,8 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, ""], + "vite/picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, ""], } } diff --git a/changelog.md b/changelog.md index 6af3197d..d7fdcffc 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,19 @@ -# 1.11.4 +# 1.11.5 + +- Переписан механизм монтирования UI. +- Упрощена логика загрзуки аудио. +- Исправлено получение субтитров на VKVideo (#1424) +- Исправлена загрузка аудио на мобильных устройствах (#1646) +- Улучшена/исправлена работа archive.org (#1636) +- Исправлена работа Coursehunter (#1476) +- Исправлена работа /d/ для Яндекс Диска (#1572) +- Исправлена работа Reddit (#1613) +- Исправлена работа Odysee (#1643) +- Исправлена работа YouTube Embed (#1637) +- Исправлена логика автоматического включения проксирования (#1638) +- Обновлены зависимости и проведена оптимизация/очистка кода + +# 1.11.4 - Добавлена поддержка Mediafile Cloud (#1603), Jove (#1593), Datacamp (#1606), PreserveTube (#1366) - Добавлена настройка "Язык субтитров по умолчанию": можно выбрать автоопределение, язык оригинального видео или конкретный язык diff --git a/dist-ext/vot-extension-chrome-1.11.5.zip b/dist-ext/vot-extension-chrome-1.11.5.zip new file mode 100644 index 00000000..ec6b8de2 Binary files /dev/null and b/dist-ext/vot-extension-chrome-1.11.5.zip differ diff --git a/dist-ext/vot-extension-firefox-1.11.5.xpi b/dist-ext/vot-extension-firefox-1.11.5.xpi new file mode 100644 index 00000000..45863bb3 Binary files /dev/null and b/dist-ext/vot-extension-firefox-1.11.5.xpi differ diff --git a/dist-ext/vot-extension-firefox-updates.json b/dist-ext/vot-extension-firefox-updates.json index 9b5a1113..91bbc105 100644 --- a/dist-ext/vot-extension-firefox-updates.json +++ b/dist-ext/vot-extension-firefox-updates.json @@ -3,8 +3,13 @@ "vot-extension@firefox": { "updates": [ { +<<<<<<< Updated upstream "version": "1.11.4", "update_link": "https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist-ext/vot-extension-firefox-1.11.4.xpi" +======= + "version": "1.11.5", + "update_link": "https://raw.githubusercontent.com/ilyhalight/voice-over-translation/master/dist-ext/vot-extension-firefox-1.11.5.xpi" +>>>>>>> Stashed changes } ] } diff --git a/dist/vot-min.user.js b/dist/vot-min.user.js index 4de3bd46..3bb64d80 100644 --- a/dist/vot-min.user.js +++ b/dist/vot-min.user.js @@ -7,7 +7,11 @@ // @name:ru [VOT] - Закадровый перевод видео // @name:zh [VOT] - 画外音视频翻译 // @namespace vot +<<<<<<< Updated upstream // @version 1.11.4 +======= +// @version 1.11.5 +>>>>>>> Stashed changes // @author Toil, SashaXser, MrSoczekXD, mynovelhost, sodapng // @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 @@ -91,9 +95,7 @@ // @match *://*.archive.org/* // @match *://*.patreon.com/* // @match *://*.reddit.com/* -// @match *://*.kodik.info/* -// @match *://*.kodik.biz/* -// @match *://*.kodik.cc/* +// @match *://*.kodikplayer.com/* // @match *://*.kick.com/* // @match *://developer.apple.com/* // @match *://dev.epicgames.com/* @@ -246,7 +248,11 @@ // @grant window.focus // ==/UserScript== +<<<<<<< Updated upstream var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t)=>()=>(e&&(t=e(e=0)),t),c=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),l=(e,t)=>{let r={};for(var i in e)n(r,i,{get:e[i],enumerable:!0});return t||n(r,Symbol.toStringTag,{value:`Module`}),r},u=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;lt[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},d=(e,r,i)=>(i=e==null?{}:t(a(e)),u(r||!e||!e.__esModule?n(i,`default`,{value:e,enumerable:!0}):i,e)),f={host:`api.browser.yandex.ru`,hostVOT:`vot.toil.cc/v1`,hostWorker:`vot-worker.toil.cc`,mediaProxy:`media-proxy.toil.cc`,userAgent:` Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 YaBrowser/26.3.1.981 Yowser/2.5 Safari/537.36`,componentVersion:`26.3.1.981`,hmac:`bt8xH3VOlb4mqf0nqAibnDOoiPlXsisf`,defaultDuration:310,minChunkSize:5295308,loggerLevel:1,version:`2.4.16`};function p(){let e=0,t=0;for(let n=0;n<28;n+=7){let r=this.buf[this.pos++];if(e|=(r&127)<>4,!(n&128))return this.assertBounds(),[e,t];for(let n=3;n<=31;n+=7){let r=this.buf[this.pos++];if(t|=(r&127)<>>r,a=!(!(i>>>7)&&t==0),o=(a?i|128:i)&255;if(n.push(o),!a)return}let r=e>>>28&15|(t&7)<<4,i=!!(t>>3);if(n.push((i?r|128:r)&255),i){for(let e=3;e<31;e+=7){let r=t>>>e,i=!!(r>>>7),a=(i?r|128:r)&255;if(n.push(a),!i)return}n.push(t>>>31&1)}}var h=4294967296;function g(e){let t=e[0]===`-`;t&&(e=e.slice(1));let n=1e6,r=0,i=0;function a(t,a){let o=Number(e.slice(t,a));i*=n,r=r*n+o,r>=h&&(i+=r/h|0,r%=h)}return a(-24,-18),a(-18,-12),a(-12,-6),a(-6),t?ne(r,i):te(r,i)}function _(e,t){let n=te(e,t),r=n.hi&2147483648;r&&(n=ne(n.lo,n.hi));let i=v(n.lo,n.hi);return r?`-`+i:i}function v(e,t){if({lo:e,hi:t}=ee(e,t),t<=2097151)return String(h*t+e);let n=e&16777215,r=(e>>>24|t<<8)&16777215,i=t>>16&65535,a=n+r*6777216+i*6710656,o=r+i*8147497,s=i*2,c=1e7;return a>=c&&(o+=Math.floor(a/c),a%=c),o>=c&&(s+=Math.floor(o/c),o%=c),s.toString()+re(o)+re(a)}function ee(e,t){return{lo:e>>>0,hi:t>>>0}}function te(e,t){return{lo:e|0,hi:t|0}}function ne(e,t){return t=~t,e?e=~e+1:t+=1,te(e,t)}var re=e=>{let t=String(e);return`0000000`.slice(t.length)+t};function ie(e,t){if(e>=0){for(;e>127;)t.push(e&127|128),e>>>=7;t.push(e)}else{for(let n=0;n<9;n++)t.push(e&127|128),e>>=7;t.push(1)}}function ae(){let e=this.buf[this.pos++],t=e&127;if(!(e&128)||(e=this.buf[this.pos++],t|=(e&127)<<7,!(e&128))||(e=this.buf[this.pos++],t|=(e&127)<<14,!(e&128))||(e=this.buf[this.pos++],t|=(e&127)<<21,!(e&128)))return this.assertBounds(),t;e=this.buf[this.pos++],t|=(e&15)<<28;for(let t=5;e&128&&t<10;t++)e=this.buf[this.pos++];if(e&128)throw Error(`invalid varint`);return this.assertBounds(),t>>>0}var y=oe();function oe(){let e=new DataView(new ArrayBuffer(8));if(typeof BigInt==`function`&&typeof e.getBigInt64==`function`&&typeof e.getBigUint64==`function`&&typeof e.setBigInt64==`function`&&typeof e.setBigUint64==`function`&&(typeof process!=`object`||typeof process.env!=`object`||process.env.BUF_BIGINT_DISABLE!==`1`)){let t=BigInt(`-9223372036854775808`),n=BigInt(`9223372036854775807`),r=BigInt(`0`),i=BigInt(`18446744073709551615`);return{zero:BigInt(0),supported:!0,parse(e){let r=typeof e==`bigint`?e:BigInt(e);if(r>n||ri||t>>0)}raw(e){return this.buf.length&&(this.chunks.push(new Uint8Array(this.buf)),this.buf=[]),this.chunks.push(e),this}uint32(e){for(pe(e);e>127;)this.buf.push(e&127|128),e>>>=7;return this.buf.push(e),this}int32(e){return fe(e),ie(e,this.buf),this}bool(e){return this.buf.push(e?1:0),this}bytes(e){return this.uint32(e.byteLength),this.raw(e)}string(e){let t=this.encodeUtf8(e);return this.uint32(t.byteLength),this.raw(t)}float(e){me(e);let t=new Uint8Array(4);return new DataView(t.buffer).setFloat32(0,e,!0),this.raw(t)}double(e){let t=new Uint8Array(8);return new DataView(t.buffer).setFloat64(0,e,!0),this.raw(t)}fixed32(e){pe(e);let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!0),this.raw(t)}sfixed32(e){fe(e);let t=new Uint8Array(4);return new DataView(t.buffer).setInt32(0,e,!0),this.raw(t)}sint32(e){return fe(e),e=(e<<1^e>>31)>>>0,ie(e,this.buf),this}sfixed64(e){let t=new Uint8Array(8),n=new DataView(t.buffer),r=y.enc(e);return n.setInt32(0,r.lo,!0),n.setInt32(4,r.hi,!0),this.raw(t)}fixed64(e){let t=new Uint8Array(8),n=new DataView(t.buffer),r=y.uEnc(e);return n.setInt32(0,r.lo,!0),n.setInt32(4,r.hi,!0),this.raw(t)}int64(e){let t=y.enc(e);return m(t.lo,t.hi,this.buf),this}sint64(e){let t=y.enc(e),n=t.hi>>31;return m(t.lo<<1^n,(t.hi<<1|t.lo>>>31)^n,this.buf),this}uint64(e){let t=y.uEnc(e);return m(t.lo,t.hi,this.buf),this}},x=class{constructor(e,t=ue().decodeUtf8){this.decodeUtf8=t,this.varint64=p,this.uint32=ae,this.buf=e,this.len=e.length,this.pos=0,this.view=new DataView(e.buffer,e.byteOffset,e.byteLength)}tag(){let e=this.uint32(),t=e>>>3,n=e&7;if(t<=0||n<0||n>5)throw Error(`illegal tag: field no `+t+` wire type `+n);return[t,n]}skip(e,t){let n=this.pos;switch(e){case de.Varint:for(;this.buf[this.pos++]&128;);break;case de.Bit64:this.pos+=4;case de.Bit32:this.pos+=4;break;case de.LengthDelimited:let n=this.uint32();this.pos+=n;break;case de.StartGroup:for(;;){let[e,n]=this.tag();if(n===de.EndGroup){if(t!==void 0&&e!==t)throw Error(`invalid end group tag`);break}this.skip(n,e)}break;default:throw Error(`cant skip wire type `+e)}return this.assertBounds(),this.buf.subarray(n,this.pos)}assertBounds(){if(this.pos>this.len)throw RangeError(`premature EOF`)}int32(){return this.uint32()|0}sint32(){let e=this.uint32();return e>>>1^-(e&1)}int64(){return y.dec(...this.varint64())}uint64(){return y.uDec(...this.varint64())}sint64(){let[e,t]=this.varint64(),n=-(e&1);return e=(e>>>1|(t&1)<<31)^n,t=t>>>1^n,y.dec(e,t)}bool(){let[e,t]=this.varint64();return e!==0||t!==0}fixed32(){return this.view.getUint32((this.pos+=4)-4,!0)}sfixed32(){return this.view.getInt32((this.pos+=4)-4,!0)}fixed64(){return y.uDec(this.sfixed32(),this.sfixed32())}sfixed64(){return y.dec(this.sfixed32(),this.sfixed32())}float(){return this.view.getFloat32((this.pos+=4)-4,!0)}double(){return this.view.getFloat64((this.pos+=8)-8,!0)}bytes(){let e=this.uint32(),t=this.pos;return this.pos+=e,this.assertBounds(),this.buf.subarray(t,t+e)}string(){return this.decodeUtf8(this.bytes())}};function fe(e){if(typeof e==`string`)e=Number(e);else if(typeof e!=`number`)throw Error(`invalid int32: `+typeof e);if(!Number.isInteger(e)||e>2147483647||e<-2147483648)throw Error(`invalid int32: `+e)}function pe(e){if(typeof e==`string`)e=Number(e);else if(typeof e!=`number`)throw Error(`invalid uint32: `+typeof e);if(!Number.isInteger(e)||e>4294967295||e<0)throw Error(`invalid uint32: `+e)}function me(e){if(typeof e==`string`){let t=e;if(e=Number(e),isNaN(e)&&t!==`NaN`)throw Error(`invalid float32: `+t)}else if(typeof e!=`number`)throw Error(`invalid float32: `+typeof e);if(Number.isFinite(e)&&(e>34028234663852886e22||e<-34028234663852886e22))throw Error(`invalid float32: `+e)}var S;(function(e){e[e.NO_CONNECTION=0]=`NO_CONNECTION`,e[e.TRANSLATING=10]=`TRANSLATING`,e[e.STREAMING=20]=`STREAMING`,e[e.UNRECOGNIZED=-1]=`UNRECOGNIZED`})(S||={});function he(e){switch(e){case 0:case`NO_CONNECTION`:return S.NO_CONNECTION;case 10:case`TRANSLATING`:return S.TRANSLATING;case 20:case`STREAMING`:return S.STREAMING;default:return S.UNRECOGNIZED}}function ge(e){switch(e){case S.NO_CONNECTION:return`NO_CONNECTION`;case S.TRANSLATING:return`TRANSLATING`;case S.STREAMING:return`STREAMING`;case S.UNRECOGNIZED:default:return`UNRECOGNIZED`}}function _e(){return{target:``,targetUrl:``}}var ve={encode(e,t=new b){return e.target!==``&&t.uint32(10).string(e.target),e.targetUrl!==``&&t.uint32(18).string(e.targetUrl),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=_e();for(;n.pos>>3){case 1:if(e!==10)break;i.target=n.string();continue;case 2:if(e!==18)break;i.targetUrl=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{target:w(e.target)?globalThis.String(e.target):``,targetUrl:w(e.targetUrl)?globalThis.String(e.targetUrl):``}},toJSON(e){let t={};return e.target!==``&&(t.target=e.target),e.targetUrl!==``&&(t.targetUrl=e.targetUrl),t},create(e){return ve.fromPartial(e??{})},fromPartial(e){let t=_e();return t.target=e.target??``,t.targetUrl=e.targetUrl??``,t}};function ye(){return{url:``,deviceId:void 0,firstRequest:!1,duration:0,unknown0:0,language:``,forceSourceLang:!1,unknown1:0,translationHelp:[],wasStream:!1,responseLanguage:``,unknown2:0,unknown3:0,bypassCache:!1,useLivelyVoice:!1,videoTitle:``}}var be={encode(e,t=new b){e.url!==``&&t.uint32(26).string(e.url),e.deviceId!==void 0&&t.uint32(34).string(e.deviceId),e.firstRequest!==!1&&t.uint32(40).bool(e.firstRequest),e.duration!==0&&t.uint32(49).double(e.duration),e.unknown0!==0&&t.uint32(56).int32(e.unknown0),e.language!==``&&t.uint32(66).string(e.language),e.forceSourceLang!==!1&&t.uint32(72).bool(e.forceSourceLang),e.unknown1!==0&&t.uint32(80).int32(e.unknown1);for(let n of e.translationHelp)ve.encode(n,t.uint32(90).fork()).join();return e.wasStream!==!1&&t.uint32(104).bool(e.wasStream),e.responseLanguage!==``&&t.uint32(114).string(e.responseLanguage),e.unknown2!==0&&t.uint32(120).int32(e.unknown2),e.unknown3!==0&&t.uint32(128).int32(e.unknown3),e.bypassCache!==!1&&t.uint32(136).bool(e.bypassCache),e.useLivelyVoice!==!1&&t.uint32(144).bool(e.useLivelyVoice),e.videoTitle!==``&&t.uint32(154).string(e.videoTitle),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=ye();for(;n.pos>>3){case 3:if(e!==26)break;i.url=n.string();continue;case 4:if(e!==34)break;i.deviceId=n.string();continue;case 5:if(e!==40)break;i.firstRequest=n.bool();continue;case 6:if(e!==49)break;i.duration=n.double();continue;case 7:if(e!==56)break;i.unknown0=n.int32();continue;case 8:if(e!==66)break;i.language=n.string();continue;case 9:if(e!==72)break;i.forceSourceLang=n.bool();continue;case 10:if(e!==80)break;i.unknown1=n.int32();continue;case 11:if(e!==90)break;i.translationHelp.push(ve.decode(n,n.uint32()));continue;case 13:if(e!==104)break;i.wasStream=n.bool();continue;case 14:if(e!==114)break;i.responseLanguage=n.string();continue;case 15:if(e!==120)break;i.unknown2=n.int32();continue;case 16:if(e!==128)break;i.unknown3=n.int32();continue;case 17:if(e!==136)break;i.bypassCache=n.bool();continue;case 18:if(e!==144)break;i.useLivelyVoice=n.bool();continue;case 19:if(e!==154)break;i.videoTitle=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,deviceId:w(e.deviceId)?globalThis.String(e.deviceId):void 0,firstRequest:w(e.firstRequest)?globalThis.Boolean(e.firstRequest):!1,duration:w(e.duration)?globalThis.Number(e.duration):0,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):0,language:w(e.language)?globalThis.String(e.language):``,forceSourceLang:w(e.forceSourceLang)?globalThis.Boolean(e.forceSourceLang):!1,unknown1:w(e.unknown1)?globalThis.Number(e.unknown1):0,translationHelp:globalThis.Array.isArray(e?.translationHelp)?e.translationHelp.map(e=>ve.fromJSON(e)):[],wasStream:w(e.wasStream)?globalThis.Boolean(e.wasStream):!1,responseLanguage:w(e.responseLanguage)?globalThis.String(e.responseLanguage):``,unknown2:w(e.unknown2)?globalThis.Number(e.unknown2):0,unknown3:w(e.unknown3)?globalThis.Number(e.unknown3):0,bypassCache:w(e.bypassCache)?globalThis.Boolean(e.bypassCache):!1,useLivelyVoice:w(e.useLivelyVoice)?globalThis.Boolean(e.useLivelyVoice):!1,videoTitle:w(e.videoTitle)?globalThis.String(e.videoTitle):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.deviceId!==void 0&&(t.deviceId=e.deviceId),e.firstRequest!==!1&&(t.firstRequest=e.firstRequest),e.duration!==0&&(t.duration=e.duration),e.unknown0!==0&&(t.unknown0=Math.round(e.unknown0)),e.language!==``&&(t.language=e.language),e.forceSourceLang!==!1&&(t.forceSourceLang=e.forceSourceLang),e.unknown1!==0&&(t.unknown1=Math.round(e.unknown1)),e.translationHelp?.length&&(t.translationHelp=e.translationHelp.map(e=>ve.toJSON(e))),e.wasStream!==!1&&(t.wasStream=e.wasStream),e.responseLanguage!==``&&(t.responseLanguage=e.responseLanguage),e.unknown2!==0&&(t.unknown2=Math.round(e.unknown2)),e.unknown3!==0&&(t.unknown3=Math.round(e.unknown3)),e.bypassCache!==!1&&(t.bypassCache=e.bypassCache),e.useLivelyVoice!==!1&&(t.useLivelyVoice=e.useLivelyVoice),e.videoTitle!==``&&(t.videoTitle=e.videoTitle),t},create(e){return be.fromPartial(e??{})},fromPartial(e){let t=ye();return t.url=e.url??``,t.deviceId=e.deviceId??void 0,t.firstRequest=e.firstRequest??!1,t.duration=e.duration??0,t.unknown0=e.unknown0??0,t.language=e.language??``,t.forceSourceLang=e.forceSourceLang??!1,t.unknown1=e.unknown1??0,t.translationHelp=e.translationHelp?.map(e=>ve.fromPartial(e))||[],t.wasStream=e.wasStream??!1,t.responseLanguage=e.responseLanguage??``,t.unknown2=e.unknown2??0,t.unknown3=e.unknown3??0,t.bypassCache=e.bypassCache??!1,t.useLivelyVoice=e.useLivelyVoice??!1,t.videoTitle=e.videoTitle??``,t}};function xe(){return{url:void 0,duration:void 0,status:0,remainingTime:void 0,unknown0:void 0,translationId:``,language:void 0,message:void 0,isLivelyVoice:!1,unknown2:void 0,shouldRetry:void 0,unknown3:void 0}}var Se={encode(e,t=new b){return e.url!==void 0&&t.uint32(10).string(e.url),e.duration!==void 0&&t.uint32(17).double(e.duration),e.status!==0&&t.uint32(32).int32(e.status),e.remainingTime!==void 0&&t.uint32(40).int32(e.remainingTime),e.unknown0!==void 0&&t.uint32(48).int32(e.unknown0),e.translationId!==``&&t.uint32(58).string(e.translationId),e.language!==void 0&&t.uint32(66).string(e.language),e.message!==void 0&&t.uint32(74).string(e.message),e.isLivelyVoice!==!1&&t.uint32(80).bool(e.isLivelyVoice),e.unknown2!==void 0&&t.uint32(88).int32(e.unknown2),e.shouldRetry!==void 0&&t.uint32(96).int32(e.shouldRetry),e.unknown3!==void 0&&t.uint32(104).int32(e.unknown3),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=xe();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==17)break;i.duration=n.double();continue;case 4:if(e!==32)break;i.status=n.int32();continue;case 5:if(e!==40)break;i.remainingTime=n.int32();continue;case 6:if(e!==48)break;i.unknown0=n.int32();continue;case 7:if(e!==58)break;i.translationId=n.string();continue;case 8:if(e!==66)break;i.language=n.string();continue;case 9:if(e!==74)break;i.message=n.string();continue;case 10:if(e!==80)break;i.isLivelyVoice=n.bool();continue;case 11:if(e!==88)break;i.unknown2=n.int32();continue;case 12:if(e!==96)break;i.shouldRetry=n.int32();continue;case 13:if(e!==104)break;i.unknown3=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):void 0,duration:w(e.duration)?globalThis.Number(e.duration):void 0,status:w(e.status)?globalThis.Number(e.status):0,remainingTime:w(e.remainingTime)?globalThis.Number(e.remainingTime):void 0,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):void 0,translationId:w(e.translationId)?globalThis.String(e.translationId):``,language:w(e.language)?globalThis.String(e.language):void 0,message:w(e.message)?globalThis.String(e.message):void 0,isLivelyVoice:w(e.isLivelyVoice)?globalThis.Boolean(e.isLivelyVoice):!1,unknown2:w(e.unknown2)?globalThis.Number(e.unknown2):void 0,shouldRetry:w(e.shouldRetry)?globalThis.Number(e.shouldRetry):void 0,unknown3:w(e.unknown3)?globalThis.Number(e.unknown3):void 0}},toJSON(e){let t={};return e.url!==void 0&&(t.url=e.url),e.duration!==void 0&&(t.duration=e.duration),e.status!==0&&(t.status=Math.round(e.status)),e.remainingTime!==void 0&&(t.remainingTime=Math.round(e.remainingTime)),e.unknown0!==void 0&&(t.unknown0=Math.round(e.unknown0)),e.translationId!==``&&(t.translationId=e.translationId),e.language!==void 0&&(t.language=e.language),e.message!==void 0&&(t.message=e.message),e.isLivelyVoice!==!1&&(t.isLivelyVoice=e.isLivelyVoice),e.unknown2!==void 0&&(t.unknown2=Math.round(e.unknown2)),e.shouldRetry!==void 0&&(t.shouldRetry=Math.round(e.shouldRetry)),e.unknown3!==void 0&&(t.unknown3=Math.round(e.unknown3)),t},create(e){return Se.fromPartial(e??{})},fromPartial(e){let t=xe();return t.url=e.url??void 0,t.duration=e.duration??void 0,t.status=e.status??0,t.remainingTime=e.remainingTime??void 0,t.unknown0=e.unknown0??void 0,t.translationId=e.translationId??``,t.language=e.language??void 0,t.message=e.message??void 0,t.isLivelyVoice=e.isLivelyVoice??!1,t.unknown2=e.unknown2??void 0,t.shouldRetry=e.shouldRetry??void 0,t.unknown3=e.unknown3??void 0,t}};function Ce(){return{status:0,remainingTime:void 0,message:void 0,unknown0:void 0}}var C={encode(e,t=new b){return e.status!==0&&t.uint32(8).int32(e.status),e.remainingTime!==void 0&&t.uint32(16).int32(e.remainingTime),e.message!==void 0&&t.uint32(26).string(e.message),e.unknown0!==void 0&&t.uint32(32).int32(e.unknown0),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ce();for(;n.pos>>3){case 1:if(e!==8)break;i.status=n.int32();continue;case 2:if(e!==16)break;i.remainingTime=n.int32();continue;case 3:if(e!==26)break;i.message=n.string();continue;case 4:if(e!==32)break;i.unknown0=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{status:w(e.status)?globalThis.Number(e.status):0,remainingTime:w(e.remainingTime)?globalThis.Number(e.remainingTime):void 0,message:w(e.message)?globalThis.String(e.message):void 0,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):void 0}},toJSON(e){let t={};return e.status!==0&&(t.status=Math.round(e.status)),e.remainingTime!==void 0&&(t.remainingTime=Math.round(e.remainingTime)),e.message!==void 0&&(t.message=e.message),e.unknown0!==void 0&&(t.unknown0=Math.round(e.unknown0)),t},create(e){return C.fromPartial(e??{})},fromPartial(e){let t=Ce();return t.status=e.status??0,t.remainingTime=e.remainingTime??void 0,t.message=e.message??void 0,t.unknown0=e.unknown0??void 0,t}};function we(){return{url:``,duration:0,language:``,responseLanguage:``}}var Te={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.duration!==0&&t.uint32(17).double(e.duration),e.language!==``&&t.uint32(26).string(e.language),e.responseLanguage!==``&&t.uint32(34).string(e.responseLanguage),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=we();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==17)break;i.duration=n.double();continue;case 3:if(e!==26)break;i.language=n.string();continue;case 4:if(e!==34)break;i.responseLanguage=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,duration:w(e.duration)?globalThis.Number(e.duration):0,language:w(e.language)?globalThis.String(e.language):``,responseLanguage:w(e.responseLanguage)?globalThis.String(e.responseLanguage):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.duration!==0&&(t.duration=e.duration),e.language!==``&&(t.language=e.language),e.responseLanguage!==``&&(t.responseLanguage=e.responseLanguage),t},create(e){return Te.fromPartial(e??{})},fromPartial(e){let t=we();return t.url=e.url??``,t.duration=e.duration??0,t.language=e.language??``,t.responseLanguage=e.responseLanguage??``,t}};function Ee(){return{default:void 0,cloning:void 0}}var De={encode(e,t=new b){return e.default!==void 0&&C.encode(e.default,t.uint32(10).fork()).join(),e.cloning!==void 0&&C.encode(e.cloning,t.uint32(18).fork()).join(),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ee();for(;n.pos>>3){case 1:if(e!==10)break;i.default=C.decode(n,n.uint32());continue;case 2:if(e!==18)break;i.cloning=C.decode(n,n.uint32());continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{default:w(e.default)?C.fromJSON(e.default):void 0,cloning:w(e.cloning)?C.fromJSON(e.cloning):void 0}},toJSON(e){let t={};return e.default!==void 0&&(t.default=C.toJSON(e.default)),e.cloning!==void 0&&(t.cloning=C.toJSON(e.cloning)),t},create(e){return De.fromPartial(e??{})},fromPartial(e){let t=Ee();return t.default=e.default!==void 0&&e.default!==null?C.fromPartial(e.default):void 0,t.cloning=e.cloning!==void 0&&e.cloning!==null?C.fromPartial(e.cloning):void 0,t}};function Oe(){return{audioFile:new Uint8Array,fileId:``}}var ke={encode(e,t=new b){return e.audioFile.length!==0&&t.uint32(18).bytes(e.audioFile),e.fileId!==``&&t.uint32(10).string(e.fileId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Oe();for(;n.pos>>3){case 2:if(e!==18)break;i.audioFile=n.bytes();continue;case 1:if(e!==10)break;i.fileId=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{audioFile:w(e.audioFile)?nt(e.audioFile):new Uint8Array,fileId:w(e.fileId)?globalThis.String(e.fileId):``}},toJSON(e){let t={};return e.audioFile.length!==0&&(t.audioFile=rt(e.audioFile)),e.fileId!==``&&(t.fileId=e.fileId),t},create(e){return ke.fromPartial(e??{})},fromPartial(e){let t=Oe();return t.audioFile=e.audioFile??new Uint8Array,t.fileId=e.fileId??``,t}};function Ae(){return{audioFile:new Uint8Array,chunkId:0}}var je={encode(e,t=new b){return e.audioFile.length!==0&&t.uint32(18).bytes(e.audioFile),e.chunkId!==0&&t.uint32(8).int32(e.chunkId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ae();for(;n.pos>>3){case 2:if(e!==18)break;i.audioFile=n.bytes();continue;case 1:if(e!==8)break;i.chunkId=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{audioFile:w(e.audioFile)?nt(e.audioFile):new Uint8Array,chunkId:w(e.chunkId)?globalThis.Number(e.chunkId):0}},toJSON(e){let t={};return e.audioFile.length!==0&&(t.audioFile=rt(e.audioFile)),e.chunkId!==0&&(t.chunkId=Math.round(e.chunkId)),t},create(e){return je.fromPartial(e??{})},fromPartial(e){let t=Ae();return t.audioFile=e.audioFile??new Uint8Array,t.chunkId=e.chunkId??0,t}};function Me(){return{audioBuffer:void 0,audioPartsLength:0,fileId:``,version:0}}var Ne={encode(e,t=new b){return e.audioBuffer!==void 0&&je.encode(e.audioBuffer,t.uint32(10).fork()).join(),e.audioPartsLength!==0&&t.uint32(16).int32(e.audioPartsLength),e.fileId!==``&&t.uint32(26).string(e.fileId),e.version!==0&&t.uint32(32).int32(e.version),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Me();for(;n.pos>>3){case 1:if(e!==10)break;i.audioBuffer=je.decode(n,n.uint32());continue;case 2:if(e!==16)break;i.audioPartsLength=n.int32();continue;case 3:if(e!==26)break;i.fileId=n.string();continue;case 4:if(e!==32)break;i.version=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{audioBuffer:w(e.audioBuffer)?je.fromJSON(e.audioBuffer):void 0,audioPartsLength:w(e.audioPartsLength)?globalThis.Number(e.audioPartsLength):0,fileId:w(e.fileId)?globalThis.String(e.fileId):``,version:w(e.version)?globalThis.Number(e.version):0}},toJSON(e){let t={};return e.audioBuffer!==void 0&&(t.audioBuffer=je.toJSON(e.audioBuffer)),e.audioPartsLength!==0&&(t.audioPartsLength=Math.round(e.audioPartsLength)),e.fileId!==``&&(t.fileId=e.fileId),e.version!==0&&(t.version=Math.round(e.version)),t},create(e){return Ne.fromPartial(e??{})},fromPartial(e){let t=Me();return t.audioBuffer=e.audioBuffer!==void 0&&e.audioBuffer!==null?je.fromPartial(e.audioBuffer):void 0,t.audioPartsLength=e.audioPartsLength??0,t.fileId=e.fileId??``,t.version=e.version??0,t}};function Pe(){return{translationId:``,url:``,partialAudioInfo:void 0,audioInfo:void 0}}var Fe={encode(e,t=new b){return e.translationId!==``&&t.uint32(10).string(e.translationId),e.url!==``&&t.uint32(18).string(e.url),e.partialAudioInfo!==void 0&&Ne.encode(e.partialAudioInfo,t.uint32(34).fork()).join(),e.audioInfo!==void 0&&ke.encode(e.audioInfo,t.uint32(50).fork()).join(),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Pe();for(;n.pos>>3){case 1:if(e!==10)break;i.translationId=n.string();continue;case 2:if(e!==18)break;i.url=n.string();continue;case 4:if(e!==34)break;i.partialAudioInfo=Ne.decode(n,n.uint32());continue;case 6:if(e!==50)break;i.audioInfo=ke.decode(n,n.uint32());continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{translationId:w(e.translationId)?globalThis.String(e.translationId):``,url:w(e.url)?globalThis.String(e.url):``,partialAudioInfo:w(e.partialAudioInfo)?Ne.fromJSON(e.partialAudioInfo):void 0,audioInfo:w(e.audioInfo)?ke.fromJSON(e.audioInfo):void 0}},toJSON(e){let t={};return e.translationId!==``&&(t.translationId=e.translationId),e.url!==``&&(t.url=e.url),e.partialAudioInfo!==void 0&&(t.partialAudioInfo=Ne.toJSON(e.partialAudioInfo)),e.audioInfo!==void 0&&(t.audioInfo=ke.toJSON(e.audioInfo)),t},create(e){return Fe.fromPartial(e??{})},fromPartial(e){let t=Pe();return t.translationId=e.translationId??``,t.url=e.url??``,t.partialAudioInfo=e.partialAudioInfo!==void 0&&e.partialAudioInfo!==null?Ne.fromPartial(e.partialAudioInfo):void 0,t.audioInfo=e.audioInfo!==void 0&&e.audioInfo!==null?ke.fromPartial(e.audioInfo):void 0,t}};function Ie(){return{status:0,remainingChunks:[]}}var Le={encode(e,t=new b){e.status!==0&&t.uint32(8).int32(e.status);for(let n of e.remainingChunks)t.uint32(18).string(n);return t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ie();for(;n.pos>>3){case 1:if(e!==8)break;i.status=n.int32();continue;case 2:if(e!==18)break;i.remainingChunks.push(n.string());continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{status:w(e.status)?globalThis.Number(e.status):0,remainingChunks:globalThis.Array.isArray(e?.remainingChunks)?e.remainingChunks.map(e=>globalThis.String(e)):[]}},toJSON(e){let t={};return e.status!==0&&(t.status=Math.round(e.status)),e.remainingChunks?.length&&(t.remainingChunks=e.remainingChunks),t},create(e){return Le.fromPartial(e??{})},fromPartial(e){let t=Ie();return t.status=e.status??0,t.remainingChunks=e.remainingChunks?.map(e=>e)||[],t}};function Re(){return{language:``,url:``,unknown0:0,translatedLanguage:``,translatedUrl:``,unknown1:0,unknown2:0}}var ze={encode(e,t=new b){return e.language!==``&&t.uint32(10).string(e.language),e.url!==``&&t.uint32(18).string(e.url),e.unknown0!==0&&t.uint32(24).int32(e.unknown0),e.translatedLanguage!==``&&t.uint32(34).string(e.translatedLanguage),e.translatedUrl!==``&&t.uint32(42).string(e.translatedUrl),e.unknown1!==0&&t.uint32(48).int32(e.unknown1),e.unknown2!==0&&t.uint32(56).int32(e.unknown2),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Re();for(;n.pos>>3){case 1:if(e!==10)break;i.language=n.string();continue;case 2:if(e!==18)break;i.url=n.string();continue;case 3:if(e!==24)break;i.unknown0=n.int32();continue;case 4:if(e!==34)break;i.translatedLanguage=n.string();continue;case 5:if(e!==42)break;i.translatedUrl=n.string();continue;case 6:if(e!==48)break;i.unknown1=n.int32();continue;case 7:if(e!==56)break;i.unknown2=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{language:w(e.language)?globalThis.String(e.language):``,url:w(e.url)?globalThis.String(e.url):``,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):0,translatedLanguage:w(e.translatedLanguage)?globalThis.String(e.translatedLanguage):``,translatedUrl:w(e.translatedUrl)?globalThis.String(e.translatedUrl):``,unknown1:w(e.unknown1)?globalThis.Number(e.unknown1):0,unknown2:w(e.unknown2)?globalThis.Number(e.unknown2):0}},toJSON(e){let t={};return e.language!==``&&(t.language=e.language),e.url!==``&&(t.url=e.url),e.unknown0!==0&&(t.unknown0=Math.round(e.unknown0)),e.translatedLanguage!==``&&(t.translatedLanguage=e.translatedLanguage),e.translatedUrl!==``&&(t.translatedUrl=e.translatedUrl),e.unknown1!==0&&(t.unknown1=Math.round(e.unknown1)),e.unknown2!==0&&(t.unknown2=Math.round(e.unknown2)),t},create(e){return ze.fromPartial(e??{})},fromPartial(e){let t=Re();return t.language=e.language??``,t.url=e.url??``,t.unknown0=e.unknown0??0,t.translatedLanguage=e.translatedLanguage??``,t.translatedUrl=e.translatedUrl??``,t.unknown1=e.unknown1??0,t.unknown2=e.unknown2??0,t}};function Be(){return{url:``,language:``}}var Ve={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.language!==``&&t.uint32(18).string(e.language),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Be();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==18)break;i.language=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,language:w(e.language)?globalThis.String(e.language):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.language!==``&&(t.language=e.language),t},create(e){return Ve.fromPartial(e??{})},fromPartial(e){let t=Be();return t.url=e.url??``,t.language=e.language??``,t}};function He(){return{waiting:!1,subtitles:[]}}var Ue={encode(e,t=new b){e.waiting!==!1&&t.uint32(8).bool(e.waiting);for(let n of e.subtitles)ze.encode(n,t.uint32(18).fork()).join();return t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=He();for(;n.pos>>3){case 1:if(e!==8)break;i.waiting=n.bool();continue;case 2:if(e!==18)break;i.subtitles.push(ze.decode(n,n.uint32()));continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{waiting:w(e.waiting)?globalThis.Boolean(e.waiting):!1,subtitles:globalThis.Array.isArray(e?.subtitles)?e.subtitles.map(e=>ze.fromJSON(e)):[]}},toJSON(e){let t={};return e.waiting!==!1&&(t.waiting=e.waiting),e.subtitles?.length&&(t.subtitles=e.subtitles.map(e=>ze.toJSON(e))),t},create(e){return Ue.fromPartial(e??{})},fromPartial(e){let t=He();return t.waiting=e.waiting??!1,t.subtitles=e.subtitles?.map(e=>ze.fromPartial(e))||[],t}};function We(){return{url:``,timestamp:``}}var Ge={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.timestamp!==``&&t.uint32(18).string(e.timestamp),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=We();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==18)break;i.timestamp=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,timestamp:w(e.timestamp)?globalThis.String(e.timestamp):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.timestamp!==``&&(t.timestamp=e.timestamp),t},create(e){return Ge.fromPartial(e??{})},fromPartial(e){let t=We();return t.url=e.url??``,t.timestamp=e.timestamp??``,t}};function Ke(){return{url:``,language:``,responseLanguage:``,unknown0:0,unknown1:0}}var qe={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.language!==``&&t.uint32(18).string(e.language),e.responseLanguage!==``&&t.uint32(26).string(e.responseLanguage),e.unknown0!==0&&t.uint32(40).int32(e.unknown0),e.unknown1!==0&&t.uint32(48).int32(e.unknown1),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ke();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==18)break;i.language=n.string();continue;case 3:if(e!==26)break;i.responseLanguage=n.string();continue;case 5:if(e!==40)break;i.unknown0=n.int32();continue;case 6:if(e!==48)break;i.unknown1=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,language:w(e.language)?globalThis.String(e.language):``,responseLanguage:w(e.responseLanguage)?globalThis.String(e.responseLanguage):``,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):0,unknown1:w(e.unknown1)?globalThis.Number(e.unknown1):0}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.language!==``&&(t.language=e.language),e.responseLanguage!==``&&(t.responseLanguage=e.responseLanguage),e.unknown0!==0&&(t.unknown0=Math.round(e.unknown0)),e.unknown1!==0&&(t.unknown1=Math.round(e.unknown1)),t},create(e){return qe.fromPartial(e??{})},fromPartial(e){let t=Ke();return t.url=e.url??``,t.language=e.language??``,t.responseLanguage=e.responseLanguage??``,t.unknown0=e.unknown0??0,t.unknown1=e.unknown1??0,t}};function Je(){return{interval:0,translatedInfo:void 0,pingId:void 0}}var Ye={encode(e,t=new b){return e.interval!==0&&t.uint32(8).int32(e.interval),e.translatedInfo!==void 0&&Ge.encode(e.translatedInfo,t.uint32(18).fork()).join(),e.pingId!==void 0&&t.uint32(24).int32(e.pingId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Je();for(;n.pos>>3){case 1:if(e!==8)break;i.interval=n.int32();continue;case 2:if(e!==18)break;i.translatedInfo=Ge.decode(n,n.uint32());continue;case 3:if(e!==24)break;i.pingId=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{interval:w(e.interval)?he(e.interval):0,translatedInfo:w(e.translatedInfo)?Ge.fromJSON(e.translatedInfo):void 0,pingId:w(e.pingId)?globalThis.Number(e.pingId):void 0}},toJSON(e){let t={};return e.interval!==0&&(t.interval=ge(e.interval)),e.translatedInfo!==void 0&&(t.translatedInfo=Ge.toJSON(e.translatedInfo)),e.pingId!==void 0&&(t.pingId=Math.round(e.pingId)),t},create(e){return Ye.fromPartial(e??{})},fromPartial(e){let t=Je();return t.interval=e.interval??0,t.translatedInfo=e.translatedInfo!==void 0&&e.translatedInfo!==null?Ge.fromPartial(e.translatedInfo):void 0,t.pingId=e.pingId??void 0,t}};function Xe(){return{pingId:0}}var Ze={encode(e,t=new b){return e.pingId!==0&&t.uint32(8).int32(e.pingId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Xe();for(;n.pos>>3){case 1:if(e!==8)break;i.pingId=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{pingId:w(e.pingId)?globalThis.Number(e.pingId):0}},toJSON(e){let t={};return e.pingId!==0&&(t.pingId=Math.round(e.pingId)),t},create(e){return Ze.fromPartial(e??{})},fromPartial(e){let t=Xe();return t.pingId=e.pingId??0,t}};function Qe(){return{uuid:``,module:``}}var $e={encode(e,t=new b){return e.uuid!==``&&t.uint32(10).string(e.uuid),e.module!==``&&t.uint32(18).string(e.module),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Qe();for(;n.pos>>3){case 1:if(e!==10)break;i.uuid=n.string();continue;case 2:if(e!==18)break;i.module=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{uuid:w(e.uuid)?globalThis.String(e.uuid):``,module:w(e.module)?globalThis.String(e.module):``}},toJSON(e){let t={};return e.uuid!==``&&(t.uuid=e.uuid),e.module!==``&&(t.module=e.module),t},create(e){return $e.fromPartial(e??{})},fromPartial(e){let t=Qe();return t.uuid=e.uuid??``,t.module=e.module??``,t}};function et(){return{secretKey:``,expires:0}}var tt={encode(e,t=new b){return e.secretKey!==``&&t.uint32(10).string(e.secretKey),e.expires!==0&&t.uint32(16).int32(e.expires),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=et();for(;n.pos>>3){case 1:if(e!==10)break;i.secretKey=n.string();continue;case 2:if(e!==16)break;i.expires=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{secretKey:w(e.secretKey)?globalThis.String(e.secretKey):``,expires:w(e.expires)?globalThis.Number(e.expires):0}},toJSON(e){let t={};return e.secretKey!==``&&(t.secretKey=e.secretKey),e.expires!==0&&(t.expires=Math.round(e.expires)),t},create(e){return tt.fromPartial(e??{})},fromPartial(e){let t=et();return t.secretKey=e.secretKey??``,t.expires=e.expires??0,t}};function nt(e){if(globalThis.Buffer)return Uint8Array.from(globalThis.Buffer.from(e,`base64`));{let t=globalThis.atob(e),n=new Uint8Array(t.length);for(let e=0;e{t.push(globalThis.String.fromCharCode(e))}),globalThis.btoa(t.join(``))}}function w(e){return e!=null}var it;(function(e){e[e.DEBUG=0]=`DEBUG`,e[e.INFO=1]=`INFO`,e[e.WARN=2]=`WARN`,e[e.ERROR=3]=`ERROR`,e[e.SILENCE=4]=`SILENCE`})(it||={});var at=`[vot.js v${f.version}]`;function ot(e){return f.loggerLevel<=e}function st(...e){ot(it.DEBUG)&&console.log(at,...e)}function ct(...e){ot(it.INFO)&&console.info(at,...e)}function lt(...e){ot(it.WARN)&&console.warn(at,...e)}function ut(...e){ot(it.ERROR)&&console.error(at,...e)}var T={canLog:ot,log:st,info:ct,warn:lt,error:ut},dt=l({default:()=>ft,getRandomValues:()=>mt,randomUUID:()=>ht,subtle:()=>pt}),ft,pt,mt,ht,gt=s((()=>{if(ft=globalThis.crypto,!ft?.subtle)throw TypeError(`Web Crypto API is not available in this environment.`);pt=ft.subtle,mt=ft.getRandomValues.bind(ft),ht=typeof ft.randomUUID==`function`?ft.randomUUID.bind(ft):void 0})),{componentVersion:_t}=f;async function vt(){return typeof window<`u`&&window.crypto?window.crypto:await Promise.resolve().then(()=>(gt(),dt))}var bt=new TextEncoder;async function xt(e,t,n){let r=await vt(),i=await r.subtle.importKey(`raw`,bt.encode(t),{name:`HMAC`,hash:{name:e}},!1,[`sign`,`verify`]);return await r.subtle.sign(`HMAC`,i,n)}async function St(e){let t=await xt(`SHA-256`,f.hmac,e);return new Uint8Array(t).reduce((e,t)=>e+t.toString(16).padStart(2,`0`),``)}async function Ct(e,t,n,r){let{secretKey:i,uuid:a}=t,o=`${a}:${r}:${_t}`,s=await St(bt.encode(o));if(e===`Ya-Summary`)return{[`X-${e}-Sk`]:i,[`X-${e}-Token`]:`${s}:${o}`};if(!n)throw TypeError(`Body is required for sec type ${e}`);let c=await St(n);return{[`${e}-Signature`]:c,[`Sec-${e}-Sk`]:i,[`Sec-${e}-Token`]:`${s}:${o}`}}function wt(){let e=``;for(let t=0;t<32;t++){let t=Math.floor(Math.random()*16);e+=`0123456789ABCDEF`[t]}return e}async function Tt(e,t){try{let n=await xt(`SHA-1`,e,bt.encode(t));return btoa(String.fromCharCode(...new Uint8Array(n)))}catch(e){return T.error(e),!1}}var Et={"sec-ch-ua":`"Chromium";v="146", "YaBrowser";v="${_t.slice(0,5)}", "Not?A_Brand";v="26", "Yowser";v="2.5"`,"sec-ch-ua-full-version-list":`"Chromium";v="146.0.7680.154", "YaBrowser";v="${_t}", "Not?A_Brand";v="26.0.0.0", "Yowser";v="2.5"`,"Sec-Fetch-Mode":`no-cors`},Dt={afr:`af`,aka:`ak`,alb:`sq`,amh:`am`,ara:`ar`,arm:`hy`,asm:`as`,aym:`ay`,aze:`az`,baq:`eu`,bel:`be`,ben:`bn`,bos:`bs`,bul:`bg`,bur:`my`,cat:`ca`,chi:`zh`,cos:`co`,cze:`cs`,dan:`da`,div:`dv`,dut:`nl`,eng:`en`,epo:`eo`,est:`et`,ewe:`ee`,fin:`fi`,fre:`fr`,fry:`fy`,geo:`ka`,ger:`de`,gla:`gd`,gle:`ga`,glg:`gl`,gre:`el`,grn:`gn`,guj:`gu`,hat:`ht`,hau:`ha`,hin:`hi`,hrv:`hr`,hun:`hu`,ibo:`ig`,ice:`is`,ind:`id`,ita:`it`,jav:`jv`,jpn:`ja`,kan:`kn`,kaz:`kk`,khm:`km`,kin:`rw`,kir:`ky`,kor:`ko`,kur:`ku`,lao:`lo`,lat:`la`,lav:`lv`,lin:`ln`,lit:`lt`,ltz:`lb`,lug:`lg`,mac:`mk`,mal:`ml`,mao:`mi`,mar:`mr`,may:`ms`,mlg:`mg`,mlt:`mt`,mon:`mn`,nep:`ne`,nor:`no`,nya:`ny`,ori:`or`,orm:`om`,pan:`pa`,per:`fa`,pol:`pl`,por:`pt`,pus:`ps`,que:`qu`,rum:`ro`,rus:`ru`,san:`sa`,sin:`si`,slo:`sk`,slv:`sl`,smo:`sm`,sna:`sn`,snd:`sd`,som:`so`,sot:`st`,spa:`es`,srp:`sr`,sun:`su`,swa:`sw`,swe:`sv`,tam:`ta`,tat:`tt`,tel:`te`,tgk:`tg`,tha:`th`,tir:`ti`,tso:`ts`,tuk:`tk`,tur:`tr`,uig:`ug`,ukr:`uk`,urd:`ur`,uzb:`uz`,vie:`vi`,wel:`cy`,xho:`xh`,yid:`yi`,yor:`yo`,zul:`zu`};async function Ot(e,t={headers:{"User-Agent":f.userAgent}}){let{timeout:n=3e3,signal:r,...i}=t;if(!r&&(!n||n<=0))return await fetch(e,i);let a=new AbortController,o=e=>{a.signal.aborted||a.abort(e)};r&&(r.aborted?o(r.reason):r.addEventListener(`abort`,()=>o(r.reason),{once:!0}));let s;n&&n>0&&(s=setTimeout(()=>o(Error(`Fetch timeout`)),n));try{return await fetch(e,{...i,signal:a.signal})}finally{s&&clearTimeout(s)}}function kt(){return Math.floor(Date.now()/1e3)}function E(e){return e.length===3?Dt[e]:e.toLowerCase().split(/[_;-]/)[0].trim()}function D(e,t=`mp4`){let n=`https://${f.mediaProxy}/v1/proxy/video.${t}?format=base64&force=true`;return e instanceof URL?`${n}&url=${btoa(e.href)}&origin=${e.origin}&referer=${e.origin}`:`${n}&url=${btoa(e)}`}function At(e,t){let n=e.replace(/^\/+/,``),r=new URL(`https://vk.com/video`);r.searchParams.set(`z`,n);for(let e of[`list`,`access_key`]){let n=t.searchParams.get(e);n&&r.searchParams.set(e,n)}return r.toString()}function jt(e,t,n,r,i,{forceSourceLang:a=!1,wasStream:o=!1,videoTitle:s=``,bypassCache:c=!1,useLivelyVoice:l=!1,firstRequest:u=!0}={}){return be.encode({url:e,firstRequest:u,duration:t,unknown0:1,language:n,forceSourceLang:a,unknown1:0,translationHelp:i??[],responseLanguage:r,wasStream:o,unknown2:1,unknown3:2,bypassCache:c,useLivelyVoice:l,videoTitle:s}).finish()}function Mt(e){return Se.decode(new Uint8Array(e))}function Nt(e,t,n,r){return Te.encode({url:e,duration:t,language:n,responseLanguage:r}).finish()}function Pt(e){return De.decode(new Uint8Array(e))}function Ft(e){return`chunkId`in e}function It(e,t,n,r){return r&&Ft(n)?Fe.encode({url:e,translationId:t,partialAudioInfo:{...r,audioBuffer:n}}).finish():Fe.encode({url:e,translationId:t,audioInfo:n}).finish()}function Lt(e){return Le.decode(new Uint8Array(e))}function Rt(e,t){return Ve.encode({url:e,language:t}).finish()}function zt(e){return Ue.decode(new Uint8Array(e))}function Bt(e){return Ze.encode({pingId:e}).finish()}function Vt(e,t,n){return qe.encode({url:e,language:t,responseLanguage:n,unknown0:1,unknown1:0}).finish()}function Ht(e){return Ye.decode(new Uint8Array(e))}var O={encodeTranslationRequest:jt,decodeTranslationResponse:Mt,encodeTranslationCacheRequest:Nt,decodeTranslationCacheResponse:Pt,isPartialAudioBuffer:Ft,encodeTranslationAudioRequest:It,decodeTranslationAudioResponse:Lt,encodeSubtitlesRequest:Rt,decodeSubtitlesResponse:zt,encodeStreamPingRequest:Bt,encodeStreamRequest:Vt,decodeStreamResponse:Ht};function Ut(e,t){return $e.encode({uuid:e,module:t}).finish()}function Wt(e){return tt.decode(new Uint8Array(e))}var Gt={encodeSessionRequest:Ut,decodeSessionResponse:Wt},Kt;(function(e){e[e.FAILED=0]=`FAILED`,e[e.FINISHED=1]=`FINISHED`,e[e.WAITING=2]=`WAITING`,e[e.LONG_WAITING=3]=`LONG_WAITING`,e[e.PART_CONTENT=5]=`PART_CONTENT`,e[e.AUDIO_REQUESTED=6]=`AUDIO_REQUESTED`,e[e.SESSION_REQUIRED=7]=`SESSION_REQUIRED`})(Kt||={});var qt;(function(e){e.WEB_API_VIDEO_SRC_FROM_IFRAME=`web_api_video_src_from_iframe`,e.WEB_API_VIDEO_SRC=`web_api_video_src`,e.WEB_API_GET_ALL_GENERATING_URLS_DATA_FROM_IFRAME=`web_api_get_all_generating_urls_data_from_iframe`,e.WEB_API_GET_ALL_GENERATING_URLS_DATA_FROM_IFRAME_TMP_EXP=`web_api_get_all_generating_urls_data_from_iframe_tmp_exp`,e.WEB_API_REPLACED_FETCH_INSIDE_IFRAME=`web_api_replaced_fetch_inside_iframe`,e.ANDROID_API=`android_api`,e.WEB_API_SLOW=`web_api_slow`,e.WEB_API_STEAL_SIG_AND_N=`web_api_steal_sig_and_n`,e.WEB_API_COMBINED=`web_api_get_all_generating_urls_data_from_iframe,web_api_steal_sig_and_n`})(qt||={});var k;(function(e){e.custom=`custom`,e.directlink=`custom`,e.youtube=`youtube`,e.preservetube=`preservetube`,e.piped=`piped`,e.invidious=`invidious`,e.niconico=`niconico`,e.vk=`vk`,e.nine_gag=`nine_gag`,e.gag=`nine_gag`,e.twitch=`twitch`,e.proxitok=`proxitok`,e.tiktok=`tiktok`,e.vimeo=`vimeo`,e.xvideos=`xvideos`,e.xhamster=`xhamster`,e.spankbang=`spankbang`,e.rule34video=`rule34video`,e.picarto=`picarto`,e.olympicsreplay=`olympics_replay`,e.pornhub=`pornhub`,e.twitter=`twitter`,e.x=`twitter`,e.rumble=`rumble`,e.facebook=`facebook`,e.rutube=`rutube`,e.coub=`coub`,e.bilibili=`bilibili`,e.mail_ru=`mailru`,e.mailru=`mailru`,e.bitchute=`bitchute`,e.eporner=`eporner`,e.peertube=`peertube`,e.dailymotion=`dailymotion`,e.trovo=`trovo`,e.yandexdisk=`yandexdisk`,e.ok_ru=`okru`,e.okru=`okru`,e.googledrive=`googledrive`,e.bannedvideo=`bannedvideo`,e.weverse=`weverse`,e.weibo=`weibo`,e.newgrounds=`newgrounds`,e.egghead=`egghead`,e.youku=`youku`,e.archive=`archive`,e.kodik=`kodik`,e.patreon=`patreon`,e.reddit=`reddit`,e.kick=`kick`,e.apple_developer=`apple_developer`,e.appledeveloper=`apple_developer`,e.epicgames=`epicgames`,e.odysee=`odysee`,e.coursehunterLike=`coursehunterLike`,e.sap=`sap`,e.watchpornto=`watchpornto`,e.jove=`jove`,e.linkedin=`linkedin`,e.incestflix=`incestflix`,e.porntn=`porntn`,e.dzen=`dzen`,e.bunnystream=`bunnystream`,e.cloudflarestream=`cloudflarestream`,e.loom=`loom`,e.rtnews=`rtnews`,e.bitview=`bitview`,e.thisvid=`thisvid`,e.ign=`ign`,e.zdf=`zdf`,e.bunkr=`bunkr`,e.imdb=`imdb`,e.telegram=`telegram`})(k||={});function Jt(e,t,n){return e===k.patreon?{service:`mux`,videoId:new URL(n).pathname.slice(1)}:{service:e,videoId:t}}var A=class extends Error{data;constructor(e,t=void 0){super(e),this.data=t,this.name=`VOTJSError`}},Yt=class{host;schema;fetch;fetchOpts;sessions={};userAgent=f.userAgent;headers={"User-Agent":this.userAgent,Accept:`application/x-protobuf`,"Accept-Language":`en`,"Content-Type":`application/x-protobuf`,Pragma:`no-cache`,"Cache-Control":`no-cache`};hostSchemaRe=/(http(s)?):\/\//;constructor({host:e=f.host,fetchFn:t=Ot,fetchOpts:n={},headers:r={}}={}){let i=this.hostSchemaRe.exec(e)?.[1];this.host=i?e.replace(`${i}://`,``):e,this.schema=i??`https`,this.fetch=t,this.fetchOpts=n,this.headers={...this.headers,...r}}async request(e,t,n={},r=`POST`){let i=this.getOpts(new Blob([t]),n,r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.arrayBuffer();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}async requestJSON(e,t=null,n={},r=`POST`){let i=this.getOpts(t,{"Content-Type":`application/json`,...n},r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.json();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}getOpts(e,t={},n=`POST`){return{method:n,headers:{...this.headers,...t},body:e,...this.fetchOpts}}async getSession(e){let t=kt(),n=this.sessions[e];if(n&&n.timestamp+n.expires>t)return n;let{secretKey:r,expires:i,uuid:a}=await this.createSession(e);return this.sessions[e]={secretKey:r,expires:i,timestamp:t,uuid:a},this.sessions[e]}async createSession(e){let t=wt(),n=Gt.encodeSessionRequest(t,e),r=await this.request(`/session/create`,n,{"Vtrans-Signature":await St(n)});if(!r.success)throw new A(`Failed to request create session`,r);return{...Gt.decodeSessionResponse(r.data),uuid:t}}},Xt=class extends Yt{hostVOT;schemaVOT;apiToken;requestLang;responseLang;paths={videoTranslation:`/video-translation/translate`,videoTranslationFailAudio:`/video-translation/fail-audio-js`,videoTranslationAudio:`/video-translation/audio`,videoTranslationCache:`/video-translation/cache`,videoSubtitles:`/video-subtitles/get-subtitles`,streamPing:`/stream-translation/ping-stream`,streamTranslation:`/stream-translation/translate-stream`};isCustomLink(e){return!!(/\.(m3u8|m4(a|v)|mpd)/.exec(e)??/^https:\/\/cdn\.qstv\.on\.epicgames\.com/.exec(e))}headersVOT={"User-Agent":`vot.js/${f.version}`,"Content-Type":`application/json`,Pragma:`no-cache`,"Cache-Control":`no-cache`};constructor({host:e,hostVOT:t=f.hostVOT,fetchFn:n,fetchOpts:r,requestLang:i=`en`,responseLang:a=`ru`,apiToken:o,headers:s}={}){super({host:e,fetchFn:n,fetchOpts:r,headers:s});let c=this.hostSchemaRe.exec(t)?.[1];this.hostVOT=c?t.replace(`${c}://`,``):t,this.schemaVOT=c??`https`,this.requestLang=i,this.responseLang=a,this.apiToken=o}get apiTokenHeader(){return this.apiToken?{Authorization:`OAuth ${this.apiToken}`}:{}}async requestVOT(e,t,n={}){let r=this.getOpts(JSON.stringify(t),{...this.headersVOT,...n});try{let t=await this.fetch(`${this.schemaVOT}://${this.hostVOT}${e}`,r),n=await t.json();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}async translateVideoYAImpl({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,translationHelp:r=null,headers:i={},extraOpts:a={},shouldSendFailedAudio:o=!0}){let{url:s,duration:c=f.defaultDuration}=e,l=await this.getSession(`video-translation`),u=O.encodeTranslationRequest(s,c,t,n,r,a),d=this.paths.videoTranslation,p=await Ct(`Vtrans`,l,u,d),m=a.useLivelyVoice?this.apiTokenHeader:{},h=await this.request(d,u,{...p,...m,...i});if(!h.success)throw new A(`Failed to request video translation`,h);let g=O.decodeTranslationResponse(h.data);T.log(`translateVideo`,g);let{status:_,translationId:v}=g;switch(_){case Kt.FAILED:throw new A(`Yandex couldn't translate video`,g);case Kt.FINISHED:case Kt.PART_CONTENT:if(!g.url)throw new A(`Audio link wasn't received from Yandex response`,g);return{translationId:v,translated:!0,url:g.url,status:_,remainingTime:g.remainingTime??-1};case Kt.WAITING:case Kt.LONG_WAITING:return{translationId:v,translated:!1,status:_,remainingTime:g.remainingTime??-1};case Kt.AUDIO_REQUESTED:return s.startsWith(`https://youtu.be/`)&&o?(await this.requestVtransFailAudio(s),await this.requestVtransAudio(s,g.translationId,{audioFile:new Uint8Array,fileId:qt.WEB_API_GET_ALL_GENERATING_URLS_DATA_FROM_IFRAME}),await this.translateVideoYAImpl({videoData:e,requestLang:t,responseLang:n,translationHelp:r,headers:i,shouldSendFailedAudio:!1})):{translationId:v,translated:!1,status:_,remainingTime:g.remainingTime??-1};case Kt.SESSION_REQUIRED:throw new A(`Yandex auth required to translate video. See docs for more info`,g);default:throw T.error(`Unknown response`,g),new A(`Unknown response from Yandex`,g)}}async translateVideoVOTImpl({url:e,videoId:t,service:n,requestLang:r=this.requestLang,responseLang:i=this.responseLang,headers:a={},provider:o=`yandex`}){let s=Jt(n,t,e),c=await this.requestVOT(this.paths.videoTranslation,{provider:o,service:s.service,video_id:s.videoId,from_lang:r,to_lang:i,raw_video:e},{...a});if(!c.success)throw new A(`Failed to request video translation`,c);let l=c.data;switch(l.status){case`failed`:throw new A(`Yandex couldn't translate video`,l);case`success`:if(!l.translated_url)throw new A(`Audio link wasn't received from VOT response`,l);return{translationId:String(l.id),translated:!0,url:l.translated_url,status:1,remainingTime:-1};case`waiting`:return{translationId:``,translated:!1,remainingTime:l.remaining_time,status:2,message:l.message}}}async requestVtransFailAudio(e){let t=await this.requestJSON(this.paths.videoTranslationFailAudio,JSON.stringify({video_url:e}),void 0,`PUT`);if(!t.data||typeof t.data==`string`||t.data.status!==1)throw new A(`Failed to request to fake video translation fail audio js`,t);return t}async requestVtransAudio(e,t,n,r,i={}){let a=await this.getSession(`video-translation`),o;if(O.isPartialAudioBuffer(n)){if(!r)throw new A(`Partial audio metadata is required for partial audio buffer`,n);o=O.encodeTranslationAudioRequest(e,t,n,r)}else o=O.encodeTranslationAudioRequest(e,t,n,void 0);let s=this.paths.videoTranslationAudio,c=await Ct(`Vtrans`,a,o,s),l=await this.request(s,o,{...c,...i},`PUT`);if(!l.success)throw new A(`Failed to request video translation audio`,l);return O.decodeTranslationAudioResponse(l.data)}async translateVideoCache({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,headers:r={}}){let{url:i,duration:a=f.defaultDuration}=e,o=await this.getSession(`video-translation`),s=O.encodeTranslationCacheRequest(i,a,t,n),c=this.paths.videoTranslationCache,l=await Ct(`Vtrans`,o,s,c),u=await this.request(c,s,{...l,...r},`POST`);if(!u.success)throw new A(`Failed to request video translation cache`,u);return O.decodeTranslationCacheResponse(u.data)}async translateVideo({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,translationHelp:r=null,headers:i={},extraOpts:a={},shouldSendFailedAudio:o=!0}){let{url:s,videoId:c,host:l}=e;return this.isCustomLink(s)?await this.translateVideoVOTImpl({url:s,videoId:c,service:l,requestLang:t,responseLang:n,headers:i,provider:a.useLivelyVoice?`yandex_lively`:`yandex`}):await this.translateVideoYAImpl({videoData:e,requestLang:t,responseLang:n,translationHelp:r,headers:i,extraOpts:a,shouldSendFailedAudio:o})}async getSubtitlesYAImpl({videoData:e,requestLang:t=this.requestLang,headers:n={}}){let{url:r}=e,i=await this.getSession(`video-translation`),a=O.encodeSubtitlesRequest(r,t),o=this.paths.videoSubtitles,s=await Ct(`Vsubs`,i,a,o),c=await this.request(o,a,{...s,...n});if(!c.success)throw new A(`Failed to request video subtitles`,c);let l=O.decodeSubtitlesResponse(c.data),u=l.subtitles.map(e=>{let{language:t,url:n,translatedLanguage:r,translatedUrl:i}=e;return{language:t,url:n,translatedLanguage:r,translatedUrl:i}});return{waiting:l.waiting,subtitles:u}}async getSubtitlesVOTImpl({url:e,videoId:t,service:n,headers:r={}}){let i=Jt(n,t,e),a=await this.requestVOT(this.paths.videoSubtitles,{provider:`yandex`,service:i.service,video_id:i.videoId},r);if(!a.success)throw new A(`Failed to request video subtitles`,a);let o=a.data;return{waiting:!1,subtitles:o.reduce((e,t)=>{if(!t.lang_from)return e;let n=o.find(e=>e.lang===t.lang_from);return n&&e.push({language:n.lang,url:n.subtitle_url,translatedLanguage:t.lang,translatedUrl:t.subtitle_url}),e},[])}}async getSubtitles({videoData:e,requestLang:t=this.requestLang,headers:n={}}){let{url:r,videoId:i,host:a}=e;return this.isCustomLink(r)?await this.getSubtitlesVOTImpl({url:r,videoId:i,service:a,headers:n}):await this.getSubtitlesYAImpl({videoData:e,requestLang:t,headers:n})}async pingStream({pingId:e,headers:t={}}){let n=await this.getSession(`video-translation`),r=O.encodeStreamPingRequest(e),i=this.paths.streamPing,a=await Ct(`Vtrans`,n,r,i),o=await this.request(i,r,{...a,...t});if(!o.success)throw new A(`Failed to request stream ping`,o);return!0}async translateStream({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,headers:r={}}){let{url:i}=e;if(this.isCustomLink(i))throw new A(`Unsupported video URL for getting stream translation`);let a=await this.getSession(`video-translation`),o=O.encodeStreamRequest(i,t,n),s=this.paths.streamTranslation,c=await Ct(`Vtrans`,a,o,s),l=await this.request(s,o,{...c,...r});if(!l.success)throw new A(`Failed to request stream translation`,l);let u=O.decodeStreamResponse(l.data),d=u.interval;switch(d){case S.NO_CONNECTION:case S.TRANSLATING:return{translated:!1,interval:d,message:d===S.NO_CONNECTION?`streamNoConnectionToServer`:`translationTakeFewMinutes`};case S.STREAMING:if(u.pingId===void 0)throw new A(`Stream ping id wasn't received from Yandex response`,u);return{translated:!0,interval:d,pingId:u.pingId,result:u.translatedInfo};default:throw T.error(`Unknown response`,u),new A(`Unknown response from Yandex`,u)}}},Zt=class extends Xt{constructor(e={}){e.host=e.host??f.hostWorker,super(e)}async request(e,t,n={},r=`POST`){let i=this.getOpts(JSON.stringify({headers:{...this.headers,...n},body:Array.from(t)}),{"Content-Type":`application/json`},r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.arrayBuffer();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}async requestJSON(e,t=null,n={},r=`POST`){let i=this.getOpts(JSON.stringify({headers:{...this.headers,"Content-Type":`application/json`,Accept:`application/json`,...n},body:t}),{Accept:`application/json`,"Content-Type":`application/json`},r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.json();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}},Qt=class extends Xt{constructor(e){super(e),this.headers={...Et,...this.headers}}},$t=class extends Zt{constructor(e){super(e),this.headers={...Et,...this.headers}}},en=class extends Error{constructor(e){super(e),this.name=`VideoDataError`}},tn=/(file:\/\/(\/)?|(http(s)?:\/\/)(127\.0\.0\.1|localhost|192\.168\.(\d){1,3}\.(\d){1,3}))/,nn=[`yewtu.be`,`inv.nadeko.net`,`invidious.nerdvpn.de`,`invidious.protokolla.fi`,`invidious.materialio.us`,`iv.melmac.space`],rn=[`piped.video`,`piped.kavin.rocks`,`piped.private.coffee`],an=[`proxitok.pabloferreiro.es`,`proxitok.pussthecat.org`,`tok.habedieeh.re`,`proxitok.esmailelbob.xyz`,`proxitok.privacydev.net`,`tok.artemislena.eu`,`tok.adminforge.de`,`tt.vern.cc`,`cringe.whatever.social`,`proxitok.lunar.icu`,`proxitok.privacy.com.de`],on=[`peertube.tmp.rcp.tf`,`dalek.zone`,`video.sadmin.io`,`videos.viorsan.com`,`peertube.1312.media`,`tube.shanti.cafe`,`bee-tube.fr`,`video.blender.org`,`beetoons.tv`,`makertube.net`,`peertube.tv`,`framatube.org`,`tilvids.com`,`diode.zone`,`fedimovie.com`,`video.hardlimit.com`,`share.tube`,`peervideo.club`],sn=[`coursehunter.net`,`coursetrain.net`],j;(function(e){e.udemy=`udemy`,e.coursera=`coursera`,e.douyin=`douyin`,e.artstation=`artstation`,e.kickstarter=`kickstarter`,e.datacamp=`datacamp`,e.oraclelearn=`oraclelearn`,e.deeplearningai=`deeplearningai`,e.netacad=`netacad`,e.mediafile=`mediafile`})(j||={}),{...k,...j};var M={bilibiliPlayer:`.bpx-player-video-wrap, div.player-mobile-box.player-mobile-autoplay`,flowplayer:`.fp-player, div.flowplayer`,idPlayer:`#player`,jwPlayer:`.jwplayer, .jw-media`,player:`.player`,shakaPlayer:`.shaka-video-container, [id^="shaka-video-container-"]`,videoJsUniversal:`[id^='vjs_video_']:not([id*='_html5_api']):not(video), video-js:not([id*='_html5_api']), .video-js:not(video):not([id*='_html5_api']), .vjs-player:not([id*='_html5_api']), [data-vjs-player]:not([id*='_html5_api'])`,vkVideoPlayer:`.videoplayer_media, vk-video-player`},cn=[{additionalData:`mobile`,host:k.youtube,url:`https://youtu.be/`,match:/^m.youtube.com$/,selector:`.player-container`,needExtraData:!0},{host:k.youtube,url:`https://youtu.be/`,match:e=>/^(www.)?youtube(-nocookie|kids)?.com$/.test(e.hostname)&&e.pathname.startsWith(`/tv`),selector:`#container`,needExtraData:!0},{host:k.youtube,url:`https://youtu.be/`,match:/^(www.)?youtube(-nocookie|kids)?.com$/,selector:`.html5-video-container:not(#inline-player *)`,needExtraData:!0},{host:k.invidious,url:`https://youtu.be/`,match:nn,selector:M.idPlayer,needBypassCSP:!0},{host:k.piped,url:`https://youtu.be/`,match:rn,selector:M.shakaPlayer,needBypassCSP:!0},{host:k.preservetube,url:`https://preservetube.com/`,match:/^preservetube\.com$/,selector:`div.video-wrapper`,needExtraData:!0},{host:k.zdf,url:`https://www.zdf.de/play/`,match:[/^zdf.de$/,/^(www.)?zdf.de$/],selector:`div.zdfplayer-app.zdfplayer-desktop, div.zdfplayer-app`},{host:k.niconico,url:`https://www.nicovideo.jp/watch/`,match:[/^(www\.|sp\.)?nicovideo\.jp$/,/^nico\.ms$/],selector:`[class*="grid-area_[player]"] > div`},{additionalData:`mobile`,host:k.vk,url:`https://vk.com/video?z=`,match:[/^m.vk.(com|ru)$/,/^m.vkvideo.ru$/],selector:M.vkVideoPlayer,shadowRoot:!0,needExtraData:!0},{additionalData:`clips`,host:k.vk,url:`https://vk.com/video?z=`,match:/^(www.|m.)?vk.(com|ru)$/,selector:`div[data-testid="clipcontainer-video"]`,needExtraData:!0},{host:k.vk,url:`https://vk.com/video?z=`,match:[/^(www\.|m\.)?vk\.(com|ru)$/,/^(.*\.)?vkvideo\.ru$/],selector:M.vkVideoPlayer,needExtraData:!0},{host:k.nine_gag,url:`https://9gag.com/gag/`,match:/^9gag.com$/,selector:`.video-post`,needExtraData:!0},{host:k.twitch,url:`https://twitch.tv/`,match:[/^m.twitch.tv$/,/^(www.)?twitch.tv$/,/^clips.twitch.tv$/,/^player.twitch.tv$/],needExtraData:!0,selector:`.video-ref, main > div > section > div > div > div`},{host:k.proxitok,url:`https://www.tiktok.com/`,match:an,selector:`.column.has-text-centered`},{host:k.tiktok,url:`https://www.tiktok.com/`,match:/^(www.)?tiktok.com$/,selector:null},{host:j.douyin,url:`https://www.douyin.com/`,match:/^(www.)?douyin.com/,selector:`.xg-video-container`,needExtraData:!0,needBypassCSP:!0},{host:k.vimeo,url:`https://vimeo.com/`,match:/^(www\.|m\.)?vimeo.com$/,needExtraData:!0,selector:M.player},{host:k.vimeo,url:`https://player.vimeo.com/`,match:/^player.vimeo.com$/,additionalData:`embed`,needExtraData:!0,needBypassCSP:!0,selector:M.player},{host:k.xvideos,url:`https://www.xvideos.com/`,match:[/^(www.)?xvideos(-ar)?.com$/,/^(www.)?xvideos(\d\d\d).com$/,/^(www.)?xv-ru.com$/],selector:`#hlsplayer`,needBypassCSP:!0},{host:k.xhamster,url:`https://xhamster.com/`,match:e=>/^(?:[^.]+\.)?(?:xhamster\.(?:com|desi)|xhamster\d+\.(?:com|desi)|xhvid\.com)$/.test(e.host)&&/\/(?:videos\/[^/]+-[\dA-Za-z]+)\/?$/.test(e.pathname),selector:`#player-container`},{host:k.spankbang,url:`https://spankbang.com/`,match:e=>/^(?:[^.]+\.)?spankbang\.com$/.test(e.host)&&/\/(?:[\da-z]+\/(?:video|play|embed)(?:\/[^/]+)?|[\da-z]+-[\da-z]+\/playlist\/[^/?#&]+)\/?$/i.test(e.pathname),selector:`#main_video_player`},{host:k.rule34video,url:`https://rule34video.com/video/`,match:e=>/^(www\.)?rule34video\.com$/.test(e.host)&&/\/videos?\/\d+/.test(e.pathname),selector:M.flowplayer},{host:k.picarto,url:`https://picarto.tv/`,match:e=>/^(www\.)?picarto\.tv$/.test(e.host)&&/^(?:\/[^/]+\/(?:profile\/)?videos\/[^/?#&]+|\/videopopout\/[^/?#&]+|\/[^/#?]+\/?)$/.test(e.pathname),selector:`[class*="VideosTab__PlayerWrapper"]`},{host:k.olympicsreplay,url:`https://olympics.com/`,match:e=>/^(www\.)?olympics\.com$/.test(e.host)&&/^\/[a-z]{2}\/(?:[a-z0-9-]+\/)?(?:replay|videos?|original-series\/episode)\/[\w-]+\/?$/i.test(e.pathname),selector:M.videoJsUniversal},{host:k.pornhub,url:`https://rt.pornhub.com/view_video.php?viewkey=`,match:/^[a-z]+.pornhub.(com|org)$/,selector:`.mainPlayerDiv > .video-element-wrapper-js > div`,eventSelector:`.mgp_eventCatcher`},{additionalData:`embed`,host:k.pornhub,url:`https://rt.pornhub.com/view_video.php?viewkey=`,match:e=>/^[a-z]+.pornhub.(com|org)$/.exec(e.host)&&e.pathname.startsWith(`/embed/`),selector:M.idPlayer},{host:k.twitter,url:`https://twitter.com/i/status/`,match:/^(twitter|x).com$/,selector:`div[data-testid="videoComponent"]`,needBypassCSP:!0},{host:k.rumble,url:`https://rumble.com/`,match:/^rumble.com$/,selector:`[id^="vid_"] > div`},{host:k.facebook,url:`https://facebook.com/`,match:e=>e.host.includes(`facebook.com`)&&e.pathname.includes(`/videos/`),selector:`div[role="main"] div[data-pagelet$="video" i]`,needBypassCSP:!0},{additionalData:`reels`,host:k.facebook,url:`https://facebook.com/`,match:e=>e.host.includes(`facebook.com`)&&e.pathname.includes(`/reel/`),selector:`div[role="main"]`,needBypassCSP:!0},{host:k.rutube,url:`https://rutube.ru/video/`,match:/^rutube.ru$/,selector:`div[class*="videoWrapper"]`},{additionalData:`embed`,host:k.rutube,url:`https://rutube.ru/video/`,match:/^rutube.ru$/,selector:`#app > div > div`},{host:k.bilibili,url:`https://www.bilibili.com/`,match:/^(www|m|player).bilibili.com$/,selector:M.bilibiliPlayer},{host:k.bilibili,url:`https://www.bilibili.tv/`,match:/^(?:www\.|m\.)?bilibili\.tv$/,selector:M.bilibiliPlayer},{additionalData:`old`,host:k.bilibili,url:`https://www.bilibili.com/`,match:/^(www|m).bilibili.com$/,selector:null},{host:k.mailru,url:`https://my.mail.ru/`,match:/^my.mail.ru$/,selector:`#b-video-wrapper`},{host:k.bitchute,url:`https://www.bitchute.com/video/`,match:/^(www.)?bitchute.com$/,selector:M.videoJsUniversal},{host:k.eporner,url:`https://www.eporner.com/`,match:/^(www.)?eporner.com$/,selector:M.videoJsUniversal},{host:k.peertube,url:`stub`,match:on,selector:M.videoJsUniversal},{host:k.dailymotion,url:`https://www.dailymotion.com/video/`,match:/^((www\.|player\.)?dailymotion\.com|geo(\d+)?\.dailymotion\.com|dai\.ly)$/,selector:M.player},{host:k.trovo,url:`https://trovo.live/s/`,match:/^trovo.live$/,selector:`.player-video`},{host:k.yandexdisk,url:`https://yadi.sk/`,match:/^disk.yandex.(ru|kz|com(\.(am|ge|tr))?|by|az|co\.il|ee|lt|lv|md|net|tj|tm|uz)$/,selector:`.video-player__player > div:nth-child(1)`,eventSelector:`.video-player__player`,needBypassCSP:!0,needExtraData:!0},{host:k.okru,url:`https://ok.ru/video/`,match:/^ok.ru$/,selector:M.vkVideoPlayer,shadowRoot:!0},{host:k.googledrive,url:`https://drive.google.com/file/d/`,match:/^youtube.googleapis.com$/,selector:`.html5-video-container`},{host:k.bannedvideo,url:`https://madmaxworld.tv/watch?id=`,match:/^(www.)?banned.video|madmaxworld.tv$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.weverse,url:`https://weverse.io/`,match:/^weverse.io$/,selector:`.webplayer-internal-source-wrapper`,needExtraData:!0},{host:k.weibo,url:`https://weibo.com/`,match:e=>/^(?:www\.)?weibo\.com$/.test(e.host)&&/^\/(?:\d+\/[A-Za-z0-9]+|0\/[A-Za-z0-9]+|tv\/show\/\d+:(?:[\da-f]{32}|\d{16,}))\/?$/.test(e.pathname)||/^video\.weibo\.com$/.test(e.host)&&/^\/show\/?$/.test(e.pathname)&&/^\d+:(?:[\da-f]{32}|\d{16,})$/i.test(e.searchParams.get(`fid`)??``)||/^(?:www\.)?weibo\.com$/.test(e.host)&&/^\/newlogin\/?$/.test(e.pathname)&&(e.searchParams.has(`url`)||/^[A-Za-z0-9]+$/.test(e.searchParams.get(`layerid`)??``)),selector:M.videoJsUniversal||`#playVideo`},{host:k.newgrounds,url:`https://www.newgrounds.com/`,match:/^(www.)?newgrounds.com$/,selector:`.ng-video-player`},{host:k.egghead,url:`https://egghead.io/`,match:/^egghead.io$/,selector:`.cueplayer-react-video-holder`},{host:k.youku,url:`https://v.youku.com/`,match:/^v.youku.com$/,selector:`#ykPlayer`},{host:k.archive,url:`https://archive.org/details/`,match:/^archive.org$/,selector:M.jwPlayer},{host:k.kodik,url:`stub`,match:/^kodik.(info|biz|cc)$/,selector:M.flowplayer,needExtraData:!0},{host:k.patreon,url:`stub`,match:/^(www.)?patreon.com$/,selector:`div[data-tag="post-card"] div[elevation="subtle"] > div > div > div > div`,needExtraData:!0},{additionalData:`old`,host:k.reddit,url:`stub`,match:/^old.reddit.com$/,selector:`.reddit-video-player-root`,needExtraData:!0,needBypassCSP:!0},{host:k.reddit,url:`stub`,match:/^(www.|new.)?reddit.com$/,selector:`div[slot=post-media-container]`,shadowRoot:!0,needExtraData:!0,needBypassCSP:!0},{host:k.kick,url:`https://kick.com/`,match:/^kick.com$/,selector:`#injected-embedded-channel-player-video > div`,needExtraData:!0},{host:k.appledeveloper,url:`https://developer.apple.com/`,match:/^developer.apple.com$/,selector:`.developer-video-player`,needExtraData:!0,needBypassCSP:!0},{host:k.epicgames,url:`https://dev.epicgames.com/community/learning/`,match:/^dev.epicgames.com$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.odysee,url:`stub`,match:/^odysee.com$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.coursehunterLike,url:`stub`,match:sn,selector:null,needExtraData:!0},{host:k.sap,url:`https://learning.sap.com/courses/`,match:/^learning.sap.com$/,selector:`.playkit-container`,eventSelector:`.playkit-player`,needExtraData:!0,needBypassCSP:!0},{host:j.udemy,url:`https://www.udemy.com/`,match:/udemy.com$/,selector:M.shakaPlayer,needExtraData:!0},{host:j.datacamp,url:`https://www.datacamp.com/courses/`,match:e=>/^(?:campus\.|projector\.)?datacamp\.com$/.test(e.hostname),selector:M.videoJsUniversal,needExtraData:!0},{host:j.coursera,url:`https://www.coursera.org/`,match:/coursera.org$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.watchpornto,url:`https://watchporn.to/`,match:/^watchporn.to$/,selector:M.flowplayer},{host:k.jove,url:`https://jove.com/`,match:/^(?:app|www)\.jove\.com$/,selector:M.flowplayer},{host:k.linkedin,url:`https://www.linkedin.com/learning/`,match:/^(www.)?linkedin.com$/,selector:M.videoJsUniversal,needExtraData:!0,needBypassCSP:!0},{host:k.incestflix,url:`https://www.incestflix.net/watch/`,match:/^(www.)?incestflix.(net|to|com)$/,selector:`#incflix-stream`,needExtraData:!0},{host:k.porntn,url:`https://porntn.com/videos/`,match:/^porntn.com$/,selector:M.flowplayer,needExtraData:!0},{host:k.dzen,url:`https://dzen.ru/video/watch/`,match:/^dzen.ru$/,selector:`[class*="player__playerWrap"] > div`},{host:k.bunnystream,url:`stub`,match:[/^video\.bunnycdn\.com$/,/^iframe\.mediadelivery\.net$/,/^(?:[^.]+\.)*b-cdn\.net$/],selector:null},{host:k.cloudflarestream,url:`stub`,match:/^(watch|embed|iframe|customer-[^.]+).cloudflarestream.com$/,selector:null},{host:k.loom,url:`https://www.loom.com/share/`,match:/^(www.)?loom.com$/,selector:`.VideoLayersContainer`,needExtraData:!0,needBypassCSP:!0},{host:j.artstation,url:`https://www.artstation.com/learning/`,match:/^(www.)?artstation.com$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.rtnews,url:`https://www.rt.com/`,match:/^(www.)?rt.com$/,selector:M.jwPlayer,needExtraData:!0},{host:k.bitview,url:`https://www.bitview.net/watch?v=`,match:/^(www.)?bitview.net$/,selector:`.vlScreen`,needExtraData:!0},{host:j.kickstarter,url:`https://www.kickstarter.com/`,match:/^(www.)?kickstarter.com/,selector:`.ksr-video-player`,needExtraData:!0},{host:k.thisvid,url:`https://thisvid.com/`,match:/^(www.)?thisvid.com$/,selector:M.flowplayer},{additionalData:`regional`,host:k.ign,url:`https://de.ign.com/`,match:/^(\w{2}.)?ign.com$/,needExtraData:!0,selector:`.video-container`},{host:k.ign,url:`https://www.ign.com/`,match:/^(www.)?ign.com$/,selector:M.player,needExtraData:!0},{host:k.bunkr,url:`https://bunkr.site/`,match:/^bunkr\.(site|black|cat|media|red|site|ws|org|s[kiu]|c[ir]|fi|p[hks]|ru|la|is|to|a[cx])$/,needExtraData:!0,selector:`.plyr__video-wrapper`},{host:k.imdb,url:`https://www.imdb.com/video/`,match:/^(www\.)?imdb\.com$/,selector:M.jwPlayer},{host:k.telegram,url:`https://t.me/`,match:e=>/^web\.telegram\.org$/.test(e.hostname)&&e.pathname.startsWith(`/k`),selector:`.ckin__player`},{host:j.oraclelearn,url:`https://mylearn.oracle.com/ou/course/`,match:/^mylearn\.oracle\.com/,selector:M.videoJsUniversal,needExtraData:!0,needBypassCSP:!0},{host:j.deeplearningai,url:`https://learn.deeplearning.ai/courses/`,match:/^learn(-dev|-staging)?\.deeplearning\.ai/,selector:`.lesson-video-player`,needExtraData:!0},{host:j.netacad,url:`https://www.netacad.com/`,match:/^(www\.)?netacad\.com/,selector:M.videoJsUniversal,needExtraData:!0},{host:j.mediafile,url:`https://mediafile.cc/`,match:/^(www\.)?mediafile\.cc$/,selector:`div#playerContainer`,needExtraData:!0},{host:k.custom,url:`stub`,match:e=>/([^.]+)\.(mp4|webm)/.test(e.pathname),rawResult:!0}],N=class extends Error{constructor(e){super(e),this.name=`VideoHelperError`}},P=class{API_ORIGIN=window.location.origin;fetch;extraInfo;referer;origin;service;video;language;constructor({fetchFn:e=Ot,extraInfo:t=!0,referer:n=document.referrer??`${window.location.origin}/`,origin:r=window.location.origin,service:i,video:a,language:o=`en`}={}){this.fetch=e,this.extraInfo=t,this.referer=n,this.origin=/^(http(s)?):\/\//.test(String(r))?r:window.location.origin,this.service=i,this.video=a,this.language=o}getVideoData(e){return Promise.resolve(void 0)}getVideoId(e){return Promise.resolve(void 0)}returnBaseData(e){if(this.service)return{url:this.service.url+e,videoId:e,host:this.service.host,duration:void 0}}},ln=class extends P{API_ORIGIN=`https://developer.apple.com`;async getVideoData(e){try{let e=document.querySelector(`meta[property='og:video']`)?.content;if(!e)throw new N(`Failed to find content url`);return{url:e}}catch(t){T.error(`Failed to get apple developer video data by video ID: ${e}`,t.message);return}}async getVideoId(e){return/videos\/play\/([^/]+)\/([\d]+)/.exec(e.pathname)?.[0]}},un=class extends P{async getVideoId(e){return/(details|embed)\/([^/]+)/.exec(e.pathname)?.[2]}},dn=class extends P{API_ORIGIN=`https://www.artstation.com/api/v2/learning`;getCSRFToken(){return document.querySelector(`meta[name="public-csrf-token"]`)?.content}async getCourseInfo(e){try{let t=this.getCSRFToken();return await(await this.fetch(`${this.API_ORIGIN}/courses/${e}/autoplay.json`,{method:`POST`,headers:t?{"PUBLIC-CSRF-TOKEN":t}:{}})).json()}catch(t){return T.error(`Failed to get artstation course info by courseId: ${e}.`,t.message),!1}}async getVideoUrl(e){try{return(await(await this.fetch(`${this.API_ORIGIN}/quicksilver/video_url.json?chapter_id=${e}`)).json()).url.replace(`qsep://`,`https://`)}catch(t){return T.error(`Failed to get artstation video url by chapterId: ${e}.`,t.message),!1}}async getVideoData(e){let[,t,,,n]=e.split(`/`),r=await this.getCourseInfo(t);if(!r)return;let i=r.chapters.find(e=>e.hash_id===n);if(!i)return;let a=await this.getVideoUrl(i.id);if(!a)return;let{title:o,duration:s,subtitles:c}=i;return{url:a,title:o,duration:s,subtitles:c.filter(e=>e.format===`vtt`).map(e=>({language:E(e.locale),source:`artstation`,format:`vtt`,url:e.file_url}))}}async getVideoId(e){return/courses\/(\w{3,5})\/([^/]+)\/chapters\/(\w{3,5})/.exec(e.pathname)?.[0]}},fn=class extends P{API_ORIGIN=`https://api.banned.video`;async getVideoInfo(e){try{return await(await this.fetch(`${this.API_ORIGIN}/graphql`,{method:`POST`,body:JSON.stringify({operationName:`GetVideo`,query:`query GetVideo($id: String!) { +======= +var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t)=>()=>(e&&(t=e(e=0)),t),c=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),l=(e,t)=>{let r={};for(var i in e)n(r,i,{get:e[i],enumerable:!0});return t||n(r,Symbol.toStringTag,{value:`Module`}),r},u=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;lt[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},d=(e,r,i)=>(i=e==null?{}:t(a(e)),u(r||!e||!e.__esModule?n(i,`default`,{value:e,enumerable:!0}):i,e)),f={host:`api.browser.yandex.ru`,hostVOT:`vot.toil.cc/v1`,hostWorker:`vot-worker.toil.cc`,mediaProxy:`media-proxy.transly.workers.dev`,userAgent:` Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 YaBrowser/26.3.3.869 Yowser/2.5 Safari/537.36`,componentVersion:`26.3.3.869`,hmac:`bt8xH3VOlb4mqf0nqAibnDOoiPlXsisf`,defaultDuration:310,minChunkSize:5295308,loggerLevel:1,version:`2.4.17`};function p(){let e=0,t=0;for(let n=0;n<28;n+=7){let r=this.buf[this.pos++];if(e|=(r&127)<>4,!(n&128))return this.assertBounds(),[e,t];for(let n=3;n<=31;n+=7){let r=this.buf[this.pos++];if(t|=(r&127)<>>r,a=!(!(i>>>7)&&t==0),o=(a?i|128:i)&255;if(n.push(o),!a)return}let r=e>>>28&15|(t&7)<<4,i=!!(t>>3);if(n.push((i?r|128:r)&255),i){for(let e=3;e<31;e+=7){let r=t>>>e,i=!!(r>>>7),a=(i?r|128:r)&255;if(n.push(a),!i)return}n.push(t>>>31&1)}}var h=4294967296;function g(e){let t=e[0]===`-`;t&&(e=e.slice(1));let n=1e6,r=0,i=0;function a(t,a){let o=Number(e.slice(t,a));i*=n,r=r*n+o,r>=h&&(i+=r/h|0,r%=h)}return a(-24,-18),a(-18,-12),a(-12,-6),a(-6),t?ne(r,i):te(r,i)}function _(e,t){let n=te(e,t),r=n.hi&2147483648;r&&(n=ne(n.lo,n.hi));let i=v(n.lo,n.hi);return r?`-`+i:i}function v(e,t){if({lo:e,hi:t}=ee(e,t),t<=2097151)return String(h*t+e);let n=e&16777215,r=(e>>>24|t<<8)&16777215,i=t>>16&65535,a=n+r*6777216+i*6710656,o=r+i*8147497,s=i*2,c=1e7;return a>=c&&(o+=Math.floor(a/c),a%=c),o>=c&&(s+=Math.floor(o/c),o%=c),s.toString()+re(o)+re(a)}function ee(e,t){return{lo:e>>>0,hi:t>>>0}}function te(e,t){return{lo:e|0,hi:t|0}}function ne(e,t){return t=~t,e?e=~e+1:t+=1,te(e,t)}var re=e=>{let t=String(e);return`0000000`.slice(t.length)+t};function ie(e,t){if(e>=0){for(;e>127;)t.push(e&127|128),e>>>=7;t.push(e)}else{for(let n=0;n<9;n++)t.push(e&127|128),e>>=7;t.push(1)}}function ae(){let e=this.buf[this.pos++],t=e&127;if(!(e&128)||(e=this.buf[this.pos++],t|=(e&127)<<7,!(e&128))||(e=this.buf[this.pos++],t|=(e&127)<<14,!(e&128))||(e=this.buf[this.pos++],t|=(e&127)<<21,!(e&128)))return this.assertBounds(),t;e=this.buf[this.pos++],t|=(e&15)<<28;for(let t=5;e&128&&t<10;t++)e=this.buf[this.pos++];if(e&128)throw Error(`invalid varint`);return this.assertBounds(),t>>>0}var y=oe();function oe(){let e=new DataView(new ArrayBuffer(8));if(typeof BigInt==`function`&&typeof e.getBigInt64==`function`&&typeof e.getBigUint64==`function`&&typeof e.setBigInt64==`function`&&typeof e.setBigUint64==`function`&&(typeof process!=`object`||typeof process.env!=`object`||process.env.BUF_BIGINT_DISABLE!==`1`)){let t=BigInt(`-9223372036854775808`),n=BigInt(`9223372036854775807`),r=BigInt(`0`),i=BigInt(`18446744073709551615`);return{zero:BigInt(0),supported:!0,parse(e){let r=typeof e==`bigint`?e:BigInt(e);if(r>n||ri||t>>0)}raw(e){return this.buf.length&&(this.chunks.push(new Uint8Array(this.buf)),this.buf=[]),this.chunks.push(e),this}uint32(e){for(pe(e);e>127;)this.buf.push(e&127|128),e>>>=7;return this.buf.push(e),this}int32(e){return fe(e),ie(e,this.buf),this}bool(e){return this.buf.push(e?1:0),this}bytes(e){return this.uint32(e.byteLength),this.raw(e)}string(e){let t=this.encodeUtf8(e);return this.uint32(t.byteLength),this.raw(t)}float(e){me(e);let t=new Uint8Array(4);return new DataView(t.buffer).setFloat32(0,e,!0),this.raw(t)}double(e){let t=new Uint8Array(8);return new DataView(t.buffer).setFloat64(0,e,!0),this.raw(t)}fixed32(e){pe(e);let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!0),this.raw(t)}sfixed32(e){fe(e);let t=new Uint8Array(4);return new DataView(t.buffer).setInt32(0,e,!0),this.raw(t)}sint32(e){return fe(e),e=(e<<1^e>>31)>>>0,ie(e,this.buf),this}sfixed64(e){let t=new Uint8Array(8),n=new DataView(t.buffer),r=y.enc(e);return n.setInt32(0,r.lo,!0),n.setInt32(4,r.hi,!0),this.raw(t)}fixed64(e){let t=new Uint8Array(8),n=new DataView(t.buffer),r=y.uEnc(e);return n.setInt32(0,r.lo,!0),n.setInt32(4,r.hi,!0),this.raw(t)}int64(e){let t=y.enc(e);return m(t.lo,t.hi,this.buf),this}sint64(e){let t=y.enc(e),n=t.hi>>31;return m(t.lo<<1^n,(t.hi<<1|t.lo>>>31)^n,this.buf),this}uint64(e){let t=y.uEnc(e);return m(t.lo,t.hi,this.buf),this}},x=class{constructor(e,t=ue().decodeUtf8){this.decodeUtf8=t,this.varint64=p,this.uint32=ae,this.buf=e,this.len=e.length,this.pos=0,this.view=new DataView(e.buffer,e.byteOffset,e.byteLength)}tag(){let e=this.uint32(),t=e>>>3,n=e&7;if(t<=0||n<0||n>5)throw Error(`illegal tag: field no `+t+` wire type `+n);return[t,n]}skip(e,t){let n=this.pos;switch(e){case de.Varint:for(;this.buf[this.pos++]&128;);break;case de.Bit64:this.pos+=4;case de.Bit32:this.pos+=4;break;case de.LengthDelimited:let n=this.uint32();this.pos+=n;break;case de.StartGroup:for(;;){let[e,n]=this.tag();if(n===de.EndGroup){if(t!==void 0&&e!==t)throw Error(`invalid end group tag`);break}this.skip(n,e)}break;default:throw Error(`cant skip wire type `+e)}return this.assertBounds(),this.buf.subarray(n,this.pos)}assertBounds(){if(this.pos>this.len)throw RangeError(`premature EOF`)}int32(){return this.uint32()|0}sint32(){let e=this.uint32();return e>>>1^-(e&1)}int64(){return y.dec(...this.varint64())}uint64(){return y.uDec(...this.varint64())}sint64(){let[e,t]=this.varint64(),n=-(e&1);return e=(e>>>1|(t&1)<<31)^n,t=t>>>1^n,y.dec(e,t)}bool(){let[e,t]=this.varint64();return e!==0||t!==0}fixed32(){return this.view.getUint32((this.pos+=4)-4,!0)}sfixed32(){return this.view.getInt32((this.pos+=4)-4,!0)}fixed64(){return y.uDec(this.sfixed32(),this.sfixed32())}sfixed64(){return y.dec(this.sfixed32(),this.sfixed32())}float(){return this.view.getFloat32((this.pos+=4)-4,!0)}double(){return this.view.getFloat64((this.pos+=8)-8,!0)}bytes(){let e=this.uint32(),t=this.pos;return this.pos+=e,this.assertBounds(),this.buf.subarray(t,t+e)}string(){return this.decodeUtf8(this.bytes())}};function fe(e){if(typeof e==`string`)e=Number(e);else if(typeof e!=`number`)throw Error(`invalid int32: `+typeof e);if(!Number.isInteger(e)||e>2147483647||e<-2147483648)throw Error(`invalid int32: `+e)}function pe(e){if(typeof e==`string`)e=Number(e);else if(typeof e!=`number`)throw Error(`invalid uint32: `+typeof e);if(!Number.isInteger(e)||e>4294967295||e<0)throw Error(`invalid uint32: `+e)}function me(e){if(typeof e==`string`){let t=e;if(e=Number(e),isNaN(e)&&t!==`NaN`)throw Error(`invalid float32: `+t)}else if(typeof e!=`number`)throw Error(`invalid float32: `+typeof e);if(Number.isFinite(e)&&(e>34028234663852886e22||e<-34028234663852886e22))throw Error(`invalid float32: `+e)}var S;(function(e){e[e.NO_CONNECTION=0]=`NO_CONNECTION`,e[e.TRANSLATING=10]=`TRANSLATING`,e[e.STREAMING=20]=`STREAMING`,e[e.UNRECOGNIZED=-1]=`UNRECOGNIZED`})(S||={});function he(e){switch(e){case 0:case`NO_CONNECTION`:return S.NO_CONNECTION;case 10:case`TRANSLATING`:return S.TRANSLATING;case 20:case`STREAMING`:return S.STREAMING;default:return S.UNRECOGNIZED}}function ge(e){switch(e){case S.NO_CONNECTION:return`NO_CONNECTION`;case S.TRANSLATING:return`TRANSLATING`;case S.STREAMING:return`STREAMING`;case S.UNRECOGNIZED:default:return`UNRECOGNIZED`}}function _e(){return{target:``,targetUrl:``}}var ve={encode(e,t=new b){return e.target!==``&&t.uint32(10).string(e.target),e.targetUrl!==``&&t.uint32(18).string(e.targetUrl),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=_e();for(;n.pos>>3){case 1:if(e!==10)break;i.target=n.string();continue;case 2:if(e!==18)break;i.targetUrl=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{target:w(e.target)?globalThis.String(e.target):``,targetUrl:w(e.targetUrl)?globalThis.String(e.targetUrl):``}},toJSON(e){let t={};return e.target!==``&&(t.target=e.target),e.targetUrl!==``&&(t.targetUrl=e.targetUrl),t},create(e){return ve.fromPartial(e??{})},fromPartial(e){let t=_e();return t.target=e.target??``,t.targetUrl=e.targetUrl??``,t}};function ye(){return{url:``,deviceId:void 0,firstRequest:!1,duration:0,unknown0:0,language:``,forceSourceLang:!1,unknown1:0,translationHelp:[],wasStream:!1,responseLanguage:``,unknown2:0,unknown3:0,bypassCache:!1,useLivelyVoice:!1,videoTitle:``}}var be={encode(e,t=new b){e.url!==``&&t.uint32(26).string(e.url),e.deviceId!==void 0&&t.uint32(34).string(e.deviceId),e.firstRequest!==!1&&t.uint32(40).bool(e.firstRequest),e.duration!==0&&t.uint32(49).double(e.duration),e.unknown0!==0&&t.uint32(56).int32(e.unknown0),e.language!==``&&t.uint32(66).string(e.language),e.forceSourceLang!==!1&&t.uint32(72).bool(e.forceSourceLang),e.unknown1!==0&&t.uint32(80).int32(e.unknown1);for(let n of e.translationHelp)ve.encode(n,t.uint32(90).fork()).join();return e.wasStream!==!1&&t.uint32(104).bool(e.wasStream),e.responseLanguage!==``&&t.uint32(114).string(e.responseLanguage),e.unknown2!==0&&t.uint32(120).int32(e.unknown2),e.unknown3!==0&&t.uint32(128).int32(e.unknown3),e.bypassCache!==!1&&t.uint32(136).bool(e.bypassCache),e.useLivelyVoice!==!1&&t.uint32(144).bool(e.useLivelyVoice),e.videoTitle!==``&&t.uint32(154).string(e.videoTitle),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=ye();for(;n.pos>>3){case 3:if(e!==26)break;i.url=n.string();continue;case 4:if(e!==34)break;i.deviceId=n.string();continue;case 5:if(e!==40)break;i.firstRequest=n.bool();continue;case 6:if(e!==49)break;i.duration=n.double();continue;case 7:if(e!==56)break;i.unknown0=n.int32();continue;case 8:if(e!==66)break;i.language=n.string();continue;case 9:if(e!==72)break;i.forceSourceLang=n.bool();continue;case 10:if(e!==80)break;i.unknown1=n.int32();continue;case 11:if(e!==90)break;i.translationHelp.push(ve.decode(n,n.uint32()));continue;case 13:if(e!==104)break;i.wasStream=n.bool();continue;case 14:if(e!==114)break;i.responseLanguage=n.string();continue;case 15:if(e!==120)break;i.unknown2=n.int32();continue;case 16:if(e!==128)break;i.unknown3=n.int32();continue;case 17:if(e!==136)break;i.bypassCache=n.bool();continue;case 18:if(e!==144)break;i.useLivelyVoice=n.bool();continue;case 19:if(e!==154)break;i.videoTitle=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,deviceId:w(e.deviceId)?globalThis.String(e.deviceId):void 0,firstRequest:w(e.firstRequest)?globalThis.Boolean(e.firstRequest):!1,duration:w(e.duration)?globalThis.Number(e.duration):0,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):0,language:w(e.language)?globalThis.String(e.language):``,forceSourceLang:w(e.forceSourceLang)?globalThis.Boolean(e.forceSourceLang):!1,unknown1:w(e.unknown1)?globalThis.Number(e.unknown1):0,translationHelp:globalThis.Array.isArray(e?.translationHelp)?e.translationHelp.map(e=>ve.fromJSON(e)):[],wasStream:w(e.wasStream)?globalThis.Boolean(e.wasStream):!1,responseLanguage:w(e.responseLanguage)?globalThis.String(e.responseLanguage):``,unknown2:w(e.unknown2)?globalThis.Number(e.unknown2):0,unknown3:w(e.unknown3)?globalThis.Number(e.unknown3):0,bypassCache:w(e.bypassCache)?globalThis.Boolean(e.bypassCache):!1,useLivelyVoice:w(e.useLivelyVoice)?globalThis.Boolean(e.useLivelyVoice):!1,videoTitle:w(e.videoTitle)?globalThis.String(e.videoTitle):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.deviceId!==void 0&&(t.deviceId=e.deviceId),e.firstRequest!==!1&&(t.firstRequest=e.firstRequest),e.duration!==0&&(t.duration=e.duration),e.unknown0!==0&&(t.unknown0=Math.round(e.unknown0)),e.language!==``&&(t.language=e.language),e.forceSourceLang!==!1&&(t.forceSourceLang=e.forceSourceLang),e.unknown1!==0&&(t.unknown1=Math.round(e.unknown1)),e.translationHelp?.length&&(t.translationHelp=e.translationHelp.map(e=>ve.toJSON(e))),e.wasStream!==!1&&(t.wasStream=e.wasStream),e.responseLanguage!==``&&(t.responseLanguage=e.responseLanguage),e.unknown2!==0&&(t.unknown2=Math.round(e.unknown2)),e.unknown3!==0&&(t.unknown3=Math.round(e.unknown3)),e.bypassCache!==!1&&(t.bypassCache=e.bypassCache),e.useLivelyVoice!==!1&&(t.useLivelyVoice=e.useLivelyVoice),e.videoTitle!==``&&(t.videoTitle=e.videoTitle),t},create(e){return be.fromPartial(e??{})},fromPartial(e){let t=ye();return t.url=e.url??``,t.deviceId=e.deviceId??void 0,t.firstRequest=e.firstRequest??!1,t.duration=e.duration??0,t.unknown0=e.unknown0??0,t.language=e.language??``,t.forceSourceLang=e.forceSourceLang??!1,t.unknown1=e.unknown1??0,t.translationHelp=e.translationHelp?.map(e=>ve.fromPartial(e))||[],t.wasStream=e.wasStream??!1,t.responseLanguage=e.responseLanguage??``,t.unknown2=e.unknown2??0,t.unknown3=e.unknown3??0,t.bypassCache=e.bypassCache??!1,t.useLivelyVoice=e.useLivelyVoice??!1,t.videoTitle=e.videoTitle??``,t}};function xe(){return{url:void 0,duration:void 0,status:0,remainingTime:void 0,unknown0:void 0,translationId:``,language:void 0,message:void 0,isLivelyVoice:!1,unknown2:void 0,shouldRetry:void 0,unknown3:void 0}}var Se={encode(e,t=new b){return e.url!==void 0&&t.uint32(10).string(e.url),e.duration!==void 0&&t.uint32(17).double(e.duration),e.status!==0&&t.uint32(32).int32(e.status),e.remainingTime!==void 0&&t.uint32(40).int32(e.remainingTime),e.unknown0!==void 0&&t.uint32(48).int32(e.unknown0),e.translationId!==``&&t.uint32(58).string(e.translationId),e.language!==void 0&&t.uint32(66).string(e.language),e.message!==void 0&&t.uint32(74).string(e.message),e.isLivelyVoice!==!1&&t.uint32(80).bool(e.isLivelyVoice),e.unknown2!==void 0&&t.uint32(88).int32(e.unknown2),e.shouldRetry!==void 0&&t.uint32(96).int32(e.shouldRetry),e.unknown3!==void 0&&t.uint32(104).int32(e.unknown3),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=xe();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==17)break;i.duration=n.double();continue;case 4:if(e!==32)break;i.status=n.int32();continue;case 5:if(e!==40)break;i.remainingTime=n.int32();continue;case 6:if(e!==48)break;i.unknown0=n.int32();continue;case 7:if(e!==58)break;i.translationId=n.string();continue;case 8:if(e!==66)break;i.language=n.string();continue;case 9:if(e!==74)break;i.message=n.string();continue;case 10:if(e!==80)break;i.isLivelyVoice=n.bool();continue;case 11:if(e!==88)break;i.unknown2=n.int32();continue;case 12:if(e!==96)break;i.shouldRetry=n.int32();continue;case 13:if(e!==104)break;i.unknown3=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):void 0,duration:w(e.duration)?globalThis.Number(e.duration):void 0,status:w(e.status)?globalThis.Number(e.status):0,remainingTime:w(e.remainingTime)?globalThis.Number(e.remainingTime):void 0,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):void 0,translationId:w(e.translationId)?globalThis.String(e.translationId):``,language:w(e.language)?globalThis.String(e.language):void 0,message:w(e.message)?globalThis.String(e.message):void 0,isLivelyVoice:w(e.isLivelyVoice)?globalThis.Boolean(e.isLivelyVoice):!1,unknown2:w(e.unknown2)?globalThis.Number(e.unknown2):void 0,shouldRetry:w(e.shouldRetry)?globalThis.Number(e.shouldRetry):void 0,unknown3:w(e.unknown3)?globalThis.Number(e.unknown3):void 0}},toJSON(e){let t={};return e.url!==void 0&&(t.url=e.url),e.duration!==void 0&&(t.duration=e.duration),e.status!==0&&(t.status=Math.round(e.status)),e.remainingTime!==void 0&&(t.remainingTime=Math.round(e.remainingTime)),e.unknown0!==void 0&&(t.unknown0=Math.round(e.unknown0)),e.translationId!==``&&(t.translationId=e.translationId),e.language!==void 0&&(t.language=e.language),e.message!==void 0&&(t.message=e.message),e.isLivelyVoice!==!1&&(t.isLivelyVoice=e.isLivelyVoice),e.unknown2!==void 0&&(t.unknown2=Math.round(e.unknown2)),e.shouldRetry!==void 0&&(t.shouldRetry=Math.round(e.shouldRetry)),e.unknown3!==void 0&&(t.unknown3=Math.round(e.unknown3)),t},create(e){return Se.fromPartial(e??{})},fromPartial(e){let t=xe();return t.url=e.url??void 0,t.duration=e.duration??void 0,t.status=e.status??0,t.remainingTime=e.remainingTime??void 0,t.unknown0=e.unknown0??void 0,t.translationId=e.translationId??``,t.language=e.language??void 0,t.message=e.message??void 0,t.isLivelyVoice=e.isLivelyVoice??!1,t.unknown2=e.unknown2??void 0,t.shouldRetry=e.shouldRetry??void 0,t.unknown3=e.unknown3??void 0,t}};function Ce(){return{status:0,remainingTime:void 0,message:void 0,unknown0:void 0}}var C={encode(e,t=new b){return e.status!==0&&t.uint32(8).int32(e.status),e.remainingTime!==void 0&&t.uint32(16).int32(e.remainingTime),e.message!==void 0&&t.uint32(26).string(e.message),e.unknown0!==void 0&&t.uint32(32).int32(e.unknown0),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ce();for(;n.pos>>3){case 1:if(e!==8)break;i.status=n.int32();continue;case 2:if(e!==16)break;i.remainingTime=n.int32();continue;case 3:if(e!==26)break;i.message=n.string();continue;case 4:if(e!==32)break;i.unknown0=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{status:w(e.status)?globalThis.Number(e.status):0,remainingTime:w(e.remainingTime)?globalThis.Number(e.remainingTime):void 0,message:w(e.message)?globalThis.String(e.message):void 0,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):void 0}},toJSON(e){let t={};return e.status!==0&&(t.status=Math.round(e.status)),e.remainingTime!==void 0&&(t.remainingTime=Math.round(e.remainingTime)),e.message!==void 0&&(t.message=e.message),e.unknown0!==void 0&&(t.unknown0=Math.round(e.unknown0)),t},create(e){return C.fromPartial(e??{})},fromPartial(e){let t=Ce();return t.status=e.status??0,t.remainingTime=e.remainingTime??void 0,t.message=e.message??void 0,t.unknown0=e.unknown0??void 0,t}};function we(){return{url:``,duration:0,language:``,responseLanguage:``}}var Te={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.duration!==0&&t.uint32(17).double(e.duration),e.language!==``&&t.uint32(26).string(e.language),e.responseLanguage!==``&&t.uint32(34).string(e.responseLanguage),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=we();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==17)break;i.duration=n.double();continue;case 3:if(e!==26)break;i.language=n.string();continue;case 4:if(e!==34)break;i.responseLanguage=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,duration:w(e.duration)?globalThis.Number(e.duration):0,language:w(e.language)?globalThis.String(e.language):``,responseLanguage:w(e.responseLanguage)?globalThis.String(e.responseLanguage):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.duration!==0&&(t.duration=e.duration),e.language!==``&&(t.language=e.language),e.responseLanguage!==``&&(t.responseLanguage=e.responseLanguage),t},create(e){return Te.fromPartial(e??{})},fromPartial(e){let t=we();return t.url=e.url??``,t.duration=e.duration??0,t.language=e.language??``,t.responseLanguage=e.responseLanguage??``,t}};function Ee(){return{default:void 0,cloning:void 0}}var De={encode(e,t=new b){return e.default!==void 0&&C.encode(e.default,t.uint32(10).fork()).join(),e.cloning!==void 0&&C.encode(e.cloning,t.uint32(18).fork()).join(),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ee();for(;n.pos>>3){case 1:if(e!==10)break;i.default=C.decode(n,n.uint32());continue;case 2:if(e!==18)break;i.cloning=C.decode(n,n.uint32());continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{default:w(e.default)?C.fromJSON(e.default):void 0,cloning:w(e.cloning)?C.fromJSON(e.cloning):void 0}},toJSON(e){let t={};return e.default!==void 0&&(t.default=C.toJSON(e.default)),e.cloning!==void 0&&(t.cloning=C.toJSON(e.cloning)),t},create(e){return De.fromPartial(e??{})},fromPartial(e){let t=Ee();return t.default=e.default!==void 0&&e.default!==null?C.fromPartial(e.default):void 0,t.cloning=e.cloning!==void 0&&e.cloning!==null?C.fromPartial(e.cloning):void 0,t}};function Oe(){return{audioFile:new Uint8Array,fileId:``}}var ke={encode(e,t=new b){return e.audioFile.length!==0&&t.uint32(18).bytes(e.audioFile),e.fileId!==``&&t.uint32(10).string(e.fileId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Oe();for(;n.pos>>3){case 2:if(e!==18)break;i.audioFile=n.bytes();continue;case 1:if(e!==10)break;i.fileId=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{audioFile:w(e.audioFile)?nt(e.audioFile):new Uint8Array,fileId:w(e.fileId)?globalThis.String(e.fileId):``}},toJSON(e){let t={};return e.audioFile.length!==0&&(t.audioFile=rt(e.audioFile)),e.fileId!==``&&(t.fileId=e.fileId),t},create(e){return ke.fromPartial(e??{})},fromPartial(e){let t=Oe();return t.audioFile=e.audioFile??new Uint8Array,t.fileId=e.fileId??``,t}};function Ae(){return{audioFile:new Uint8Array,chunkId:0}}var je={encode(e,t=new b){return e.audioFile.length!==0&&t.uint32(18).bytes(e.audioFile),e.chunkId!==0&&t.uint32(8).int32(e.chunkId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ae();for(;n.pos>>3){case 2:if(e!==18)break;i.audioFile=n.bytes();continue;case 1:if(e!==8)break;i.chunkId=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{audioFile:w(e.audioFile)?nt(e.audioFile):new Uint8Array,chunkId:w(e.chunkId)?globalThis.Number(e.chunkId):0}},toJSON(e){let t={};return e.audioFile.length!==0&&(t.audioFile=rt(e.audioFile)),e.chunkId!==0&&(t.chunkId=Math.round(e.chunkId)),t},create(e){return je.fromPartial(e??{})},fromPartial(e){let t=Ae();return t.audioFile=e.audioFile??new Uint8Array,t.chunkId=e.chunkId??0,t}};function Me(){return{audioBuffer:void 0,audioPartsLength:0,fileId:``,version:0}}var Ne={encode(e,t=new b){return e.audioBuffer!==void 0&&je.encode(e.audioBuffer,t.uint32(10).fork()).join(),e.audioPartsLength!==0&&t.uint32(16).int32(e.audioPartsLength),e.fileId!==``&&t.uint32(26).string(e.fileId),e.version!==0&&t.uint32(32).int32(e.version),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Me();for(;n.pos>>3){case 1:if(e!==10)break;i.audioBuffer=je.decode(n,n.uint32());continue;case 2:if(e!==16)break;i.audioPartsLength=n.int32();continue;case 3:if(e!==26)break;i.fileId=n.string();continue;case 4:if(e!==32)break;i.version=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{audioBuffer:w(e.audioBuffer)?je.fromJSON(e.audioBuffer):void 0,audioPartsLength:w(e.audioPartsLength)?globalThis.Number(e.audioPartsLength):0,fileId:w(e.fileId)?globalThis.String(e.fileId):``,version:w(e.version)?globalThis.Number(e.version):0}},toJSON(e){let t={};return e.audioBuffer!==void 0&&(t.audioBuffer=je.toJSON(e.audioBuffer)),e.audioPartsLength!==0&&(t.audioPartsLength=Math.round(e.audioPartsLength)),e.fileId!==``&&(t.fileId=e.fileId),e.version!==0&&(t.version=Math.round(e.version)),t},create(e){return Ne.fromPartial(e??{})},fromPartial(e){let t=Me();return t.audioBuffer=e.audioBuffer!==void 0&&e.audioBuffer!==null?je.fromPartial(e.audioBuffer):void 0,t.audioPartsLength=e.audioPartsLength??0,t.fileId=e.fileId??``,t.version=e.version??0,t}};function Pe(){return{translationId:``,url:``,partialAudioInfo:void 0,audioInfo:void 0}}var Fe={encode(e,t=new b){return e.translationId!==``&&t.uint32(10).string(e.translationId),e.url!==``&&t.uint32(18).string(e.url),e.partialAudioInfo!==void 0&&Ne.encode(e.partialAudioInfo,t.uint32(34).fork()).join(),e.audioInfo!==void 0&&ke.encode(e.audioInfo,t.uint32(50).fork()).join(),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Pe();for(;n.pos>>3){case 1:if(e!==10)break;i.translationId=n.string();continue;case 2:if(e!==18)break;i.url=n.string();continue;case 4:if(e!==34)break;i.partialAudioInfo=Ne.decode(n,n.uint32());continue;case 6:if(e!==50)break;i.audioInfo=ke.decode(n,n.uint32());continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{translationId:w(e.translationId)?globalThis.String(e.translationId):``,url:w(e.url)?globalThis.String(e.url):``,partialAudioInfo:w(e.partialAudioInfo)?Ne.fromJSON(e.partialAudioInfo):void 0,audioInfo:w(e.audioInfo)?ke.fromJSON(e.audioInfo):void 0}},toJSON(e){let t={};return e.translationId!==``&&(t.translationId=e.translationId),e.url!==``&&(t.url=e.url),e.partialAudioInfo!==void 0&&(t.partialAudioInfo=Ne.toJSON(e.partialAudioInfo)),e.audioInfo!==void 0&&(t.audioInfo=ke.toJSON(e.audioInfo)),t},create(e){return Fe.fromPartial(e??{})},fromPartial(e){let t=Pe();return t.translationId=e.translationId??``,t.url=e.url??``,t.partialAudioInfo=e.partialAudioInfo!==void 0&&e.partialAudioInfo!==null?Ne.fromPartial(e.partialAudioInfo):void 0,t.audioInfo=e.audioInfo!==void 0&&e.audioInfo!==null?ke.fromPartial(e.audioInfo):void 0,t}};function Ie(){return{status:0,remainingChunks:[]}}var Le={encode(e,t=new b){e.status!==0&&t.uint32(8).int32(e.status);for(let n of e.remainingChunks)t.uint32(18).string(n);return t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ie();for(;n.pos>>3){case 1:if(e!==8)break;i.status=n.int32();continue;case 2:if(e!==18)break;i.remainingChunks.push(n.string());continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{status:w(e.status)?globalThis.Number(e.status):0,remainingChunks:globalThis.Array.isArray(e?.remainingChunks)?e.remainingChunks.map(e=>globalThis.String(e)):[]}},toJSON(e){let t={};return e.status!==0&&(t.status=Math.round(e.status)),e.remainingChunks?.length&&(t.remainingChunks=e.remainingChunks),t},create(e){return Le.fromPartial(e??{})},fromPartial(e){let t=Ie();return t.status=e.status??0,t.remainingChunks=e.remainingChunks?.map(e=>e)||[],t}};function Re(){return{language:``,url:``,unknown0:0,translatedLanguage:``,translatedUrl:``,unknown1:0,unknown2:0}}var ze={encode(e,t=new b){return e.language!==``&&t.uint32(10).string(e.language),e.url!==``&&t.uint32(18).string(e.url),e.unknown0!==0&&t.uint32(24).int32(e.unknown0),e.translatedLanguage!==``&&t.uint32(34).string(e.translatedLanguage),e.translatedUrl!==``&&t.uint32(42).string(e.translatedUrl),e.unknown1!==0&&t.uint32(48).int32(e.unknown1),e.unknown2!==0&&t.uint32(56).int32(e.unknown2),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Re();for(;n.pos>>3){case 1:if(e!==10)break;i.language=n.string();continue;case 2:if(e!==18)break;i.url=n.string();continue;case 3:if(e!==24)break;i.unknown0=n.int32();continue;case 4:if(e!==34)break;i.translatedLanguage=n.string();continue;case 5:if(e!==42)break;i.translatedUrl=n.string();continue;case 6:if(e!==48)break;i.unknown1=n.int32();continue;case 7:if(e!==56)break;i.unknown2=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{language:w(e.language)?globalThis.String(e.language):``,url:w(e.url)?globalThis.String(e.url):``,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):0,translatedLanguage:w(e.translatedLanguage)?globalThis.String(e.translatedLanguage):``,translatedUrl:w(e.translatedUrl)?globalThis.String(e.translatedUrl):``,unknown1:w(e.unknown1)?globalThis.Number(e.unknown1):0,unknown2:w(e.unknown2)?globalThis.Number(e.unknown2):0}},toJSON(e){let t={};return e.language!==``&&(t.language=e.language),e.url!==``&&(t.url=e.url),e.unknown0!==0&&(t.unknown0=Math.round(e.unknown0)),e.translatedLanguage!==``&&(t.translatedLanguage=e.translatedLanguage),e.translatedUrl!==``&&(t.translatedUrl=e.translatedUrl),e.unknown1!==0&&(t.unknown1=Math.round(e.unknown1)),e.unknown2!==0&&(t.unknown2=Math.round(e.unknown2)),t},create(e){return ze.fromPartial(e??{})},fromPartial(e){let t=Re();return t.language=e.language??``,t.url=e.url??``,t.unknown0=e.unknown0??0,t.translatedLanguage=e.translatedLanguage??``,t.translatedUrl=e.translatedUrl??``,t.unknown1=e.unknown1??0,t.unknown2=e.unknown2??0,t}};function Be(){return{url:``,language:``}}var Ve={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.language!==``&&t.uint32(18).string(e.language),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Be();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==18)break;i.language=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,language:w(e.language)?globalThis.String(e.language):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.language!==``&&(t.language=e.language),t},create(e){return Ve.fromPartial(e??{})},fromPartial(e){let t=Be();return t.url=e.url??``,t.language=e.language??``,t}};function He(){return{waiting:!1,subtitles:[]}}var Ue={encode(e,t=new b){e.waiting!==!1&&t.uint32(8).bool(e.waiting);for(let n of e.subtitles)ze.encode(n,t.uint32(18).fork()).join();return t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=He();for(;n.pos>>3){case 1:if(e!==8)break;i.waiting=n.bool();continue;case 2:if(e!==18)break;i.subtitles.push(ze.decode(n,n.uint32()));continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{waiting:w(e.waiting)?globalThis.Boolean(e.waiting):!1,subtitles:globalThis.Array.isArray(e?.subtitles)?e.subtitles.map(e=>ze.fromJSON(e)):[]}},toJSON(e){let t={};return e.waiting!==!1&&(t.waiting=e.waiting),e.subtitles?.length&&(t.subtitles=e.subtitles.map(e=>ze.toJSON(e))),t},create(e){return Ue.fromPartial(e??{})},fromPartial(e){let t=He();return t.waiting=e.waiting??!1,t.subtitles=e.subtitles?.map(e=>ze.fromPartial(e))||[],t}};function We(){return{url:``,timestamp:``}}var Ge={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.timestamp!==``&&t.uint32(18).string(e.timestamp),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=We();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==18)break;i.timestamp=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,timestamp:w(e.timestamp)?globalThis.String(e.timestamp):``}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.timestamp!==``&&(t.timestamp=e.timestamp),t},create(e){return Ge.fromPartial(e??{})},fromPartial(e){let t=We();return t.url=e.url??``,t.timestamp=e.timestamp??``,t}};function Ke(){return{url:``,language:``,responseLanguage:``,unknown0:0,unknown1:0}}var qe={encode(e,t=new b){return e.url!==``&&t.uint32(10).string(e.url),e.language!==``&&t.uint32(18).string(e.language),e.responseLanguage!==``&&t.uint32(26).string(e.responseLanguage),e.unknown0!==0&&t.uint32(40).int32(e.unknown0),e.unknown1!==0&&t.uint32(48).int32(e.unknown1),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Ke();for(;n.pos>>3){case 1:if(e!==10)break;i.url=n.string();continue;case 2:if(e!==18)break;i.language=n.string();continue;case 3:if(e!==26)break;i.responseLanguage=n.string();continue;case 5:if(e!==40)break;i.unknown0=n.int32();continue;case 6:if(e!==48)break;i.unknown1=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{url:w(e.url)?globalThis.String(e.url):``,language:w(e.language)?globalThis.String(e.language):``,responseLanguage:w(e.responseLanguage)?globalThis.String(e.responseLanguage):``,unknown0:w(e.unknown0)?globalThis.Number(e.unknown0):0,unknown1:w(e.unknown1)?globalThis.Number(e.unknown1):0}},toJSON(e){let t={};return e.url!==``&&(t.url=e.url),e.language!==``&&(t.language=e.language),e.responseLanguage!==``&&(t.responseLanguage=e.responseLanguage),e.unknown0!==0&&(t.unknown0=Math.round(e.unknown0)),e.unknown1!==0&&(t.unknown1=Math.round(e.unknown1)),t},create(e){return qe.fromPartial(e??{})},fromPartial(e){let t=Ke();return t.url=e.url??``,t.language=e.language??``,t.responseLanguage=e.responseLanguage??``,t.unknown0=e.unknown0??0,t.unknown1=e.unknown1??0,t}};function Je(){return{interval:0,translatedInfo:void 0,pingId:void 0}}var Ye={encode(e,t=new b){return e.interval!==0&&t.uint32(8).int32(e.interval),e.translatedInfo!==void 0&&Ge.encode(e.translatedInfo,t.uint32(18).fork()).join(),e.pingId!==void 0&&t.uint32(24).int32(e.pingId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Je();for(;n.pos>>3){case 1:if(e!==8)break;i.interval=n.int32();continue;case 2:if(e!==18)break;i.translatedInfo=Ge.decode(n,n.uint32());continue;case 3:if(e!==24)break;i.pingId=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{interval:w(e.interval)?he(e.interval):0,translatedInfo:w(e.translatedInfo)?Ge.fromJSON(e.translatedInfo):void 0,pingId:w(e.pingId)?globalThis.Number(e.pingId):void 0}},toJSON(e){let t={};return e.interval!==0&&(t.interval=ge(e.interval)),e.translatedInfo!==void 0&&(t.translatedInfo=Ge.toJSON(e.translatedInfo)),e.pingId!==void 0&&(t.pingId=Math.round(e.pingId)),t},create(e){return Ye.fromPartial(e??{})},fromPartial(e){let t=Je();return t.interval=e.interval??0,t.translatedInfo=e.translatedInfo!==void 0&&e.translatedInfo!==null?Ge.fromPartial(e.translatedInfo):void 0,t.pingId=e.pingId??void 0,t}};function Xe(){return{pingId:0}}var Ze={encode(e,t=new b){return e.pingId!==0&&t.uint32(8).int32(e.pingId),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Xe();for(;n.pos>>3){case 1:if(e!==8)break;i.pingId=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{pingId:w(e.pingId)?globalThis.Number(e.pingId):0}},toJSON(e){let t={};return e.pingId!==0&&(t.pingId=Math.round(e.pingId)),t},create(e){return Ze.fromPartial(e??{})},fromPartial(e){let t=Xe();return t.pingId=e.pingId??0,t}};function Qe(){return{uuid:``,module:``}}var $e={encode(e,t=new b){return e.uuid!==``&&t.uint32(10).string(e.uuid),e.module!==``&&t.uint32(18).string(e.module),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=Qe();for(;n.pos>>3){case 1:if(e!==10)break;i.uuid=n.string();continue;case 2:if(e!==18)break;i.module=n.string();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{uuid:w(e.uuid)?globalThis.String(e.uuid):``,module:w(e.module)?globalThis.String(e.module):``}},toJSON(e){let t={};return e.uuid!==``&&(t.uuid=e.uuid),e.module!==``&&(t.module=e.module),t},create(e){return $e.fromPartial(e??{})},fromPartial(e){let t=Qe();return t.uuid=e.uuid??``,t.module=e.module??``,t}};function et(){return{secretKey:``,expires:0}}var tt={encode(e,t=new b){return e.secretKey!==``&&t.uint32(10).string(e.secretKey),e.expires!==0&&t.uint32(16).int32(e.expires),t},decode(e,t){let n=e instanceof x?e:new x(e),r=t===void 0?n.len:n.pos+t,i=et();for(;n.pos>>3){case 1:if(e!==10)break;i.secretKey=n.string();continue;case 2:if(e!==16)break;i.expires=n.int32();continue}if((e&7)==4||e===0)break;n.skip(e&7)}return i},fromJSON(e){return{secretKey:w(e.secretKey)?globalThis.String(e.secretKey):``,expires:w(e.expires)?globalThis.Number(e.expires):0}},toJSON(e){let t={};return e.secretKey!==``&&(t.secretKey=e.secretKey),e.expires!==0&&(t.expires=Math.round(e.expires)),t},create(e){return tt.fromPartial(e??{})},fromPartial(e){let t=et();return t.secretKey=e.secretKey??``,t.expires=e.expires??0,t}};function nt(e){if(globalThis.Buffer)return Uint8Array.from(globalThis.Buffer.from(e,`base64`));{let t=globalThis.atob(e),n=new Uint8Array(t.length);for(let e=0;e{t.push(globalThis.String.fromCharCode(e))}),globalThis.btoa(t.join(``))}}function w(e){return e!=null}var it;(function(e){e[e.DEBUG=0]=`DEBUG`,e[e.INFO=1]=`INFO`,e[e.WARN=2]=`WARN`,e[e.ERROR=3]=`ERROR`,e[e.SILENCE=4]=`SILENCE`})(it||={});var at=`[vot.js v${f.version}]`;function ot(e){return f.loggerLevel<=e}function st(...e){ot(it.DEBUG)&&console.log(at,...e)}function ct(...e){ot(it.INFO)&&console.info(at,...e)}function lt(...e){ot(it.WARN)&&console.warn(at,...e)}function ut(...e){ot(it.ERROR)&&console.error(at,...e)}var T={canLog:ot,log:st,info:ct,warn:lt,error:ut},dt=l({default:()=>ft,getRandomValues:()=>mt,randomUUID:()=>ht,subtle:()=>pt}),ft,pt,mt,ht,gt=s((()=>{if(ft=globalThis.crypto,!ft?.subtle)throw TypeError(`Web Crypto API is not available in this environment.`);pt=ft.subtle,mt=ft.getRandomValues.bind(ft),ht=typeof ft.randomUUID==`function`?ft.randomUUID.bind(ft):void 0})),{componentVersion:_t}=f;async function vt(){return typeof window<`u`&&window.crypto?window.crypto:await Promise.resolve().then(()=>(gt(),dt))}var bt=new TextEncoder;async function xt(e,t,n){let r=await vt(),i=await r.subtle.importKey(`raw`,bt.encode(t),{name:`HMAC`,hash:{name:e}},!1,[`sign`,`verify`]);return await r.subtle.sign(`HMAC`,i,n)}async function St(e){let t=await xt(`SHA-256`,f.hmac,e);return new Uint8Array(t).reduce((e,t)=>e+t.toString(16).padStart(2,`0`),``)}async function Ct(e,t,n,r){let{secretKey:i,uuid:a}=t,o=`${a}:${r}:${_t}`,s=await St(bt.encode(o));if(e===`Ya-Summary`)return{[`X-${e}-Sk`]:i,[`X-${e}-Token`]:`${s}:${o}`};if(!n)throw TypeError(`Body is required for sec type ${e}`);let c=await St(n);return{[`${e}-Signature`]:c,[`Sec-${e}-Sk`]:i,[`Sec-${e}-Token`]:`${s}:${o}`}}function wt(){let e=``;for(let t=0;t<32;t++){let t=Math.floor(Math.random()*16);e+=`0123456789ABCDEF`[t]}return e}async function Tt(e,t){try{let n=await xt(`SHA-1`,e,bt.encode(t));return btoa(String.fromCharCode(...new Uint8Array(n)))}catch(e){return T.error(e),!1}}var Et={"sec-ch-ua":`"Chromium";v="146", "YaBrowser";v="${_t.slice(0,5)}", "Not?A_Brand";v="26", "Yowser";v="2.5"`,"sec-ch-ua-full-version-list":`"Chromium";v="146.0.7680.154", "YaBrowser";v="${_t}", "Not?A_Brand";v="26.0.0.0", "Yowser";v="2.5"`,"Sec-Fetch-Mode":`no-cors`},Dt={afr:`af`,aka:`ak`,alb:`sq`,amh:`am`,ara:`ar`,arm:`hy`,asm:`as`,aym:`ay`,aze:`az`,baq:`eu`,bel:`be`,ben:`bn`,bos:`bs`,bul:`bg`,bur:`my`,cat:`ca`,chi:`zh`,cos:`co`,cze:`cs`,dan:`da`,div:`dv`,dut:`nl`,eng:`en`,epo:`eo`,est:`et`,ewe:`ee`,fin:`fi`,fre:`fr`,fry:`fy`,geo:`ka`,ger:`de`,gla:`gd`,gle:`ga`,glg:`gl`,gre:`el`,grn:`gn`,guj:`gu`,hat:`ht`,hau:`ha`,hin:`hi`,hrv:`hr`,hun:`hu`,ibo:`ig`,ice:`is`,ind:`id`,ita:`it`,jav:`jv`,jpn:`ja`,kan:`kn`,kaz:`kk`,khm:`km`,kin:`rw`,kir:`ky`,kor:`ko`,kur:`ku`,lao:`lo`,lat:`la`,lav:`lv`,lin:`ln`,lit:`lt`,ltz:`lb`,lug:`lg`,mac:`mk`,mal:`ml`,mao:`mi`,mar:`mr`,may:`ms`,mlg:`mg`,mlt:`mt`,mon:`mn`,nep:`ne`,nor:`no`,nya:`ny`,ori:`or`,orm:`om`,pan:`pa`,per:`fa`,pol:`pl`,por:`pt`,pus:`ps`,que:`qu`,rum:`ro`,rus:`ru`,san:`sa`,sin:`si`,slo:`sk`,slv:`sl`,smo:`sm`,sna:`sn`,snd:`sd`,som:`so`,sot:`st`,spa:`es`,srp:`sr`,sun:`su`,swa:`sw`,swe:`sv`,tam:`ta`,tat:`tt`,tel:`te`,tgk:`tg`,tha:`th`,tir:`ti`,tso:`ts`,tuk:`tk`,tur:`tr`,uig:`ug`,ukr:`uk`,urd:`ur`,uzb:`uz`,vie:`vi`,wel:`cy`,xho:`xh`,yid:`yi`,yor:`yo`,zul:`zu`};async function Ot(e,t={headers:{"User-Agent":f.userAgent}}){let{timeout:n=3e3,signal:r,...i}=t;if(!r&&(!n||n<=0))return await fetch(e,i);let a=new AbortController,o=e=>{a.signal.aborted||a.abort(e)};r&&(r.aborted?o(r.reason):r.addEventListener(`abort`,()=>o(r.reason),{once:!0}));let s;n&&n>0&&(s=setTimeout(()=>o(Error(`Fetch timeout`)),n));try{return await fetch(e,{...i,signal:a.signal})}finally{s&&clearTimeout(s)}}function kt(){return Math.floor(Date.now()/1e3)}function E(e){return e.length===3?Dt[e]:e.toLowerCase().split(/[_;-]/)[0].trim()}function D(e,t=`mp4`){let n=`https://${f.mediaProxy}/v1/proxy/video.${t}?format=base64&force=true`;return e instanceof URL?`${n}&url=${btoa(e.href)}&origin=${e.origin}&referer=${e.origin}`:`${n}&url=${btoa(e)}`}function At(e,t,n,r,i,{forceSourceLang:a=!1,wasStream:o=!1,videoTitle:s=``,bypassCache:c=!1,useLivelyVoice:l=!1,firstRequest:u=!0}={}){return be.encode({url:e,firstRequest:u,duration:t,unknown0:1,language:n,forceSourceLang:a,unknown1:0,translationHelp:i??[],responseLanguage:r,wasStream:o,unknown2:1,unknown3:2,bypassCache:c,useLivelyVoice:l,videoTitle:s}).finish()}function jt(e){return Se.decode(new Uint8Array(e))}function Mt(e,t,n,r){return Te.encode({url:e,duration:t,language:n,responseLanguage:r}).finish()}function Nt(e){return De.decode(new Uint8Array(e))}function Pt(e){return`chunkId`in e}function Ft(e,t,n,r){return r&&Pt(n)?Fe.encode({url:e,translationId:t,partialAudioInfo:{...r,audioBuffer:n}}).finish():Fe.encode({url:e,translationId:t,audioInfo:n}).finish()}function It(e){return Le.decode(new Uint8Array(e))}function Lt(e,t){return Ve.encode({url:e,language:t}).finish()}function Rt(e){return Ue.decode(new Uint8Array(e))}function zt(e){return Ze.encode({pingId:e}).finish()}function Bt(e,t,n){return qe.encode({url:e,language:t,responseLanguage:n,unknown0:1,unknown1:0}).finish()}function Vt(e){return Ye.decode(new Uint8Array(e))}var O={encodeTranslationRequest:At,decodeTranslationResponse:jt,encodeTranslationCacheRequest:Mt,decodeTranslationCacheResponse:Nt,isPartialAudioBuffer:Pt,encodeTranslationAudioRequest:Ft,decodeTranslationAudioResponse:It,encodeSubtitlesRequest:Lt,decodeSubtitlesResponse:Rt,encodeStreamPingRequest:zt,encodeStreamRequest:Bt,decodeStreamResponse:Vt};function Ht(e,t){return $e.encode({uuid:e,module:t}).finish()}function Ut(e){return tt.decode(new Uint8Array(e))}var Wt={encodeSessionRequest:Ht,decodeSessionResponse:Ut},Gt;(function(e){e[e.FAILED=0]=`FAILED`,e[e.FINISHED=1]=`FINISHED`,e[e.WAITING=2]=`WAITING`,e[e.LONG_WAITING=3]=`LONG_WAITING`,e[e.PART_CONTENT=5]=`PART_CONTENT`,e[e.AUDIO_REQUESTED=6]=`AUDIO_REQUESTED`,e[e.SESSION_REQUIRED=7]=`SESSION_REQUIRED`})(Gt||={});var Kt;(function(e){e.WEB_API_VIDEO_SRC_FROM_IFRAME=`web_api_video_src_from_iframe`,e.WEB_API_VIDEO_SRC=`web_api_video_src`,e.WEB_API_GET_ALL_GENERATING_URLS_DATA_FROM_IFRAME=`web_api_get_all_generating_urls_data_from_iframe`,e.WEB_API_GET_ALL_GENERATING_URLS_DATA_FROM_IFRAME_TMP_EXP=`web_api_get_all_generating_urls_data_from_iframe_tmp_exp`,e.WEB_API_REPLACED_FETCH_INSIDE_IFRAME=`web_api_replaced_fetch_inside_iframe`,e.ANDROID_API=`android_api`,e.WEB_API_SLOW=`web_api_slow`,e.WEB_API_STEAL_SIG_AND_N=`web_api_steal_sig_and_n`,e.WEB_API_COMBINED=`web_api_get_all_generating_urls_data_from_iframe,web_api_steal_sig_and_n`})(Kt||={});var k;(function(e){e.custom=`custom`,e.directlink=`custom`,e.youtube=`youtube`,e.preservetube=`preservetube`,e.piped=`piped`,e.invidious=`invidious`,e.niconico=`niconico`,e.vk=`vk`,e.nine_gag=`nine_gag`,e.gag=`nine_gag`,e.twitch=`twitch`,e.proxitok=`proxitok`,e.tiktok=`tiktok`,e.vimeo=`vimeo`,e.xvideos=`xvideos`,e.xhamster=`xhamster`,e.spankbang=`spankbang`,e.rule34video=`rule34video`,e.picarto=`picarto`,e.olympicsreplay=`olympics_replay`,e.pornhub=`pornhub`,e.twitter=`twitter`,e.x=`twitter`,e.rumble=`rumble`,e.facebook=`facebook`,e.rutube=`rutube`,e.coub=`coub`,e.bilibili=`bilibili`,e.mail_ru=`mailru`,e.mailru=`mailru`,e.bitchute=`bitchute`,e.eporner=`eporner`,e.peertube=`peertube`,e.dailymotion=`dailymotion`,e.trovo=`trovo`,e.yandexdisk=`yandexdisk`,e.ok_ru=`okru`,e.okru=`okru`,e.googledrive=`googledrive`,e.bannedvideo=`bannedvideo`,e.weverse=`weverse`,e.weibo=`weibo`,e.newgrounds=`newgrounds`,e.egghead=`egghead`,e.youku=`youku`,e.archive=`archive`,e.kodik=`kodik`,e.patreon=`patreon`,e.reddit=`reddit`,e.kick=`kick`,e.apple_developer=`apple_developer`,e.appledeveloper=`apple_developer`,e.epicgames=`epicgames`,e.odysee=`odysee`,e.coursehunterLike=`coursehunterLike`,e.sap=`sap`,e.watchpornto=`watchpornto`,e.jove=`jove`,e.linkedin=`linkedin`,e.incestflix=`incestflix`,e.porntn=`porntn`,e.dzen=`dzen`,e.bunnystream=`bunnystream`,e.cloudflarestream=`cloudflarestream`,e.loom=`loom`,e.rtnews=`rtnews`,e.bitview=`bitview`,e.thisvid=`thisvid`,e.ign=`ign`,e.zdf=`zdf`,e.bunkr=`bunkr`,e.imdb=`imdb`,e.telegram=`telegram`})(k||={});function qt(e,t,n){return e===k.patreon?{service:`mux`,videoId:new URL(n).pathname.slice(1)}:{service:e,videoId:t}}var A=class extends Error{data;constructor(e,t=void 0){super(e),this.data=t,this.name=`VOTJSError`}},Jt=class{host;schema;fetch;fetchOpts;sessions={};userAgent=f.userAgent;headers={"User-Agent":this.userAgent,Accept:`application/x-protobuf`,"Accept-Language":`en`,"Content-Type":`application/x-protobuf`,Pragma:`no-cache`,"Cache-Control":`no-cache`};hostSchemaRe=/(http(s)?):\/\//;constructor({host:e=f.host,fetchFn:t=Ot,fetchOpts:n={},headers:r={}}={}){let i=this.hostSchemaRe.exec(e)?.[1];this.host=i?e.replace(`${i}://`,``):e,this.schema=i??`https`,this.fetch=t,this.fetchOpts=n,this.headers={...this.headers,...r}}async request(e,t,n={},r=`POST`){let i=this.getOpts(new Blob([t]),n,r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.arrayBuffer();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}async requestJSON(e,t=null,n={},r=`POST`){let i=this.getOpts(t,{"Content-Type":`application/json`,...n},r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.json();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}getOpts(e,t={},n=`POST`){return{method:n,headers:{...this.headers,...t},body:e,...this.fetchOpts}}async getSession(e){let t=kt(),n=this.sessions[e];if(n&&n.timestamp+n.expires>t)return n;let{secretKey:r,expires:i,uuid:a}=await this.createSession(e);return this.sessions[e]={secretKey:r,expires:i,timestamp:t,uuid:a},this.sessions[e]}async createSession(e){let t=wt(),n=Wt.encodeSessionRequest(t,e),r=await this.request(`/session/create`,n,{"Vtrans-Signature":await St(n)});if(!r.success)throw new A(`Failed to request create session`,r);return{...Wt.decodeSessionResponse(r.data),uuid:t}}},Yt=class extends Jt{hostVOT;schemaVOT;apiToken;requestLang;responseLang;paths={videoTranslation:`/video-translation/translate`,videoTranslationFailAudio:`/video-translation/fail-audio-js`,videoTranslationAudio:`/video-translation/audio`,videoTranslationCache:`/video-translation/cache`,videoSubtitles:`/video-subtitles/get-subtitles`,streamPing:`/stream-translation/ping-stream`,streamTranslation:`/stream-translation/translate-stream`};isCustomLink(e){return!!(/\.(m3u8|m4(a|v)|mpd)/.exec(e)??/^https:\/\/cdn\.qstv\.on\.epicgames\.com/.exec(e))}headersVOT={"User-Agent":`vot.js/${f.version}`,"Content-Type":`application/json`,Pragma:`no-cache`,"Cache-Control":`no-cache`};constructor({host:e,hostVOT:t=f.hostVOT,fetchFn:n,fetchOpts:r,requestLang:i=`en`,responseLang:a=`ru`,apiToken:o,headers:s}={}){super({host:e,fetchFn:n,fetchOpts:r,headers:s});let c=this.hostSchemaRe.exec(t)?.[1];this.hostVOT=c?t.replace(`${c}://`,``):t,this.schemaVOT=c??`https`,this.requestLang=i,this.responseLang=a,this.apiToken=o}get apiTokenHeader(){return this.apiToken?{Authorization:`OAuth ${this.apiToken}`}:{}}async requestVOT(e,t,n={}){let r=this.getOpts(JSON.stringify(t),{...this.headersVOT,...n});try{let t=await this.fetch(`${this.schemaVOT}://${this.hostVOT}${e}`,r),n=await t.json();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}async translateVideoYAImpl({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,translationHelp:r=null,headers:i={},extraOpts:a={},shouldSendFailedAudio:o=!0}){let{url:s,duration:c=f.defaultDuration}=e,l=await this.getSession(`video-translation`),u=O.encodeTranslationRequest(s,c,t,n,r,a),d=this.paths.videoTranslation,p=await Ct(`Vtrans`,l,u,d),m=a.useLivelyVoice?this.apiTokenHeader:{},h=await this.request(d,u,{...p,...m,...i});if(!h.success)throw new A(`Failed to request video translation`,h);let g=O.decodeTranslationResponse(h.data);T.log(`translateVideo`,g);let{status:_,translationId:v}=g;switch(_){case Gt.FAILED:throw new A(`Yandex couldn't translate video`,g);case Gt.FINISHED:case Gt.PART_CONTENT:if(!g.url)throw new A(`Audio link wasn't received from Yandex response`,g);return{translationId:v,translated:!0,url:g.url,status:_,remainingTime:g.remainingTime??-1};case Gt.WAITING:case Gt.LONG_WAITING:return{translationId:v,translated:!1,status:_,remainingTime:g.remainingTime??-1};case Gt.AUDIO_REQUESTED:return s.startsWith(`https://youtu.be/`)&&o?(await this.requestVtransFailAudio(s),await this.requestVtransAudio(s,g.translationId,{audioFile:new Uint8Array,fileId:Kt.WEB_API_GET_ALL_GENERATING_URLS_DATA_FROM_IFRAME}),await this.translateVideoYAImpl({videoData:e,requestLang:t,responseLang:n,translationHelp:r,headers:i,shouldSendFailedAudio:!1})):{translationId:v,translated:!1,status:_,remainingTime:g.remainingTime??-1};case Gt.SESSION_REQUIRED:throw new A(`Yandex auth required to translate video. See docs for more info`,g);default:throw T.error(`Unknown response`,g),new A(`Unknown response from Yandex`,g)}}async translateVideoVOTImpl({url:e,videoId:t,service:n,requestLang:r=this.requestLang,responseLang:i=this.responseLang,headers:a={},provider:o=`yandex`}){let s=qt(n,t,e),c=await this.requestVOT(this.paths.videoTranslation,{provider:o,service:s.service,video_id:s.videoId,from_lang:r,to_lang:i,raw_video:e},{...a});if(!c.success)throw new A(`Failed to request video translation`,c);let l=c.data;switch(l.status){case`failed`:throw new A(`Yandex couldn't translate video`,l);case`success`:if(!l.translated_url)throw new A(`Audio link wasn't received from VOT response`,l);return{translationId:String(l.id),translated:!0,url:l.translated_url,status:1,remainingTime:-1};case`waiting`:return{translationId:``,translated:!1,remainingTime:l.remaining_time,status:2,message:l.message}}}async requestVtransFailAudio(e){let t=await this.requestJSON(this.paths.videoTranslationFailAudio,JSON.stringify({video_url:e}),void 0,`PUT`);if(!t.data||typeof t.data==`string`||t.data.status!==1)throw new A(`Failed to request to fake video translation fail audio js`,t);return t}async requestVtransAudio(e,t,n,r,i={}){let a=await this.getSession(`video-translation`),o;if(O.isPartialAudioBuffer(n)){if(!r)throw new A(`Partial audio metadata is required for partial audio buffer`,n);o=O.encodeTranslationAudioRequest(e,t,n,r)}else o=O.encodeTranslationAudioRequest(e,t,n,void 0);let s=this.paths.videoTranslationAudio,c=await Ct(`Vtrans`,a,o,s),l=await this.request(s,o,{...c,...i},`PUT`);if(!l.success)throw new A(`Failed to request video translation audio`,l);return O.decodeTranslationAudioResponse(l.data)}async translateVideoCache({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,headers:r={}}){let{url:i,duration:a=f.defaultDuration}=e,o=await this.getSession(`video-translation`),s=O.encodeTranslationCacheRequest(i,a,t,n),c=this.paths.videoTranslationCache,l=await Ct(`Vtrans`,o,s,c),u=await this.request(c,s,{...l,...r},`POST`);if(!u.success)throw new A(`Failed to request video translation cache`,u);return O.decodeTranslationCacheResponse(u.data)}async translateVideo({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,translationHelp:r=null,headers:i={},extraOpts:a={},shouldSendFailedAudio:o=!0}){let{url:s,videoId:c,host:l}=e;return this.isCustomLink(s)?await this.translateVideoVOTImpl({url:s,videoId:c,service:l,requestLang:t,responseLang:n,headers:i,provider:a.useLivelyVoice?`yandex_lively`:`yandex`}):await this.translateVideoYAImpl({videoData:e,requestLang:t,responseLang:n,translationHelp:r,headers:i,extraOpts:a,shouldSendFailedAudio:o})}async getSubtitlesYAImpl({videoData:e,requestLang:t=this.requestLang,headers:n={}}){let{url:r}=e,i=await this.getSession(`video-translation`),a=O.encodeSubtitlesRequest(r,t),o=this.paths.videoSubtitles,s=await Ct(`Vsubs`,i,a,o),c=await this.request(o,a,{...s,...n});if(!c.success)throw new A(`Failed to request video subtitles`,c);let l=O.decodeSubtitlesResponse(c.data),u=l.subtitles.map(e=>{let{language:t,url:n,translatedLanguage:r,translatedUrl:i}=e;return{language:t,url:n,translatedLanguage:r,translatedUrl:i}});return{waiting:l.waiting,subtitles:u}}async getSubtitlesVOTImpl({url:e,videoId:t,service:n,headers:r={}}){let i=qt(n,t,e),a=await this.requestVOT(this.paths.videoSubtitles,{provider:`yandex`,service:i.service,video_id:i.videoId},r);if(!a.success)throw new A(`Failed to request video subtitles`,a);let o=a.data;return{waiting:!1,subtitles:o.reduce((e,t)=>{if(!t.lang_from)return e;let n=o.find(e=>e.lang===t.lang_from);return n&&e.push({language:n.lang,url:n.subtitle_url,translatedLanguage:t.lang,translatedUrl:t.subtitle_url}),e},[])}}async getSubtitles({videoData:e,requestLang:t=this.requestLang,headers:n={}}){let{url:r,videoId:i,host:a}=e;return this.isCustomLink(r)?await this.getSubtitlesVOTImpl({url:r,videoId:i,service:a,headers:n}):await this.getSubtitlesYAImpl({videoData:e,requestLang:t,headers:n})}async pingStream({pingId:e,headers:t={}}){let n=await this.getSession(`video-translation`),r=O.encodeStreamPingRequest(e),i=this.paths.streamPing,a=await Ct(`Vtrans`,n,r,i),o=await this.request(i,r,{...a,...t});if(!o.success)throw new A(`Failed to request stream ping`,o);return!0}async translateStream({videoData:e,requestLang:t=this.requestLang,responseLang:n=this.responseLang,headers:r={}}){let{url:i}=e;if(this.isCustomLink(i))throw new A(`Unsupported video URL for getting stream translation`);let a=await this.getSession(`video-translation`),o=O.encodeStreamRequest(i,t,n),s=this.paths.streamTranslation,c=await Ct(`Vtrans`,a,o,s),l=await this.request(s,o,{...c,...r});if(!l.success)throw new A(`Failed to request stream translation`,l);let u=O.decodeStreamResponse(l.data),d=u.interval;switch(d){case S.NO_CONNECTION:case S.TRANSLATING:return{translated:!1,interval:d,message:d===S.NO_CONNECTION?`streamNoConnectionToServer`:`translationTakeFewMinutes`};case S.STREAMING:if(u.pingId===void 0)throw new A(`Stream ping id wasn't received from Yandex response`,u);return{translated:!0,interval:d,pingId:u.pingId,result:u.translatedInfo};default:throw T.error(`Unknown response`,u),new A(`Unknown response from Yandex`,u)}}},Xt=class extends Yt{constructor(e={}){e.host=e.host??f.hostWorker,super(e)}async request(e,t,n={},r=`POST`){let i=this.getOpts(JSON.stringify({headers:{...this.headers,...n},body:Array.from(t)}),{"Content-Type":`application/json`},r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.arrayBuffer();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}async requestJSON(e,t=null,n={},r=`POST`){let i=this.getOpts(JSON.stringify({headers:{...this.headers,"Content-Type":`application/json`,Accept:`application/json`,...n},body:t}),{Accept:`application/json`,"Content-Type":`application/json`},r);try{let t=await this.fetch(`${this.schema}://${this.host}${e}`,i),n=await t.json();return{success:t.status===200,data:n}}catch(e){return{success:!1,data:e?.message}}}},Zt=class extends Yt{constructor(e){super(e),this.headers={...Et,...this.headers}}},Qt=class extends Xt{constructor(e){super(e),this.headers={...Et,...this.headers}}},$t=class extends Error{constructor(e){super(e),this.name=`VideoDataError`}},en=/(file:\/\/(\/)?|(http(s)?:\/\/)(127\.0\.0\.1|localhost|192\.168\.(\d){1,3}\.(\d){1,3}))/,tn=[`yewtu.be`,`inv.nadeko.net`,`invidious.nerdvpn.de`,`invidious.protokolla.fi`,`invidious.materialio.us`,`iv.melmac.space`],nn=[`piped.video`,`piped.kavin.rocks`,`piped.private.coffee`],rn=[`proxitok.pabloferreiro.es`,`proxitok.pussthecat.org`,`tok.habedieeh.re`,`proxitok.esmailelbob.xyz`,`proxitok.privacydev.net`,`tok.artemislena.eu`,`tok.adminforge.de`,`tt.vern.cc`,`cringe.whatever.social`,`proxitok.lunar.icu`,`proxitok.privacy.com.de`],an=[`peertube.tmp.rcp.tf`,`dalek.zone`,`video.sadmin.io`,`videos.viorsan.com`,`peertube.1312.media`,`tube.shanti.cafe`,`bee-tube.fr`,`video.blender.org`,`beetoons.tv`,`makertube.net`,`peertube.tv`,`framatube.org`,`tilvids.com`,`diode.zone`,`fedimovie.com`,`video.hardlimit.com`,`share.tube`,`peervideo.club`],on=[`coursehunter.net`,`coursetrain.net`],j;(function(e){e.udemy=`udemy`,e.coursera=`coursera`,e.douyin=`douyin`,e.artstation=`artstation`,e.kickstarter=`kickstarter`,e.datacamp=`datacamp`,e.oraclelearn=`oraclelearn`,e.deeplearningai=`deeplearningai`,e.netacad=`netacad`,e.mediafile=`mediafile`})(j||={}),{...k,...j};var M={bilibiliPlayer:`.bpx-player-video-wrap, div.player-mobile-box.player-mobile-autoplay`,flowplayer:`.fp-player, div.flowplayer`,idPlayer:`#player`,jwPlayer:`.jwplayer, .jw-media`,player:`.player`,shakaPlayer:`.shaka-video-container, [id^="shaka-video-container-"]`,videoJsUniversal:`[id^='vjs_video_']:not([id*='_html5_api']):not(video), video-js:not([id*='_html5_api']), .video-js:not(video):not([id*='_html5_api']), .vjs-player:not([id*='_html5_api']), [data-vjs-player]:not([id*='_html5_api'])`,vkVideoPlayer:`.videoplayer_media, vk-video-player`},sn=[{additionalData:`mobile`,host:k.youtube,url:`https://youtu.be/`,match:/^m.youtube.com$/,selector:`.player-container`,needExtraData:!0},{host:k.youtube,url:`https://youtu.be/`,match:e=>/^(www.)?youtube(-nocookie|kids)?.com$/.test(e.hostname)&&e.pathname.startsWith(`/tv`),selector:`#container`,needExtraData:!0},{host:k.youtube,url:`https://youtu.be/`,match:e=>/^(www.)?youtube(-nocookie|kids)?.com$/.test(e.host)&&!e.pathname.startsWith(`/embed/`),selector:`.html5-video-container:not(#inline-player *)`,needExtraData:!0},{host:k.youtube,url:`https://youtu.be/`,additionalData:`embed`,match:e=>/^(www.)?youtube(-nocookie|kids)?.com$/.test(e.host)&&e.pathname.startsWith(`/embed/`),selector:`html`,needExtraData:!0},{host:k.invidious,url:`https://youtu.be/`,match:tn,selector:M.idPlayer,needBypassCSP:!0},{host:k.piped,url:`https://youtu.be/`,match:nn,selector:M.shakaPlayer,needBypassCSP:!0},{host:k.preservetube,url:`https://preservetube.com/`,match:/^preservetube\.com$/,selector:`div.video-wrapper`,needExtraData:!0},{host:k.zdf,url:`https://www.zdf.de/play/`,match:[/^zdf.de$/,/^(www.)?zdf.de$/],selector:`div.zdfplayer-app.zdfplayer-desktop, div.zdfplayer-app`},{host:k.niconico,url:`https://www.nicovideo.jp/watch/`,match:[/^(www\.|sp\.)?nicovideo\.jp$/,/^nico\.ms$/],selector:`[class*="grid-area_[player]"] > div`},{additionalData:`mobile`,host:k.vk,url:`https://vk.com/`,match:[/^m.vk.(com|ru)$/,/^m.vkvideo.ru$/],selector:M.vkVideoPlayer,shadowRoot:!0,needExtraData:!0},{additionalData:`clips`,host:k.vk,url:`https://vk.com/`,match:/^(www.|m.)?vk.(com|ru)$/,selector:`div[data-testid="clipcontainer-video"]`,needExtraData:!0},{host:k.vk,url:`https://vk.com/`,match:[/^(www\.|m\.)?vk\.(com|ru)$/,/^(.*\.)?vkvideo\.ru$/],selector:M.vkVideoPlayer,needExtraData:!0},{host:k.nine_gag,url:`https://9gag.com/gag/`,match:/^9gag.com$/,selector:`.video-post`,needExtraData:!0},{host:k.twitch,url:`https://twitch.tv/`,match:[/^m.twitch.tv$/,/^(www.)?twitch.tv$/,/^clips.twitch.tv$/,/^player.twitch.tv$/],needExtraData:!0,selector:`.video-ref, main > div > section > div > div > div`},{host:k.proxitok,url:`https://www.tiktok.com/`,match:rn,selector:`.column.has-text-centered`},{host:k.tiktok,url:`https://www.tiktok.com/`,match:/^(www.)?tiktok.com$/,selector:null},{host:j.douyin,url:`https://www.douyin.com/`,match:/^(www.)?douyin.com/,selector:`.xg-video-container`,needExtraData:!0,needBypassCSP:!0},{host:k.vimeo,url:`https://vimeo.com/`,match:/^(www\.|m\.)?vimeo.com$/,needExtraData:!0,selector:M.player},{host:k.vimeo,url:`https://player.vimeo.com/`,match:/^player.vimeo.com$/,additionalData:`embed`,needExtraData:!0,needBypassCSP:!0,selector:M.player},{host:k.xvideos,url:`https://www.xvideos.com/`,match:[/^(www.)?xvideos(-ar)?.com$/,/^(www.)?xvideos(\d\d\d).com$/,/^(www.)?xv-ru.com$/],selector:`#hlsplayer`,needBypassCSP:!0},{host:k.xhamster,url:`https://xhamster.com/`,match:e=>/^(?:[^.]+\.)?(?:xhamster\.(?:com|desi)|xhamster\d+\.(?:com|desi)|xhvid\.com)$/.test(e.host)&&/\/(?:videos\/[^/]+-[\dA-Za-z]+)\/?$/.test(e.pathname),selector:`#player-container`},{host:k.spankbang,url:`https://spankbang.com/`,match:e=>/^(?:[^.]+\.)?spankbang\.com$/.test(e.host)&&/\/(?:[\da-z]+\/(?:video|play|embed)(?:\/[^/]+)?|[\da-z]+-[\da-z]+\/playlist\/[^/?#&]+)\/?$/i.test(e.pathname),selector:`#main_video_player`},{host:k.rule34video,url:`https://rule34video.com/video/`,match:e=>/^(www\.)?rule34video\.com$/.test(e.host)&&/\/videos?\/\d+/.test(e.pathname),selector:M.flowplayer},{host:k.picarto,url:`https://picarto.tv/`,match:e=>/^(www\.)?picarto\.tv$/.test(e.host)&&/^(?:\/[^/]+\/(?:profile\/)?videos\/[^/?#&]+|\/videopopout\/[^/?#&]+|\/[^/#?]+\/?)$/.test(e.pathname),selector:`[class*="VideosTab__PlayerWrapper"]`},{host:k.olympicsreplay,url:`https://olympics.com/`,match:e=>/^(www\.)?olympics\.com$/.test(e.host)&&/^\/[a-z]{2}\/(?:[a-z0-9-]+\/)?(?:replay|videos?|original-series\/episode)\/[\w-]+\/?$/i.test(e.pathname),selector:M.videoJsUniversal},{host:k.pornhub,url:`https://rt.pornhub.com/view_video.php?viewkey=`,match:/^[a-z]+.pornhub.(com|org)$/,selector:`.mainPlayerDiv > .video-element-wrapper-js > div`,eventSelector:`.mgp_eventCatcher`},{additionalData:`embed`,host:k.pornhub,url:`https://rt.pornhub.com/view_video.php?viewkey=`,match:e=>/^[a-z]+.pornhub.(com|org)$/.exec(e.host)&&e.pathname.startsWith(`/embed/`),selector:M.idPlayer},{host:k.twitter,url:`https://twitter.com/i/status/`,match:/^(twitter|x).com$/,selector:`div[data-testid="videoComponent"]`,needBypassCSP:!0},{host:k.rumble,url:`https://rumble.com/`,match:/^rumble.com$/,selector:`[id^="vid_"] > div`},{host:k.facebook,url:`https://facebook.com/`,match:e=>e.host.includes(`facebook.com`)&&e.pathname.includes(`/videos/`),selector:`div[role="main"] div[data-pagelet$="video" i]`,needBypassCSP:!0},{additionalData:`reels`,host:k.facebook,url:`https://facebook.com/`,match:e=>e.host.includes(`facebook.com`)&&e.pathname.includes(`/reel/`),selector:`div[role="main"]`,needBypassCSP:!0},{host:k.rutube,url:`https://rutube.ru/video/`,match:/^rutube.ru$/,selector:`div[class*="videoWrapper"]`},{additionalData:`embed`,host:k.rutube,url:`https://rutube.ru/video/`,match:/^rutube.ru$/,selector:`#app > div > div`},{host:k.bilibili,url:`https://www.bilibili.com/`,match:/^(www|m|player).bilibili.com$/,selector:M.bilibiliPlayer},{host:k.bilibili,url:`https://www.bilibili.tv/`,match:/^(?:www\.|m\.)?bilibili\.tv$/,selector:M.bilibiliPlayer},{additionalData:`old`,host:k.bilibili,url:`https://www.bilibili.com/`,match:/^(www|m).bilibili.com$/,selector:null},{host:k.mailru,url:`https://my.mail.ru/`,match:/^my.mail.ru$/,selector:`#b-video-wrapper`},{host:k.bitchute,url:`https://www.bitchute.com/video/`,match:/^(www.)?bitchute.com$/,selector:M.videoJsUniversal},{host:k.eporner,url:`https://www.eporner.com/`,match:/^(www.)?eporner.com$/,selector:M.videoJsUniversal},{host:k.peertube,url:`stub`,match:an,selector:M.videoJsUniversal},{host:k.dailymotion,url:`https://www.dailymotion.com/video/`,match:/^((www\.|player\.)?dailymotion\.com|geo(\d+)?\.dailymotion\.com|dai\.ly)$/,selector:M.player},{host:k.trovo,url:`https://trovo.live/s/`,match:/^trovo.live$/,selector:`.player-video`},{host:k.yandexdisk,url:`https://yadi.sk/`,match:/^disk.yandex.(ru|kz|com(\.(am|ge|tr))?|by|az|co\.il|ee|lt|lv|md|net|tj|tm|uz)$/,selector:`.video-player__player > div:nth-child(1)`,needBypassCSP:!0,needExtraData:!0},{host:k.okru,url:`https://ok.ru/video/`,match:/^ok.ru$/,selector:M.vkVideoPlayer,shadowRoot:!0},{host:k.googledrive,url:`https://drive.google.com/file/d/`,match:/^youtube.googleapis.com$/,selector:`html`},{host:k.bannedvideo,url:`https://madmaxworld.tv/watch?id=`,match:/^(www.)?banned.video|madmaxworld.tv$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.weverse,url:`https://weverse.io/`,match:/^weverse.io$/,selector:`.webplayer-internal-source-wrapper`,needExtraData:!0},{host:k.weibo,url:`https://weibo.com/`,match:e=>/^(?:www\.)?weibo\.com$/.test(e.host)&&/^\/(?:\d+\/[A-Za-z0-9]+|0\/[A-Za-z0-9]+|tv\/show\/\d+:(?:[\da-f]{32}|\d{16,}))\/?$/.test(e.pathname)||/^video\.weibo\.com$/.test(e.host)&&/^\/show\/?$/.test(e.pathname)&&/^\d+:(?:[\da-f]{32}|\d{16,})$/i.test(e.searchParams.get(`fid`)??``)||/^(?:www\.)?weibo\.com$/.test(e.host)&&/^\/newlogin\/?$/.test(e.pathname)&&(e.searchParams.has(`url`)||/^[A-Za-z0-9]+$/.test(e.searchParams.get(`layerid`)??``)),selector:M.videoJsUniversal||`#playVideo`},{host:k.newgrounds,url:`https://www.newgrounds.com/`,match:/^(www.)?newgrounds.com$/,selector:`.ng-video-player`},{host:k.egghead,url:`https://egghead.io/`,match:/^egghead.io$/,selector:`.cueplayer-react-video-holder`},{host:k.youku,url:`https://v.youku.com/`,match:/^v.youku.com$/,selector:`#ykPlayer`},{host:k.archive,url:`https://archive.org/details/`,match:/^archive.org$/,selector:M.jwPlayer,needExtraData:!0},{host:k.kodik,url:`stub`,match:/^kodikplayer.com$/,selector:M.flowplayer,needExtraData:!0},{host:k.patreon,url:`stub`,match:/^(www.)?patreon.com$/,selector:`div[data-tag="post-card"] div[elevation="subtle"] > div > div > div > div`,needExtraData:!0},{additionalData:`old`,host:k.reddit,url:`stub`,match:/^old.reddit.com$/,selector:`.reddit-video-player-root`,needExtraData:!0,needBypassCSP:!0},{host:k.reddit,url:`stub`,match:/^(www.|new.)?reddit.com$/,selector:`div[slot=post-media-container]`,shadowRoot:!0,needExtraData:!0,needBypassCSP:!0},{host:k.kick,url:`https://kick.com/`,match:/^kick.com$/,selector:`#injected-embedded-channel-player-video > div`,needExtraData:!0},{host:k.appledeveloper,url:`https://developer.apple.com/`,match:/^developer.apple.com$/,selector:`.developer-video-player`,needExtraData:!0,needBypassCSP:!0},{host:k.epicgames,url:`https://dev.epicgames.com/community/learning/`,match:/^dev.epicgames.com$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.odysee,url:`stub`,match:/^odysee.com$/,selector:`.video-js-parent`,needExtraData:!0},{host:k.coursehunterLike,url:`stub`,match:on,selector:null,needExtraData:!0},{host:k.sap,url:`https://learning.sap.com/courses/`,match:/^learning.sap.com$/,selector:`.playkit-container`,eventSelector:`.playkit-player`,needExtraData:!0,needBypassCSP:!0},{host:j.udemy,url:`https://www.udemy.com/`,match:/udemy.com$/,selector:M.shakaPlayer,needExtraData:!0},{host:j.datacamp,url:`https://www.datacamp.com/courses/`,match:e=>/^(?:campus\.|projector\.)?datacamp\.com$/.test(e.hostname),selector:M.videoJsUniversal,needExtraData:!0},{host:j.coursera,url:`https://www.coursera.org/`,match:/coursera.org$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.watchpornto,url:`https://watchporn.to/`,match:/^watchporn.to$/,selector:M.flowplayer},{host:k.jove,url:`https://jove.com/`,match:/^(?:app|www)\.jove\.com$/,selector:M.flowplayer},{host:k.linkedin,url:`https://www.linkedin.com/learning/`,match:/^(www.)?linkedin.com$/,selector:M.videoJsUniversal,needExtraData:!0,needBypassCSP:!0},{host:k.incestflix,url:`https://www.incestflix.net/watch/`,match:/^(www.)?incestflix.(net|to|com)$/,selector:`#incflix-stream`,needExtraData:!0},{host:k.porntn,url:`https://porntn.com/videos/`,match:/^porntn.com$/,selector:M.flowplayer,needExtraData:!0},{host:k.dzen,url:`https://dzen.ru/video/watch/`,match:/^dzen.ru$/,selector:`[class*="player__playerWrap"] > div`},{host:k.bunnystream,url:`stub`,match:[/^video\.bunnycdn\.com$/,/^iframe\.mediadelivery\.net$/,/^(?:[^.]+\.)*b-cdn\.net$/],selector:null},{host:k.cloudflarestream,url:`stub`,match:/^(watch|embed|iframe|customer-[^.]+).cloudflarestream.com$/,selector:null},{host:k.loom,url:`https://www.loom.com/share/`,match:/^(www.)?loom.com$/,selector:`.VideoLayersContainer`,needExtraData:!0,needBypassCSP:!0},{host:j.artstation,url:`https://www.artstation.com/learning/`,match:/^(www.)?artstation.com$/,selector:M.videoJsUniversal,needExtraData:!0},{host:k.rtnews,url:`https://www.rt.com/`,match:/^(www.)?rt.com$/,selector:M.jwPlayer,needExtraData:!0},{host:k.bitview,url:`https://www.bitview.net/watch?v=`,match:/^(www.)?bitview.net$/,selector:`.vlScreen`,needExtraData:!0},{host:j.kickstarter,url:`https://www.kickstarter.com/`,match:/^(www.)?kickstarter.com/,selector:`.ksr-video-player`,needExtraData:!0},{host:k.thisvid,url:`https://thisvid.com/`,match:/^(www.)?thisvid.com$/,selector:M.flowplayer},{additionalData:`regional`,host:k.ign,url:`https://de.ign.com/`,match:/^(\w{2}.)?ign.com$/,needExtraData:!0,selector:`.video-container`},{host:k.ign,url:`https://www.ign.com/`,match:/^(www.)?ign.com$/,selector:M.player,needExtraData:!0},{host:k.bunkr,url:`https://bunkr.site/`,match:/^bunkr\.(site|black|cat|media|red|site|ws|org|s[kiu]|c[ir]|fi|p[hks]|ru|la|is|to|a[cx])$/,needExtraData:!0,selector:`.plyr__video-wrapper`},{host:k.imdb,url:`https://www.imdb.com/video/`,match:/^(www\.)?imdb\.com$/,selector:M.jwPlayer},{host:k.telegram,url:`https://t.me/`,match:e=>/^web\.telegram\.org$/.test(e.hostname)&&e.pathname.startsWith(`/k`),selector:`.ckin__player`},{host:j.oraclelearn,url:`https://mylearn.oracle.com/ou/course/`,match:/^mylearn\.oracle\.com/,selector:M.videoJsUniversal,needExtraData:!0,needBypassCSP:!0},{host:j.deeplearningai,url:`https://learn.deeplearning.ai/courses/`,match:/^learn(-dev|-staging)?\.deeplearning\.ai/,selector:`.lesson-video-player`,needExtraData:!0},{host:j.netacad,url:`https://www.netacad.com/`,match:/^(www\.)?netacad\.com/,selector:M.videoJsUniversal,needExtraData:!0},{host:j.mediafile,url:`https://mediafile.cc/`,match:/^(www\.)?mediafile\.cc$/,selector:`div#playerContainer`,needExtraData:!0},{host:k.custom,url:`stub`,match:e=>/([^.]+)\.(mp4|webm)/.test(e.pathname),rawResult:!0}],N=class extends Error{constructor(e){super(e),this.name=`VideoHelperError`}},P=class{API_ORIGIN=window.location.origin;fetch;extraInfo;referer;origin;service;video;language;constructor({fetchFn:e=Ot,extraInfo:t=!0,referer:n=document.referrer??`${window.location.origin}/`,origin:r=window.location.origin,service:i,video:a,language:o=`en`}={}){this.fetch=e,this.extraInfo=t,this.referer=n,this.origin=/^(http(s)?):\/\//.test(String(r))?r:window.location.origin,this.service=i,this.video=a,this.language=o}getVideoData(e){return Promise.resolve(void 0)}getVideoId(e){return Promise.resolve(void 0)}returnBaseData(e){if(this.service)return{url:this.service.url+e,videoId:e,host:this.service.host,duration:void 0}}},cn=class extends P{API_ORIGIN=`https://developer.apple.com`;async getVideoData(e){try{let e=document.querySelector(`meta[property='og:video']`)?.content;if(!e)throw new N(`Failed to find content url`);return{url:e}}catch(t){T.error(`Failed to get apple developer video data by video ID: ${e}`,t.message);return}}async getVideoId(e){return/videos\/play\/([^/]+)\/([\d]+)/.exec(e.pathname)?.[0]}},ln=class extends P{async getVideoId(e){let t=/(details|embed)\/(.+)/.exec(e.pathname)?.[2];if(t)return t.replace(/\/$/,``)||void 0}async getVideoData(e){if(!e)return;let t=`https://archive.org/download/${e.replace(/\+/g,`%20`).replace(/\.[^.]+$/,`.mp4`)}`;return{url:e,video_url:t,translationHelp:[{target:`video_file_url`,targetUrl:t}]}}},un=class extends P{API_ORIGIN=`https://www.artstation.com/api/v2/learning`;getCSRFToken(){return document.querySelector(`meta[name="public-csrf-token"]`)?.content}async getCourseInfo(e){try{let t=this.getCSRFToken();return await(await this.fetch(`${this.API_ORIGIN}/courses/${e}/autoplay.json`,{method:`POST`,headers:t?{"PUBLIC-CSRF-TOKEN":t}:{}})).json()}catch(t){return T.error(`Failed to get artstation course info by courseId: ${e}.`,t.message),!1}}async getVideoUrl(e){try{return(await(await this.fetch(`${this.API_ORIGIN}/quicksilver/video_url.json?chapter_id=${e}`)).json()).url.replace(`qsep://`,`https://`)}catch(t){return T.error(`Failed to get artstation video url by chapterId: ${e}.`,t.message),!1}}async getVideoData(e){let[,t,,,n]=e.split(`/`),r=await this.getCourseInfo(t);if(!r)return;let i=r.chapters.find(e=>e.hash_id===n);if(!i)return;let a=await this.getVideoUrl(i.id);if(!a)return;let{title:o,duration:s,subtitles:c}=i;return{url:a,title:o,duration:s,subtitles:c.filter(e=>e.format===`vtt`).map(e=>({language:E(e.locale),source:`artstation`,format:`vtt`,url:e.file_url}))}}async getVideoId(e){return/courses\/(\w{3,5})\/([^/]+)\/chapters\/(\w{3,5})/.exec(e.pathname)?.[0]}},dn=class extends P{API_ORIGIN=`https://api.banned.video`;async getVideoInfo(e){try{return await(await this.fetch(`${this.API_ORIGIN}/graphql`,{method:`POST`,body:JSON.stringify({operationName:`GetVideo`,query:`query GetVideo($id: String!) { +>>>>>>> Stashed changes getVideo(id: $id) { title description: summary @@ -254,8 +260,9 @@ var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`} videoUrl: directUrl isStream: live } - }`,variables:{id:e}}),headers:{"User-Agent":`bannedVideoFrontEnd`,"apollographql-client-name":`banned-web`,"apollographql-client-version":`1.3`,"content-type":`application/json`}})).json()}catch(t){return console.error(`Failed to get bannedvideo video info by videoId: ${e}.`,t.message),!1}}async getVideoData(e){let t=await this.getVideoInfo(e);if(!t)return;let{videoUrl:n,duration:r,isStream:i,description:a,title:o}=t.data.getVideo;return{url:n,duration:r,isStream:i,title:o,description:a}}async getVideoId(e){return e.searchParams.get(`id`)??void 0}},pn=class extends P{async getVideoId(e){let t=/bangumi\/play\/([^/]+)/.exec(e.pathname)?.[0];if(t)return t;let n=e.searchParams.get(`bvid`);if(n)return`video/${n}`;let r=/^\/(?:[a-z]{2}\/)?((?:play\/\d+(?:\/\d+)?|video\/\d+))\/?$/i.exec(e.pathname)?.[1];if(r)return r;let i=/video\/([^/]+)/.exec(e.pathname)?.[0];return i&&e.searchParams.get(`p`)!==null&&(i+=`/?p=${e.searchParams.get(`p`)}`),i}},mn=class extends P{async getVideoId(e){return/(video|embed)\/([^/]+)/.exec(e.pathname)?.[2]}},hn=class extends P{async getVideoData(e){try{let e=document.querySelector(`.vlScreen > video`)?.src;if(!e)throw new N(`Failed to find video URL`);return{url:e}}catch(t){T.error(`Failed to get Bitview data by videoId: ${e}`,t.message);return}}async getVideoId(e){return e.searchParams.get(`v`)}},gn=class extends P{async getVideoData(e){let t=document.querySelector(`#player > source[type="video/mp4"]`)?.src;if(t)return{url:t}}async getVideoId(e){return/\/f\/([^/]+)/.exec(e.pathname)?.[1]}},_n=class extends P{async getVideoId(e){return e.pathname+e.search}},vn=class extends P{async getVideoId(e){return e.pathname+e.search}},yn=class extends P{API_ORIGIN=this.origin??`https://coursehunter.net`;async getCourseId(){let e=window.course_id;return e===void 0?document.querySelector(`input[name="course_id"]`)?.value:String(e)}async getLessonsData(e){let t=window.lessons;if(t?.length)return t;try{return await(await this.fetch(`${this.API_ORIGIN}/api/v1/course/${e}/lessons`)).json()}catch(t){T.error(`Failed to get CoursehunterLike lessons data by courseId: ${e}, because ${t.message}`);return}}getLessondId(e){let t=e.split(`?lesson=`)?.[1];return t||(t=document.querySelector(`.lessons-item_active`)?.dataset?.index,t)?+t:1}async getVideoData(e){let t=await this.getCourseId();if(!t)return;let n=await this.getLessonsData(t);if(!n)return;let r=this.getLessondId(e),{file:i,duration:a,title:o}=n?.[r-1];if(i)return{url:D(i),duration:a,title:o}}async getVideoId(e){let t=/course\/([^/]+)/.exec(e.pathname)?.[0];return t?t+e.search:void 0}},bn=[`auto`,`ru`,`en`,`zh`,`ko`,`lt`,`lv`,`ar`,`fr`,`it`,`es`,`de`,`ja`],xn=[`ru`,`en`,`kk`],Sn=class e extends P{SUBTITLE_SOURCE=`videojs`;SUBTITLE_FORMAT=`vtt`;static getPlayer(){let e=window.videojs,t=document.querySelector(`video.vjs-tech[id], video[id$='_html5_api']`),n=t?.id?.endsWith(`_html5_api`)?t.id.slice(0,-10):void 0;if(e?.getPlayer){if(n){let t=e.getPlayer(n);if(t)return t}if(t){let n=e.getPlayer(t);if(n)return n}}let r=(typeof e?.getPlayers==`function`?e.getPlayers():e?.players)??{};for(let e of Object.values(r)){let r=e,i=(typeof r.el==`function`?r.el():null)?.querySelector?.(`video.vjs-tech, video`)??null;if(i&&t&&i===t||n&&typeof r.id==`function`&&r.id()===n)return e}}getVideoDataByPlayer(t){try{let n=e.getPlayer(),r=document.querySelector(`video.vjs-tech, video[id$='_html5_api'], video[src]`);if(!n&&!r)throw Error(`Video player/video element not found, videoId ${t}`);let i=n?.duration?.()??r?.duration,a;if(n){let e=typeof n.currentSources==`function`?n.currentSources():n.getCache?.()?.sources;a=(Array.isArray(e)?e.find(e=>e?.type===`video/mp4`||e?.type===`video/webm`||e?.src):void 0)?.src}if(a??=r?.currentSrc||r?.src||r?.getAttribute?.(`src`)||void 0,!a)throw Error(`Failed to find video url for videoID ${t}`);let o=(r?Array.from(r.querySelectorAll(`track[src]`)):[]).filter(e=>e.kind!==`metadata`).flatMap(e=>{let t=e.getAttribute(`src`);if(!t)return[];let n=new URL(t,window.location.href).toString();return[{language:E(e.srclang||``),source:this.SUBTITLE_SOURCE,format:this.SUBTITLE_FORMAT,url:n}]});return{url:a,duration:i,subtitles:o}}catch(e){T.error(`Failed to get videojs video data`,e.message);return}}},Cn=class e extends Sn{API_ORIGIN=`https://www.coursera.org/api`;SUBTITLE_SOURCE=`coursera`;async getCourseData(e){try{return(await(await this.fetch(`${this.API_ORIGIN}/onDemandCourses.v1/${e}`)).json())?.elements?.[0]}catch(t){T.error(`Failed to get course data by courseId: ${e}`,t.message);return}}static getPlayer(){return Sn.getPlayer()}async getVideoData(t){let n=this.getVideoDataByPlayer(t);if(!n)return;let{options_:r}=e.getPlayer()??{};!n.subtitles?.length&&r&&(n.subtitles=r.tracks.map(e=>({url:e.src,language:E(e.srclang),source:this.SUBTITLE_SOURCE,format:this.SUBTITLE_FORMAT})));let i=r?.courseId;if(!i)return n;let a=`en`,o=await this.getCourseData(i);if(o){let{primaryLanguageCodes:[e]}=o;a=e?E(e):`en`}bn.includes(a)||(a=`en`);let s=(n.subtitles.find(e=>e.language===a)??n.subtitles?.[0])?.url;s||T.warn(`Failed to find any subtitle file`);let{url:c,duration:l}=n,u=s?[{target:`subtitles_file_url`,targetUrl:s},{target:`video_file_url`,targetUrl:c}]:null;return{...s?{url:this.service?.url+t,translationHelp:u}:{url:c,translationHelp:u},detectedLanguage:a,duration:l}}async getVideoId(e){return(/learn\/([^/]+)\/lecture\/([^/]+)/.exec(e.pathname)??/lecture\/([^/]+)\/([^/]+)/.exec(e.pathname))?.[0]}},wn=class extends P{getVideoIdFromUrl(e){let t=e.searchParams.get(`video`);if(t)return t}resolveVideoIdViaPostMessage(){return new Promise(e=>{let t=`https://www.dailymotion.com`,n=setTimeout(()=>{window.removeEventListener(`message`,r),e(void 0)},3e3),r=i=>{i.origin===t&&typeof i.data==`string`&&i.data.startsWith(`getVideoId:`)&&(clearTimeout(n),window.removeEventListener(`message`,r),e(i.data.replace(`getVideoId:`,``)))};window.addEventListener(`message`,r),window.top?.postMessage(`getVideoId:`,t)})}async getVideoId(e){return window.self===window.top?this.getVideoIdFromUrl(e):await this.resolveVideoIdViaPostMessage()}},Tn=class extends Sn{SUBTITLE_SOURCE=`datacamp`;getVideoDataFromInput(){try{let e=document.getElementById(`videoData`);return!e||!(e instanceof HTMLInputElement)&&!(e instanceof HTMLTextAreaElement)||!e.value?null:JSON.parse(e.value)}catch(e){return T.error(`Failed to parse DataCamp videoData input`,e instanceof Error?e.message:String(e)),null}}async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let n=this.getVideoDataFromInput(),r=n?.video_url??n?.plain_video_mp4_link??n?.plain_video_hls_link??n?.video_mp4_link??n?.video_hls_link??t.url;if(r)return{url:e,video_url:r,translationHelp:[{target:`video_file_url`,targetUrl:r}]}}async getVideoId(e){return e.href}},En=class extends P{async getVideoData(e){if(!this.video)return;let t=this.video.querySelector(`source[type="application/x-mpegurl"]`)?.src;if(t)return{url:t}}async getVideoId(e){return/courses\/(([^/]+)\/lesson\/([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},Dn=class e extends P{static getPlayer(){if(!(typeof player>`u`))return player}async getVideoData(t){let n=e.getPlayer();if(!n)return;let{config:{url:r,duration:i,lang:a,isLive:o}}=n;if(!r)return;let s=r.find(e=>e.src.includes(`www.douyin.com/aweme/v1/play/`));if(s)return{url:D(s.src),duration:i,isStream:o,...bn.includes(a)?{detectedLanguage:a}:{}}}async getVideoId(t){return/video\/([\d]+)/.exec(t.pathname)?.[0]||e.getPlayer()?.config.vid}},On=class extends P{async getVideoId(e){return/video\/watch\/([^/]+)/.exec(e.pathname)?.[1]}},kn=class extends P{async getVideoId(e){return e.pathname.slice(1)}},An=class extends P{API_ORIGIN=`https://dev.epicgames.com/community/api/learning`;async getPostInfo(e){try{return await(await this.fetch(`${this.API_ORIGIN}/post.json?hash_id=${e}`)).json()}catch(t){return T.error(`Failed to get epicgames post info by videoId: ${e}.`,t.message),!1}}getVideoBlock(){let e=/videoUrl\s?=\s"([^"]+)"?/,t=Array.from(document.body.querySelectorAll(`script`)).find(t=>e.exec(t.innerHTML));if(!t)return;let n=t.innerHTML.trim(),r=e.exec(n)?.[1]?.replace(`qsep://`,`https://`);if(!r)return;let i=/sources\s?=\s(\[([^\]]+)\])?/.exec(n)?.[1];if(!i)return{playlistUrl:r,subtitles:[]};try{return i=`${i.replace(/src:(\s)+?(videoUrl)/g,`src:"removed"`).substring(0,i.lastIndexOf(`},`))}]`.split(` + }`,variables:{id:e}}),headers:{"User-Agent":`bannedVideoFrontEnd`,"apollographql-client-name":`banned-web`,"apollographql-client-version":`1.3`,"content-type":`application/json`}})).json()}catch(t){return console.error(`Failed to get bannedvideo video info by videoId: ${e}.`,t.message),!1}}async getVideoData(e){let t=await this.getVideoInfo(e);if(!t)return;let{videoUrl:n,duration:r,isStream:i,description:a,title:o}=t.data.getVideo;return{url:n,duration:r,isStream:i,title:o,description:a}}async getVideoId(e){return e.searchParams.get(`id`)??void 0}},fn=class extends P{async getVideoId(e){let t=/bangumi\/play\/([^/]+)/.exec(e.pathname)?.[0];if(t)return t;let n=e.searchParams.get(`bvid`);if(n)return`video/${n}`;let r=/^\/(?:[a-z]{2}\/)?((?:play\/\d+(?:\/\d+)?|video\/\d+))\/?$/i.exec(e.pathname)?.[1];if(r)return r;let i=/video\/([^/]+)/.exec(e.pathname)?.[0];return i&&e.searchParams.get(`p`)!==null&&(i+=`/?p=${e.searchParams.get(`p`)}`),i}},pn=class extends P{async getVideoId(e){return/(video|embed)\/([^/]+)/.exec(e.pathname)?.[2]}},mn=class extends P{async getVideoData(e){try{let e=document.querySelector(`.vlScreen > video`)?.src;if(!e)throw new N(`Failed to find video URL`);return{url:e}}catch(t){T.error(`Failed to get Bitview data by videoId: ${e}`,t.message);return}}async getVideoId(e){return e.searchParams.get(`v`)}},hn=class extends P{async getVideoData(e){let t=document.querySelector(`#player > source[type="video/mp4"]`)?.src;if(t)return{url:t}}async getVideoId(e){return/\/f\/([^/]+)/.exec(e.pathname)?.[1]}},gn=class extends P{async getVideoId(e){return e.pathname+e.search}},_n=class extends P{async getVideoId(e){return e.pathname+e.search}},vn=class extends P{API_ORIGIN=this.origin??`https://coursehunter.net`;async getCourseId(){let e=window.course_id;return e===void 0?document.querySelector(`input[name="course_id"]`)?.value:String(e)}async getLessonsData(e){let t=window.lessons;if(t?.length)return t;try{return await(await this.fetch(`${this.API_ORIGIN}/api/v1/course/${e}/lessons`)).json()}catch(t){T.error(`Failed to get CoursehunterLike lessons data by courseId: ${e}, because ${t.message}`);return}}getLessondId(e){let t=e.split(`?lesson=`)?.[1];return t||(t=document.querySelector(`.lessons-item_active`)?.dataset?.index,t)?+t:1}async getVideoData(e){let t=await this.getCourseId();if(!t)return;let n=await this.getLessonsData(t);if(!n)return;let r=this.getLessondId(e),{file:i,duration:a,title:o}=n?.[r-1];if(i)return{url:e,video_url:i,translationHelp:[{target:`video_file_url`,targetUrl:D(i)}],duration:a,title:o}}async getVideoId(e){return e.href}},yn=[`auto`,`ru`,`en`,`zh`,`ko`,`lt`,`lv`,`ar`,`fr`,`it`,`es`,`de`,`ja`],bn=[`ru`,`en`,`kk`],xn=class e extends P{SUBTITLE_SOURCE=`videojs`;SUBTITLE_FORMAT=`vtt`;static getPlayer(){let e=window.videojs,t=document.querySelector(`video.vjs-tech[id], video[id$='_html5_api']`),n=t?.id?.endsWith(`_html5_api`)?t.id.slice(0,-10):void 0;if(e?.getPlayer){if(n){let t=e.getPlayer(n);if(t)return t}if(t){let n=e.getPlayer(t);if(n)return n}}let r=(typeof e?.getPlayers==`function`?e.getPlayers():e?.players)??{};for(let e of Object.values(r)){let r=e,i=(typeof r.el==`function`?r.el():null)?.querySelector?.(`video.vjs-tech, video`)??null;if(i&&t&&i===t||n&&typeof r.id==`function`&&r.id()===n)return e}}getVideoDataByPlayer(t){try{let n=e.getPlayer(),r=document.querySelector(`video.vjs-tech, video[id$='_html5_api'], video[src]`);if(!n&&!r)throw Error(`Video player/video element not found, videoId ${t}`);let i=n?.duration?.()??r?.duration,a;if(n){let e=typeof n.currentSources==`function`?n.currentSources():n.getCache?.()?.sources;a=(Array.isArray(e)?e.find(e=>e?.type===`video/mp4`||e?.type===`video/webm`||e?.src):void 0)?.src}if(a??=r?.currentSrc||r?.src||r?.getAttribute?.(`src`)||void 0,!a)throw Error(`Failed to find video url for videoID ${t}`);let o=(r?Array.from(r.querySelectorAll(`track[src]`)):[]).filter(e=>e.kind!==`metadata`).flatMap(e=>{let t=e.getAttribute(`src`);if(!t)return[];let n=new URL(t,window.location.href).toString();return[{language:E(e.srclang||``),source:this.SUBTITLE_SOURCE,format:this.SUBTITLE_FORMAT,url:n}]});return{url:a,duration:i,subtitles:o}}catch(e){T.error(`Failed to get videojs video data`,e.message);return}}},Sn=class e extends xn{API_ORIGIN=`https://www.coursera.org/api`;SUBTITLE_SOURCE=`coursera`;async getCourseData(e){try{return(await(await this.fetch(`${this.API_ORIGIN}/onDemandCourses.v1/${e}`)).json())?.elements?.[0]}catch(t){T.error(`Failed to get course data by courseId: ${e}`,t.message);return}}static getPlayer(){return xn.getPlayer()}async getVideoData(t){let n=this.getVideoDataByPlayer(t);if(!n)return;let{options_:r}=e.getPlayer()??{};!n.subtitles?.length&&r&&(n.subtitles=r.tracks.map(e=>({url:e.src,language:E(e.srclang),source:this.SUBTITLE_SOURCE,format:this.SUBTITLE_FORMAT})));let i=r?.courseId;if(!i)return n;let a=`en`,o=await this.getCourseData(i);if(o){let{primaryLanguageCodes:[e]}=o;a=e?E(e):`en`}yn.includes(a)||(a=`en`);let s=(n.subtitles.find(e=>e.language===a)??n.subtitles?.[0])?.url;s||T.warn(`Failed to find any subtitle file`);let{url:c,duration:l}=n,u=s?[{target:`subtitles_file_url`,targetUrl:s},{target:`video_file_url`,targetUrl:c}]:null;return{...s?{url:this.service?.url+t,translationHelp:u}:{url:c,translationHelp:u},detectedLanguage:a,duration:l}}async getVideoId(e){return(/learn\/([^/]+)\/lecture\/([^/]+)/.exec(e.pathname)??/lecture\/([^/]+)\/([^/]+)/.exec(e.pathname))?.[0]}},Cn=class extends P{getVideoIdFromUrl(e){let t=e.searchParams.get(`video`);if(t)return t}resolveVideoIdViaPostMessage(){return new Promise(e=>{let t=`https://www.dailymotion.com`,n=setTimeout(()=>{window.removeEventListener(`message`,r),e(void 0)},3e3),r=i=>{i.origin===t&&typeof i.data==`string`&&i.data.startsWith(`getVideoId:`)&&(clearTimeout(n),window.removeEventListener(`message`,r),e(i.data.replace(`getVideoId:`,``)))};window.addEventListener(`message`,r),window.top?.postMessage(`getVideoId:`,t)})}async getVideoId(e){return window.self===window.top?this.getVideoIdFromUrl(e):await this.resolveVideoIdViaPostMessage()}},wn=class extends xn{SUBTITLE_SOURCE=`datacamp`;getVideoDataFromInput(){try{let e=document.querySelector(`#slideDeckData`)||document.getElementById(`videoData`);return!e||!(e instanceof HTMLInputElement)&&!(e instanceof HTMLTextAreaElement)||!e.value?null:JSON.parse(e.value)}catch(e){return T.error(`Failed to parse DataCamp videoData input`,e instanceof Error?e.message:String(e)),null}}async getVideoData(e){if(!this.getVideoDataByPlayer(e))return;let t=this.getVideoDataFromInput(),n=t?.video_url??t?.plain_video_mp4_link??t?.plain_video_hls_link??t?.video_mp4_link??t?.video_hls_link;if(n)return{url:e,video_url:n,translationHelp:[{target:`video_file_url`,targetUrl:n}]}}async getVideoId(e){return e.href}},Tn=class extends P{async getVideoData(e){if(!this.video)return;let t=this.video.querySelector(`source[type="application/x-mpegurl"]`)?.src;if(t)return{url:t}}async getVideoId(e){return/courses\/(([^/]+)\/lesson\/([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},En=class e extends P{static getPlayer(){if(!(typeof player>`u`))return player}async getVideoData(t){let n=e.getPlayer();if(!n)return;let{config:{url:r,duration:i,lang:a,isLive:o}}=n;if(!r)return;let s=r.find(e=>e.src.includes(`www.douyin.com/aweme/v1/play/`));if(s)return{url:D(s.src),duration:i,isStream:o,...yn.includes(a)?{detectedLanguage:a}:{}}}async getVideoId(t){return/video\/([\d]+)/.exec(t.pathname)?.[0]||e.getPlayer()?.config.vid}},Dn=class extends P{async getVideoId(e){return/video\/watch\/([^/]+)/.exec(e.pathname)?.[1]}},On=class extends P{async getVideoId(e){return e.pathname.slice(1)}},kn=class extends P{API_ORIGIN=`https://dev.epicgames.com/community/api/learning`;async getPostInfo(e){try{return await(await this.fetch(`${this.API_ORIGIN}/post.json?hash_id=${e}`)).json()}catch(t){return T.error(`Failed to get epicgames post info by videoId: ${e}.`,t.message),!1}}getVideoBlock(){let e=/videoUrl\s?=\s"([^"]+)"?/,t=Array.from(document.body.querySelectorAll(`script`)).find(t=>e.exec(t.innerHTML));if(!t)return;let n=t.innerHTML.trim(),r=e.exec(n)?.[1]?.replace(`qsep://`,`https://`);if(!r)return;let i=/sources\s?=\s(\[([^\]]+)\])?/.exec(n)?.[1];if(!i)return{playlistUrl:r,subtitles:[]};try{return i=`${i.replace(/src:(\s)+?(videoUrl)/g,`src:"removed"`).substring(0,i.lastIndexOf(`},`))}]`.split(` `).map(e=>e.replace(/([^\s]+):\s?(?!.*\1)/,`"$1":`)).join(` +<<<<<<< Updated upstream `),{playlistUrl:r,subtitles:JSON.parse(i).filter(e=>e.type===`captions`)}}catch{return{playlistUrl:r,subtitles:[]}}}async getVideoData(e){let t=e.split(`:`)?.[1],n=await this.getPostInfo(t);if(!n)return;let r=this.getVideoBlock();if(!r)return;let{playlistUrl:i,subtitles:a}=r,{title:o,description:s}=n;return{url:i,title:o,description:s,subtitles:a.map(e=>({language:E(e.srclang),source:`epicgames`,format:`vtt`,url:e.src}))}}async getVideoId(e){return new Promise(e=>{let t=`https://dev.epicgames.com`,n=btoa(window.location.href);window.addEventListener(`message`,n=>{if(n.origin===t&&typeof n.data==`string`&&n.data.startsWith(`getVideoId:`))return e(n.data.replace(`getVideoId:`,``))}),window.top?.postMessage(`getVideoId:${n}`,t)})}},jn=class extends P{async getVideoId(e){return/video-([^/]+)\/([^/]+)/.exec(e.pathname)?.[0]}},Mn=class extends P{async getVideoId(e){return e.pathname.slice(1)}},Nn=class extends P{getPlayerData(){return document.querySelector(`#movie_player`)?.getVideoData?.()??void 0}async getVideoId(e){return this.getPlayerData()?.video_id}},Pn=class extends P{getVideoDataBySource(e){let t=document.querySelector(`.icms.video > source[type="video/mp4"][data-quality="360"]`)?.src;return t?{url:D(t)}:this.returnBaseData(e)}getVideoDataByNext(e){try{let e=document.getElementById(`__NEXT_DATA__`)?.textContent;if(!e)throw new en(`Not found __NEXT_DATA__ content`);let{props:{pageProps:{page:{description:t,title:n,video:{videoMetadata:{duration:r},assets:i}}}}}=JSON.parse(e),a=i.find(e=>e.height===360&&e.url.includes(`.mp4`))?.url;if(!a)throw new en(`Not found video URL in assets`);return{url:D(a),duration:r,title:n,description:t}}catch(t){return T.warn(`Failed to get ign video data by video ID: ${e}, because ${t.message}. Using clear link instead...`),this.returnBaseData(e)}}async getVideoData(e){return document.getElementById(`__NEXT_DATA__`)?this.getVideoDataByNext(e):this.getVideoDataBySource(e)}async getVideoId(e){return/([^/]+)\/([\d]+)\/video\/([^/]+)/.exec(e.pathname)?.[0]??/\/videos\/([^/]+)/.exec(e.pathname)?.[0]}},Fn=class extends P{async getVideoId(e){return/video\/([^/]+)/.exec(e.pathname)?.[1]}},In=class extends P{async getVideoData(e){try{let e=document.querySelector(`#incflix-stream source:first-of-type`);if(!e)throw new N(`Failed to find source element`);let t=e.getAttribute(`src`);if(!t)throw new N(`Failed to find source link`);let n=new URL(t.startsWith(`//`)?`https:${t}`:t);return n.searchParams.append(`media-proxy`,`video.mp4`),{url:D(n)}}catch(t){T.error(`Failed to get Incestflix data by videoId: ${e}`,t.message);return}}async getVideoId(e){return/\/watch\/([^/]+)/.exec(e.pathname)?.[1]}},Ln=class extends P{async getVideoId(e){let t=/^\/(?:[a-z]{2}\/)?v\/(?\d+)\/(?[^/?#]+)\/?$/i.exec(e.pathname)?.groups;if(!t)return;let{id:n,slug:r}=t;return`v/${n}/${r}`}},Rn=class extends P{API_ORIGIN=`https://kick.com/api`;async getClipInfo(e){try{let{clip_url:t,duration:n,title:r}=(await(await this.fetch(`${this.API_ORIGIN}/v2/clips/${e}`)).json()).clip;return{url:t,duration:n,title:r}}catch(t){T.error(`Failed to get kick clip info by clipId: ${e}.`,t.message);return}}async getVideoInfo(e){try{let{source:t,livestream:n}=await(await this.fetch(`${this.API_ORIGIN}/v1/video/${e}`)).json(),{session_title:r,duration:i}=n;return{url:t,duration:Math.round(i/1e3),title:r}}catch(t){T.error(`Failed to get kick video info by videoId: ${e}.`,t.message);return}}async getVideoData(e){return e.startsWith(`videos`)?await this.getVideoInfo(e.replace(`videos/`,``)):await this.getClipInfo(e.replace(`clips/`,``))}async getVideoId(e){return/([^/]+)\/((videos|clips)\/([^/]+))/.exec(e.pathname)?.[2]}},zn=class extends P{async getVideoData(e){try{let e=document.querySelector(`.ksr-video-player > video`),t=e?.querySelector(`source[type^='video/mp4']`)?.src;if(!t)throw new N(`Failed to find video URL`);let n=e?.querySelectorAll(`track`)??[];return{url:t,subtitles:Array.from(n).reduce((e,t)=>{let n=t.getAttribute(`srclang`),r=t.getAttribute(`src`);return!n||!r||e.push({language:E(n),url:r,format:`vtt`,source:`kickstarter`}),e},[])}}catch(t){T.error(`Failed to get Kickstarter data by videoId: ${e}`,t.message);return}}async getVideoId(e){return e.pathname.slice(1)}},Bn=class extends P{API_ORIGIN=window.location.origin;getSecureData(e){try{let[t,n,r]=e.split(`/`).filter(e=>e),i=Array.from(document.getElementsByTagName(`script`)),a=i.filter(e=>e.innerHTML.includes(`videoId = "${n}"`)||e.innerHTML.includes(`serialId = Number(${n})`));if(!a.length)throw new N(`Failed to find secure script`);let o=a[0]?.textContent?.trim();if(!o)throw new N(`Secure script content is empty`);let s=/'{[^']+}'/.exec(o)?.[0];if(!s)throw new N(`Secure json wasn't found in secure script`);let c=JSON.parse(s.replaceAll(`'`,``));if(t!==`serial`)return{videoType:t,videoId:n,hash:r,...c};let l=i.find(e=>e.innerHTML.includes(`var videoInfo = {}`))?.textContent?.trim();if(!l)throw new N(`Failed to find videoInfo content`);let u=/videoInfo\.type\s+?=\s+?'([^']+)'/.exec(l)?.[1],d=/videoInfo\.id\s+?=\s+?'([^']+)'/.exec(l)?.[1],f=/videoInfo\.hash\s+?=\s+?'([^']+)'/.exec(l)?.[1];if(!u||!d||!f)throw new N(`Failed to parse videoInfo content`);return{videoType:u,videoId:d,hash:f,...c}}catch(t){return T.error(`Failed to get kodik secure data by videoPath: ${e}.`,t.message),!1}}async getFtor(e){let{videoType:t,videoId:n,hash:r,d:i,d_sign:a,pd:o,pd_sign:s,ref:c,ref_sign:l}=e;try{return await(await this.fetch(`${this.API_ORIGIN}/ftor`,{method:`POST`,headers:{"User-Agent":f.userAgent,Origin:this.API_ORIGIN,Referer:`${this.API_ORIGIN}/${t}/${n}/${r}/360p`},body:new URLSearchParams({d:i,d_sign:a,pd:o,pd_sign:s,ref:decodeURIComponent(c),ref_sign:l,bad_user:`false`,cdn_is_working:`true`,info:`{}`,type:t,hash:r,id:n})})).json()}catch(e){return T.error(`Failed to get kodik video data (type: ${t}, id: ${n}, hash: ${r})`,e.message),!1}}decryptUrl(e){return`https:${atob(e.replace(/[a-zA-Z]/g,e=>{let t=e.charCodeAt(0)+18,n=e<=`Z`?90:122;return String.fromCharCode(n>=t?t:t-26)}))}`}async getVideoData(e){let t=this.getSecureData(e);if(!t)return;let n=await this.getFtor(t);if(!n)return;let r=Object.entries(n.links[n.default.toString()]).find(([,e])=>e.type===`application/x-mpegURL`)?.[1];if(r)return{url:r.src.startsWith(`//`)?`https:${r.src}`:this.decryptUrl(r.src)}}async getVideoId(e){return/\/(uv|video|seria|episode|season|serial)\/([^/]+)\/([^/]+)\/([\d]+)p/.exec(e.pathname)?.[0]}},Vn=class extends Sn{SUBTITLE_SOURCE=`linkedin`;async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let{url:n,duration:r,subtitles:i}=t;return{url:D(new URL(n)),duration:r,subtitles:i}}async getVideoId(e){return/\/learning\/(([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},Hn;(function(e){e.Channel=`Channel`,e.Video=`Video`})(Hn||={});var Un=class extends P{getClientVersion(){if(!(typeof SENTRY_RELEASE>`u`))return SENTRY_RELEASE.id}async getVideoData(e){try{let t=this.getClientVersion();if(!t)throw new N(`Failed to get client version`);let n=await this.fetch(`https://www.loom.com/graphql`,{headers:{"User-Agent":f.userAgent,"content-type":`application/json`,"x-loom-request-source":`loom_web_${t}`,"apollographql-client-name":`web`,"apollographql-client-version":t,"Alt-Used":`www.loom.com`},body:`{"operationName":"FetchCaptions","variables":{"videoId":"${e}"},"query":"query FetchCaptions($videoId: ID!, $password: String) {\\n fetchVideoTranscript(videoId: $videoId, password: $password) {\\n ... on VideoTranscriptDetails {\\n id\\n captions_source_url\\n language\\n __typename\\n }\\n ... on GenericError {\\n message\\n __typename\\n }\\n __typename\\n }\\n}"}`,method:`POST`});if(n.status!==200)throw new N(`Failed to get data from graphql`);let r=(await n.json()).data.fetchVideoTranscript;if(r.__typename===`GenericError`)throw new N(r.message);return{url:this.service?.url+e,subtitles:[{format:`vtt`,language:E(r.language),source:`loom`,url:r.captions_source_url}]}}catch(t){return T.error(`Failed to get Loom video data, because: ${t.message}`),this.returnBaseData(e)}}async getVideoId(e){return/(embed|share)\/([^/]+)?/.exec(e.pathname)?.[2]}},Wn=class extends P{API_ORIGIN=`https://my.mail.ru`;async getVideoMeta(e){try{return await(await this.fetch(`${this.API_ORIGIN}/+/video/meta/${e}?xemail=&ajax_call=1&func_name=&mna=&mnb=&ext=1&_=${Date.now()}`)).json()}catch(e){T.error(`Failed to get mail.ru video data`,e.message);return}}async getVideoId(e){let t=e.pathname;if(/\/(v|mail|bk|inbox)\//.exec(t))return t.slice(1);let n=/video\/embed\/([^/]+)/.exec(t)?.[1];if(!n)return;let r=await this.getVideoMeta(n);if(r)return r.meta.url.replace(`//my.mail.ru/`,``)}},Gn=class extends P{DEFAULT_SITE_ORIGIN=`https://mediafile.cc`;SITE_ORIGIN=this.service?.url?.slice(0,-1)??this.DEFAULT_SITE_ORIGIN;getVideoSrc(){let e=this.video instanceof HTMLVideoElement?this.video:document.querySelector(`video`);return e?.src||e?.currentSrc||e?.querySelector(`source[src]`)?.src||void 0}async getVideoData(e){let t=this.getVideoSrc();if(t)return{url:`${this.SITE_ORIGIN}/${e}`,video_url:t,translationHelp:[{target:`video_file_url`,targetUrl:t}]}}async getVideoId(e){return e.pathname.replace(/^\/+/,``)||void 0}},Kn=class extends Sn{SUBTITLE_SOURCE=`netacad`;async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let{url:n,duration:r,subtitles:i}=t;return{url:D(new URL(n)),duration:r,subtitles:i}}async getVideoId(e){return e.pathname+e.search}},qn=class extends P{async getVideoId(e){return/([^/]+)\/(view)\/([^/]+)/.exec(e.pathname)?.[0]}},Jn=class extends P{async getVideoId(e){return e.hostname===`nico.ms`?e.pathname.replace(/^\//,``).split(`/`)[0]||void 0:/\/watch\/([^/?#]+)/.exec(e.pathname)?.[1]}},Yn=class extends P{async getVideoData(e){let t=this.returnBaseData(e);if(!t)return t;try{if(!this.video)throw Error(`Video element not found`);let e=this.video.querySelector(`source[type^="video/mp4"], source[type^="video/webm"]`)?.src;if(!e||!/^https?:\/\//.test(e))throw Error(`Video source not found`);return{...t,translationHelp:[{target:`video_file_url`,targetUrl:e}]}}catch{return t}}async getVideoId(e){return/gag\/([^/]+)/.exec(e.pathname)?.[1]}},Xn=class extends P{API_ORIGIN=`https://odysee.com`;async getVideoData(e){try{let t=await(await this.fetch(`${this.API_ORIGIN}/${e}`)).text(),n=/"contentUrl":(\s)?"([^"]+)"/.exec(t)?.[2];if(!n)throw new N(`Odysee url doesn't parsed`);return{url:n}}catch(t){T.error(`Failed to get odysee video data by video ID: ${e}`,t.message);return}}async getVideoId(e){return e.pathname.slice(1)}},Zn=class extends P{async getVideoId(e){return/\/video\/(\d+)/.exec(e.pathname)?.[1]}},Qn=class extends P{async getVideoId(e){return/\/([a-z]{2}\/(?:[a-z0-9-]+\/)?(?:replay|videos?|original-series\/episode)\/[\w-]+)\/?$/i.exec(e.pathname)?.[1]}},$n=class extends Sn{SUBTITLE_SOURCE=`oraclelearn`;async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let{url:n,duration:r,subtitles:i}=t,a=this.returnBaseData(e),o=D(new URL(n));return a?{url:a.url,duration:r,subtitles:i,translationHelp:[{target:`video_file_url`,targetUrl:o}]}:{url:o,duration:r,subtitles:i}}async getVideoId(e){return/\/ou\/course\/(([^/]+)\/(\d+)\/(\d+))/.exec(e.pathname)?.[1]}},er=class extends P{API_ORIGIN=`https://www.patreon.com/api`;async getPosts(e){try{return await(await this.fetch(`${this.API_ORIGIN}/posts/${e}?json-api-use-default-includes=false`)).json()}catch(t){return T.error(`Failed to get patreon posts by postId: ${e}.`,t.message),!1}}async getVideoData(e){let t=await this.getPosts(e);if(!t)return;let n=t.data.attributes.post_file.url;if(n)return{url:n}}async getVideoId(e){let t=/posts\/([^/]+)/.exec(e.pathname)?.[1];if(t)return t.replace(/[^\d.]/g,``)}},tr=class extends P{async getVideoId(e){let t=e.pathname.replace(/\/+$/,``),n=/\/videos\/watch\/([^/]+)/.exec(t)?.[1];if(n)return`/videos/watch/${n}`;let r=/\/w\/([^/]+)/.exec(t)?.[1];if(r)return`/videos/watch/${r}`}},nr=class extends P{async getVideoId(e){return/\/((?:videopopout|[^/]+(?:\/profile)?\/videos)\/[^/?#&/]+)\/?$/.exec(e.pathname)?.[1]??/^\/([^/#?]+)\/?$/.exec(e.pathname)?.[1]}},rr=class extends P{async getVideoId(e){return e.searchParams.get(`viewkey`)??/embed\/([^/]+)/.exec(e.pathname)?.[1]}},ir=class extends P{async getVideoData(e){try{if(typeof flashvars>`u`)return;let{rnd:e,video_url:t,video_title:n}=flashvars;if(!t||!e)throw new N(`Failed to find video source or rnd`);let r=new URL(t);r.searchParams.append(`rnd`,e),T.log(`PornTN get_file link`,r.href);let i=await this.fetch(r.href,{method:`head`}),a=new URL(i.url);return T.log(`PornTN cdn link`,a.href),{url:D(a),title:n}}catch(t){T.error(`Failed to get PornTN data by videoId: ${e}`,t.message);return}}async getVideoId(e){return/\/videos\/(([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},ar=class extends P{async getVideoData(e){try{if(!e)throw new N(`Failed to find PreserveTube video ID`);return{url:`https://s3.archive.party/preservetube/${e}.mp4`}}catch(t){T.error(`Failed to get PreserveTube data by videoId: ${e}`,t.message);return}}async getVideoId(e){return e.searchParams.get(`v`)??void 0}},or=class extends P{API_ORIGIN=`https://www.reddit.com`;async getContentUrl(e){if(this.service?.additionalData!==`old`){let e=document.querySelector(`shreddit-player-2, shreddit-player`);return(e?.getAttribute(`src`)??e?.querySelector(`source[type="application/vnd.apple.mpegURL"]`)?.getAttribute(`src`))?.replaceAll(`&`,`&`)}return document.querySelector(`[data-hls-url]`)?.dataset.hlsUrl?.replaceAll(`&`,`&`)}async getVideoData(e){try{let t=await this.getContentUrl(e);if(!t)throw new N(`Failed to find content url`);return{url:decodeURIComponent(t)}}catch(t){T.error(`Failed to get reddit video data by video ID: ${e}`,t.message);return}}async getVideoId(e){return/\/r\/(([^/]+)\/([^/]+)\/([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},sr=class extends P{async getVideoData(e){let t=document.querySelector(`.jw-video, .media__video_noscript`);if(!t)return;let n=t.getAttribute(`src`);if(n)return n.endsWith(`.MP4`)&&(n=D(n)),{videoId:e,url:n}}async getVideoId(e){return e.pathname.slice(1)}},cr=class extends P{async getVideoId(e){let t=/\/videos?\/(\d+)(?:\/(.+))?\/?$/.exec(e.pathname);if(!t)return;let[,n,r]=t;return r?`${n}/${r.replace(/\/+$/,``)}/`:n}},lr=class extends P{async getVideoId(e){return e.pathname.slice(1)}},ur=class extends P{async getVideoId(e){return/(?:video|embed)\/([^/]+)/.exec(e.pathname)?.[1]}},dr=class extends P{API_ORIGIN=`https://learning.sap.com/`;async requestKaltura(e,t,n){try{return await(await this.fetch(`https://${e}/api_v3/service/multirequest`,{method:`POST`,body:JSON.stringify({1:{service:`session`,action:`startWidgetSession`,widgetId:`_${t}`},2:{service:`baseEntry`,action:`list`,ks:`{1:result:ks}`,filter:{redirectFromEntryId:n},responseProfile:{type:1,fields:`id,referenceId,name,description,dataUrl,duration,flavorParamsIds,type,dvrStatus,externalSourceType,createdAt,updatedAt,endDate,plays,views,downloadUrl,creatorId`}},3:{service:`baseEntry`,action:`getPlaybackContext`,entryId:`{2:result:objects:0:id}`,ks:`{1:result:ks}`,contextDataParams:{objectType:`KalturaContextDataParams`,flavorTags:`all`}},apiVersion:`3.3.0`,format:1,ks:``,clientTag:`html5:v3.17.22`,partnerId:t}),headers:{"Content-Type":`application/json`}})).json()}catch(e){T.error(`Failed to request kaltura data`,e.message);return}}async getKalturaData(e){try{let t=document.querySelector(`script[data-nscript="beforeInteractive"]`);if(!t)throw new N(`Failed to find script element`);let n=/https:\/\/([^"]+)\/p\/([^"]+)\/embedPlaykitJs\/uiconf_id\/([^"]+)/.exec(t?.src);if(!n)throw new N(`Failed to get sap data for videoId: ${e}`);let[,r,i]=n,a=document.querySelector(`#shadow`)?.firstChild?.getAttribute(`id`);if(!a){let e=document.querySelector(`#__NEXT_DATA__`);if(!e)throw new N(`Failed to find next data element`);a=/"sourceId":\s?"([^"]+)"/.exec(e.innerText)?.[1]}if(!r||Number.isNaN(+i)||!a)throw new N(`One of the necessary parameters for getting a link to a sap video in wasn't found for ${e}. Params: kalturaDomain = ${r}, partnerId = ${i}, entryId = ${a}`);return await this.requestKaltura(r,i,a)}catch(e){T.error(`Failed to get kaltura data`,e.message);return}}async getVideoData(e){let t=await this.getKalturaData(e);if(!t)return;let[,n,r]=t,{duration:i}=n.objects[0],a=r.sources.find(e=>e.format===`url`&&e.protocols===`http,https`&&e.url.includes(`.mp4`))?.url;if(a)return{url:a,subtitles:r.playbackCaptions.map(e=>({language:E(e.languageCode),source:`sap`,format:`vtt`,url:e.webVttUrl,isAutoGenerated:e.label.includes(`auto-generated`)})),duration:i}}async getVideoId(e){return/((courses|learning-journeys)\/([^/]+)(\/[^/]+)?)/.exec(e.pathname)?.[1]}},fr=class extends P{async getVideoId(e){return/\/([\da-z]+\/(?:video|play|embed)(?:\/[^/]+)?)\/?$/i.exec(e.pathname)?.[1]??/\/([\da-z]+-[\da-z]+\/playlist\/[^/]+)\/?$/i.exec(e.pathname)?.[1]}},pr=class e extends P{static getMediaViewer(){if(!(typeof appMediaViewer>`u`))return appMediaViewer}async getVideoId(t){let n=e.getMediaViewer();if(!n||n.live)return;let r=n.target.message;if(r.peer_id._!==`peerChannel`)return;let i=r.media;if(i._!==`messageMediaDocument`||i.document.type!==`video`)return;let a=r.mid&4294967295;return`${await n.managers.appPeersManager.getPeerUsername(r.peerId)}/${a}`}},mr=class extends P{async getVideoId(e){return/(videos|embed)\/[^/]+/.exec(e.pathname)?.[0]}},hr=class extends P{async getVideoId(e){return/([^/]+)\/video\/([^/]+)/.exec(e.pathname)?.[0]}},gr=class extends P{async getVideoId(e){let t=e.searchParams.get(`vid`),n=/([^/]+)\/([\d]+)/.exec(e.pathname)?.[0];if(!(!t||!n))return`${n}?vid=${t}`}},_r=class extends P{API_ORIGIN=`https://clips.twitch.tv`;async getClipLink(e,t){let n=document.querySelector(`script[type='application/ld+json']`),r=e.slice(1);if(n){let e=JSON.parse(n.innerText)[`@graph`].find(e=>e[`@type`]===`VideoObject`)?.creator.url;if(!e)throw new N(`Failed to find channel link`);return`${e.replace(`https://www.twitch.tv/`,``)}/clip/${r}`}let i=r===`embed`,a=document.querySelector(i?`.tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']`:`.clips-player a:not([class])`);if(a)return`${a.href.replace(`https://www.twitch.tv/`,``)}/clip/${i?t:r}`}async getVideoData(e){let t=document.querySelector(`[data-a-target="stream-title"], [data-test-selector="stream-info-card-component__subtitle"]`)?.innerText,n=!!document.querySelector(`[data-a-target="animated-channel-viewers-count"], .channel-status-info--live, .top-bar--pointer-enabled .tw-channel-status-text-indicator`);return{url:this.service?.url+e,isStream:n,title:t}}async getVideoId(e){let t=e.pathname;if(/^m\.twitch\.tv$/.test(t))return/videos\/([^/]+)/.exec(e.href)?.[0]??t.slice(1);if(/^player\.twitch\.tv$/.test(e.hostname))return`videos/${e.searchParams.get(`video`)}`;let n=/([^/]+)\/(?:clip)\/([^/]+)/.exec(t);if(n)return n[0];if(/^clips\.twitch\.tv$/.test(e.hostname))return await this.getClipLink(t,e.searchParams.get(`clip`));let r=/(?:videos)\/([^/]+)/.exec(t);if(r)return r[0];let i=document.querySelector(`.home-offline-hero .tw-link`);if(i?.href){let e=new URL(i.href);return/(?:videos)\/([^/]+)/.exec(e.pathname)?.[0]}return document.querySelector(`.persistent-player`)?t:void 0}},vr=class extends P{async getVideoId(e){let t=/status\/([^/]+)/.exec(e.pathname)?.[1];if(t)return t;let n=(this.video?.closest(`[data-testid="tweet"]`))?.querySelector(`a[role="link"][aria-label]`)?.href;return n?/status\/([^/]+)/.exec(n)?.[1]:void 0}};function yr(e){return typeof e==`object`&&!!e}function br(e){return typeof e==`object`&&!!e}function xr(e){if(Array.isArray(e))return e.filter(br);if(typeof e!=`object`||!e)return[];let t=e;return(Array.isArray(t.Video)?t.Video:Array.isArray(t.video)?t.video:[]).filter(br)}function Sr(e){if(!yr(e))return[];let t=[];for(let[n,r]of Object.entries(e))!yr(r)||typeof r.url!=`string`||t.push({src:r.url,type:typeof r.type==`string`?r.type:void 0,label:typeof r.height==`number`||typeof r.height==`string`?r.height:n});return t}function Cr(e){if(typeof e==`number`&&Number.isFinite(e))return e;let t=String(e??``).match(/(\d{3,4})/);return Number(t?.[1]??0)}function wr(e){if(typeof e.file==`string`)return e.file;if(typeof e.src==`string`)return e.src}function Tr(e,t){return e.includes(`mpegurl`)||/\.m3u8(?:$|[?#])/i.test(t)}function Er(e,t){return e.includes(`dash`)||/\.mpd(?:$|[?#])/i.test(t)}var Dr=class extends P{API_ORIGIN=`${window.location.origin}/api-2.0`;getModuleData(){let e=(document.querySelector(`.ud-app-loader[data-module-id='course-taking']`)??document.querySelector(`[data-module-id='course-taking']`))?.dataset?.moduleArgs;if(e)try{return JSON.parse(e)}catch{return}}getLectureId(e){let t=/(?:\/learn\/(?:v4\/t\/)?lecture\/|#\/?lecture\/)(\d+)/i,n=/\/lecture\/view\/\?/i,r=window.location.href,i=n.test(r)?new URL(r).searchParams:void 0,a=i?(()=>{for(let[e,t]of i){let n=e.toLowerCase();if(n===`lectureid`||n===`lecture_id`)return t}})():void 0;return t.exec(r)?.[1]??a??(e?t.exec(`/${e}`)?.[1]:void 0)}getCourseId(e){let t=e,n=this.normalizeId(t?.courseId??t?.course_id??t?.course?.id);if(n)return n;let r=this.normalizeId(document.querySelector(`[data-course-id]`)?.getAttribute(`data-course-id`));if(r)return r;let i=document.documentElement?.innerHTML??``;return/data-course-id=["'](\d+)/i.exec(i)?.[1]??/"courseId"\s*:\s*(\d+)/i.exec(i)?.[1]??/"courseId"\s*:\s*(\d+)/i.exec(i)?.[1]}normalizeId(e){if(typeof e==`number`&&Number.isFinite(e))return String(e);if(typeof e==`string`)return/^\d+$/.test(e)?e:void 0}parseJson(e){try{return JSON.parse(e)}catch{let t=e.replaceAll(`"`,`"`).replaceAll(`"`,`"`).replaceAll(`'`,`'`).replaceAll(`'`,`'`);try{return JSON.parse(t)}catch{return}}}getViewHtmlCandidates(e){if(typeof e!=`string`||!e.trim())return[];let t=new DOMParser().parseFromString(e,`text/html`),n=[];for(let e of Array.from(t.querySelectorAll(`source`))){let t=e.getAttribute(`src`);t&&n.push({src:t,type:e.getAttribute(`type`)??void 0,label:e.getAttribute(`data-res`)??void 0})}for(let e of Array.from(t.querySelectorAll(`[videojs-setup-data]`))){let t=e.getAttribute(`videojs-setup-data`);if(!t)continue;let r=this.parseJson(t);r&&n.push(...xr(r.sources))}return n}isErrorData(e){return Object.hasOwn(e,`error`)||Object.hasOwn(e,`detail`)&&!Object.hasOwn(e,`_class`)}async getLectureData(e,t){try{let n=await(await this.fetch(`${this.API_ORIGIN}/users/me/subscribed-courses/${e}/lectures/${t}/?`+new URLSearchParams({"fields[lecture]":`title,description,view_html,asset,download_url,is_free,last_watched_second`,"fields[asset]":`asset_type,length,stream_url,media_sources,stream_urls,download_urls,external_url,captions,data,thumbnail_sprite,slides,slide_urls,course_is_drmed,media_license_token`}).toString())).json();if(this.isErrorData(n))throw new N(n.detail??`unknown error`);return n}catch(n){T.error(`Failed to get lecture data by courseId: ${e} and lectureId: ${t}`,n.message);return}}async getCourseLang(e){try{let t=await(await this.fetch(`${this.API_ORIGIN}/users/me/subscribed-courses/${e}?`+new URLSearchParams({"fields[course]":`locale`}).toString())).json();if(!this.isErrorData(t))return t;let n=await(await this.fetch(`${this.API_ORIGIN}/courses/${e}/?`+new URLSearchParams({"fields[course]":`locale`}).toString())).json();if(this.isErrorData(n))throw new N(n.detail??`unknown error`);return n}catch(t){T.error(`Failed to get course lang by courseId: ${e}`,t.message);return}}findVideoUrl(e,t,n,r,i,a,o){let s=[],c=Array.isArray(e)?e:[];for(let e of c)s.push({src:e.src,type:e.type,label:e.label});s.push(...xr(t)),s.push(...xr(n)),s.push(...Sr(a)),typeof o==`string`&&s.push(...this.getViewHtmlCandidates(o)),typeof r==`string`&&s.push({src:r}),typeof i==`string`&&s.push({src:i});let l=this.video?.currentSrc||this.video?.src;typeof l==`string`&&l&&s.push({src:l});let u=new Map;for(let e of s){let t=wr(e);if(!t||/^javascript:/i.test(t))continue;let n=Cr(e.label??e.quality??e.height),r=String(e.type??``).toLowerCase(),i=u.get(t);(!i||n>i.quality)&&u.set(t,{url:t,type:r,quality:n,isYouTubeWatch:/:\/\/(?:www\.)?youtube\.com\/watch\?/i.test(t)})}let d=Array.from(u.values());if(!d.length)return;let f=d.filter(e=>e.type.includes(`mp4`)||/\.mp4(?:$|[?#])/i.test(e.url));return f.length?(f.sort((e,t)=>t.quality-e.quality),f[0]?.url):d.find(e=>Tr(e.type,e.url))?.url||d.find(e=>Er(e.type,e.url))?.url||d.find(e=>!e.isYouTubeWatch)?.url||d[0]?.url}getCaptionLocale(e){let t=typeof e.locale_id==`string`?e.locale_id:typeof e.locale?.locale==`string`?e.locale.locale:void 0;return t?E(t):void 0}findSubtitleUrl(e,t){if(!Array.isArray(e))return;let n=e.filter(e=>yr(e)&&(typeof e.url==`string`||typeof e.download_url==`string`)),r=n.find(e=>this.getCaptionLocale(e)===t)??n.find(e=>this.getCaptionLocale(e)===`en`)??n[0];return r?.url??r?.download_url}async getVideoData(e){let t=this.getModuleData(),n=this.getCourseId(t),r=this.getLectureId(e);if(T.log(`[Udemy] courseId: ${n}, lectureId: ${r}`),!r||!n)return;let i=await this.getLectureData(n,r);if(!i)return;let{title:a,description:o,asset:s,view_html:c}=i,{length:l,media_sources:u,captions:d}=s,f=s,p=f.stream_urls,m=f.download_urls,h=this.findVideoUrl(u,p,m,f.stream_url??f.streamUrl,f.external_url,f.data?.outputs,c);if(!h){T.log(`Failed to find video file in asset sources`,s);return}let g=`en`,_=(await this.getCourseLang(n))?.locale?.locale;typeof _==`string`&&(g=E(_)),bn.includes(g)||(g=`en`);let v=this.findSubtitleUrl(d,g);return v||T.log(`Failed to find subtitle file in captions`,d),{...v?{url:this.service?.url+e,translationHelp:[{target:`subtitles_file_url`,targetUrl:v},{target:`video_file_url`,targetUrl:h}],detectedLanguage:g}:{url:h,translationHelp:null},duration:l,title:a,description:o}}async getVideoId(e){return e.pathname.slice(1)}},Or=class extends P{API_KEY=``;DEFAULT_SITE_ORIGIN=`https://vimeo.com`;SITE_ORIGIN=this.service?.url?.slice(0,-1)??this.DEFAULT_SITE_ORIGIN;isErrorData(e){return Object.hasOwn(e,`error`)}isPrivatePlayer(){return this.referer&&!this.referer.includes(`vimeo.com`)&&this.origin.endsWith(`player.vimeo.com`)}toPublicUrl(e){let[t,n]=e.split(`:`,2);return n?`${this.DEFAULT_SITE_ORIGIN}/${t}/${n}`:`${this.DEFAULT_SITE_ORIGIN}/${t}`}returnPublicBaseData(e){let t=this.returnBaseData(e);if(t)return{...t,url:this.toPublicUrl(e)}}normalizePublicVideoUrl(e,t){try{let n=new URL(e);if(n.hostname===`player.vimeo.com`)return this.toPublicUrl(t);if(n.hostname.endsWith(`vimeo.com`)){let e=/^\/(\d+):([a-z0-9]+)$/i.exec(n.pathname);if(e)return`${this.DEFAULT_SITE_ORIGIN}/${e[1]}/${e[2]}`}}catch{}return e}async getViewerData(){try{let e=await(await this.fetch(`https://vimeo.com/_next/viewer`)).json(),{apiUrl:t,jwt:n}=e;return this.API_ORIGIN=`https://${t}`,this.API_KEY=`jwt ${n}`,e}catch(e){return T.error(`Failed to get default viewer data.`,e.message),!1}}async getVideoInfo(e){try{let t=new URLSearchParams({fields:`name,link,description,duration`}).toString(),n=await(await this.fetch(`${this.API_ORIGIN}/videos/${e}?${t}`,{headers:{Authorization:this.API_KEY}})).json();if(this.isErrorData(n))throw Error(n.developer_message??n.error);return n}catch(t){return T.error(`Failed to get video info by video ID: ${e}`,t.message),!1}}async getPrivateVideoSource(e){try{let{default_cdn:t,cdns:n}=e.dash,r=n[t].url,i=await this.fetch(r);if(i.status!==200)throw new N(await i.text());let a=await i.json(),o=new URL(a.base_url,r),s=a.audio.find(e=>e.mime_type===`audio/mp4`&&e.format===`dash`);if(!s)throw new N(`Failed to find video data`);let c=s.segments?.[0]?.url;if(!c)throw new N(`Failed to find first segment url`);let[l,u]=c.split(`?`,2),d=new URLSearchParams(u);return d.delete(`range`),new URL(`${s.base_url}${l}?${d.toString()}`,o).href}catch(e){return T.error(`Failed to get private video source`,e.message),!1}}async getPrivateVideoInfo(e){try{if(typeof playerConfig>`u`)return;let t=await this.getPrivateVideoSource(playerConfig.request.files);if(!t)throw new N(`Failed to get private video source`);let{video:{title:n,duration:r},request:{text_tracks:i}}=playerConfig;return{url:`${this.SITE_ORIGIN}/${e}`,video_url:t,title:n,duration:r,subs:i}}catch(t){return T.error(`Failed to get private video info by video ID: ${e}`,t.message),!1}}async getSubsInfo(e){try{let t=new URLSearchParams({per_page:`100`,fields:`language,type,link`}).toString(),n=await(await this.fetch(`${this.API_ORIGIN}/videos/${e}/texttracks?${t}`,{headers:{Authorization:this.API_KEY}})).json();if(this.isErrorData(n))throw Error(n.developer_message??n.error);return n.data}catch(t){return T.error(`Failed to get subtitles info by video ID: ${e}`,t.message),[]}}async getVideoData(e){if(this.isPrivatePlayer()){let t=await this.getPrivateVideoInfo(e);if(!t)return;let{url:n,subs:r,video_url:i,title:a,duration:o}=t,s=r.map(e=>({language:E(e.lang),source:`vimeo`,format:`vtt`,url:new URL(e.url,this.SITE_ORIGIN).href,isAutoGenerated:e.lang.includes(`autogenerated`)})),c=s.length?[{target:`video_file_url`,targetUrl:i},{target:`subtitles_file_url`,targetUrl:s[0].url}]:null;return{...c?{url:n,translationHelp:c}:{url:i},subtitles:s,title:a,duration:o}}if(!this.extraInfo||(e.includes(`/`)&&(e=e.replace(`/`,`:`)),!await this.getViewerData()))return this.returnPublicBaseData(e);let t=await this.getVideoInfo(e);if(!t)return this.returnPublicBaseData(e);let n=(await this.getSubsInfo(e)).map(e=>({language:E(e.language),source:`vimeo`,format:`vtt`,url:e.link,isAutoGenerated:e.language.includes(`autogen`)})),{link:r,duration:i,name:a,description:o}=t;return{url:this.normalizePublicVideoUrl(r,e),title:a,description:o,subtitles:n,duration:i}}async getVideoId(e){let t=e.pathname.replace(/\/+$/,``),n=/video\/[^/]+$/.exec(t)?.[0];if(this.isPrivatePlayer())return n;if(n){let t=e.searchParams.get(`h`),r=n.replace(`video/`,``);return t?`${r}/${t}`:r}return(/channels\/[^/]+\/([^/]+)/.exec(t)?.[1]??/groups\/[^/]+\/videos\/([^/]+)/.exec(t)?.[1]??/(showcase|album)\/[^/]+\/video\/([^/]+)/.exec(t)?.[2])||/([^/]+\/)?[^/]+$/.exec(t)?.[0]}},kr=class e extends P{static getPlayer(){if(!(typeof Videoview>`u`))try{return Videoview?.getPlayerObject?.()}catch{return}}async getVideoData(t){let n=new URL(window.location.href),r=e.getPlayer();if(!r){let e=this.returnBaseData(t);return e&&{...e,url:At(t,n)}}try{let{description:e,duration:i,md_title:a}=r.vars,o=new DOMParser().parseFromString(e,`text/html`),s=Array.from(o.body.childNodes).filter(e=>e.nodeName!==`BR`).map(e=>e.textContent).join(` `),c;return Object.hasOwn(r.vars,`subs`)&&(c=r.vars.subs.map(e=>({language:E(e.lang),source:`vk`,format:`vtt`,url:e.url,isAutoGenerated:!!e.is_auto}))),{url:At(t,n),title:a,description:s,duration:i,subtitles:c}}catch(e){T.error(`Failed to get VK video data, because: ${e.message}`);let r=this.returnBaseData(t);return r&&{...r,url:At(t,n)}}}async getVideoId(e){let t=/^\/((?:video|clip)-?\d+_\d+)(?:\/)?$/.exec(e.pathname);if(t)return t[1];let n=/\/playlist\/[^/]+\/(video-?\d+_\d+)/.exec(e.pathname);if(n)return n[1];let r=e.searchParams.get(`z`);if(r)return r.split(`/`)[0];let i=e.searchParams.get(`oid`),a=e.searchParams.get(`id`);if(i&&a){let e=Math.abs(Number.parseInt(i,10));if(!Number.isNaN(e))return`video-${e}_${a}`}}},Ar=class extends P{async getVideoId(e){return/(video|embed)\/(\d+)(\/[^/]+\/)?/.exec(e.pathname)?.[0]}},jr=/^\d+:(?:[\da-f]{32}|\d{16,})$/i,Mr=/^[A-Za-z0-9]+$/,Nr=/^(?:www\.)?weibo\.com$/,Pr=/^\/newlogin\/?$/,Fr=class extends P{async getVideoId(e){if(e.hostname===`video.weibo.com`){let t=e.searchParams.get(`fid`);return!t||!jr.test(t)?void 0:`tv/show/${t}`}if(Nr.test(e.host)&&Pr.test(e.pathname)){let t=e.searchParams.get(`url`);if(t)try{let n=new URL(t,e.origin);if(n.href!==e.href){let e=await this.getVideoId(n);if(e)return e}}catch{}let n=e.searchParams.get(`layerid`);if(n&&Mr.test(n))return`0/${n}`}let t=e.pathname.replace(/\/+$/,``);if(/^\/\d+\/[A-Za-z0-9]+$/.test(t)||/^\/0\/[A-Za-z0-9]+$/.test(t)||/^\/tv\/show\/\d+:(?:[\da-f]{32}|\d{16,})$/i.test(t))return t.slice(1)}},Ir=class extends P{API_ORIGIN=`https://global.apis.naver.com/weverse/wevweb`;API_APP_ID=`be4d79eb8fc7bd008ee82c8ec4ff6fd4`;API_HMAC_KEY=`1b9cb6378d959b45714bec49971ade22e6e24e42`;HEADERS={Accept:`application/json, text/plain, */*`,Origin:`https://weverse.io`,Referer:`https://weverse.io/`};getURLData(){return{appId:this.API_APP_ID,language:`en`,os:`WEB`,platform:`WEB`,wpf:`pc`}}async createHash(e){let t=Date.now(),n=e.substring(0,Math.min(255,e.length))+t,r=await Tt(this.API_HMAC_KEY,n);if(!r)throw new N(`Failed to get weverse HMAC signature`);return{wmsgpad:t.toString(),wmd:r}}async getHashURLParams(e){let t=await this.createHash(e);return new URLSearchParams(t).toString()}async getPostPreview(e){let t=`/post/v1.0/post-${e}/preview?`+new URLSearchParams({fieldSet:`postForPreview`,...this.getURLData()}).toString();try{let e=await this.getHashURLParams(t);return await(await this.fetch(`${this.API_ORIGIN+t}&${e}`,{headers:this.HEADERS})).json()}catch(t){return T.error(`Failed to get weverse post preview by postId: ${e}`,t.message),!1}}async getVideoInKey(e){let t=`/video/v1.1/vod/${e}/inKey?`+new URLSearchParams({gcc:`RU`,...this.getURLData()}).toString();try{let e=await this.getHashURLParams(t);return await(await this.fetch(`${this.API_ORIGIN+t}&${e}`,{method:`POST`,headers:this.HEADERS})).json()}catch(t){return T.error(`Failed to get weverse InKey by videoId: ${e}`,t.message),!1}}async getVideoInfo(e,t,n){let r=Date.now();try{let i=new URLSearchParams({key:t,sid:n,nonce:r.toString(),devt:`html5_pc`,prv:`N`,aup:`N`,stpb:`N`,cpl:`en`,env:`prod`,lc:`en`,adi:JSON.stringify([{adSystem:null}]),adu:`/`}).toString();return await(await this.fetch(`https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${e}?`+i,{headers:this.HEADERS})).json()}catch(r){return T.error(`Failed to get weverse video info (infraVideoId: ${e}, inkey: ${t}, serviceId: ${n}`,r.message),!1}}extractVideoInfo(e){return e.find(e=>e.useP2P===!1&&e.source.includes(`.mp4`))}async getVideoData(e){let t=await this.getPostPreview(e);if(!t)return;let{videoId:n,serviceId:r,infraVideoId:i}=t.extension.video;if(!(n&&r&&i))return;let a=await this.getVideoInKey(n);if(!a)return;let o=await this.getVideoInfo(i,a.inKey,r);if(!o)return;let s=this.extractVideoInfo(o.videos.list);if(s)return{url:s.source,duration:s.duration}}async getVideoId(e){return/([^/]+)\/(live|media)\/([^/]+)/.exec(e.pathname)?.[3]}},Lr=class extends P{async getVideoId(e){return/\/(videos\/[^/]+-[\dA-Za-z]+)\/?$/.exec(e.pathname)?.[1]}},Rr=class extends P{async getVideoId(e){return/[^/]+\/[^/]+$/.exec(e.pathname)?.[0]}},zr=class extends P{API_ORIGIN=window.location.origin;CLIENT_PREFIX=`/client/disk`;INLINE_PREFIX=`/i/`;DISK_PREFIX=`/d/`;isErrorData(e){return Object.hasOwn(e,`error`)}async getClientVideoData(e){let t=new URL(window.location.href).searchParams.get(`idDialog`);if(!t)return;let n=document.querySelector(`#preloaded-data`);if(n)try{let{idClient:e,sk:r}=JSON.parse(n.innerText).config,i=await(await this.fetch(`${this.API_ORIGIN}/models-v2?m=mpfs/info`,{method:`POST`,body:JSON.stringify({apiMethod:`mpfs/info`,connection_id:e,requestParams:{path:t},sk:r}),headers:{"Content-Type":`application/json`}})).json();if(this.isErrorData(i))throw new N(i.error?.message??i.error?.code);if(i?.type!==`file`)throw new N(`Failed to get resource info`);let{meta:{short_url:a,video_info:o},name:s}=i;if(!o)throw new N(`There's no video open right now`);if(!a)throw new N(`Access to the video is limited`);return{url:a,title:this.clearTitle(s),duration:Math.round(o.duration/1e3)}}catch(t){T.error(`Failed to get yandex disk video data by video ID: ${e}, because ${t.message}`);return}}clearTitle(e){return e.replace(/(\.[^.]+)$/,``)}getBodyHash(e,t){let n=JSON.stringify({hash:e,sk:t});return encodeURIComponent(n)}async fetchList(e,t){let n=this.getBodyHash(e,t),r=await(await this.fetch(`${this.API_ORIGIN}/public/api/fetch-list`,{method:`POST`,body:n})).json();if(Object.hasOwn(r,`error`))throw new N(`Failed to fetch folder list`);return r.resources}async getDownloadUrl(e,t){let n=this.getBodyHash(e,t),r=await(await this.fetch(`${this.API_ORIGIN}/public/api/download-url`,{method:`POST`,body:n})).json();if(r.error)throw new N(`Failed to get download url`);return r.data.url}async getDiskVideoData(e){try{let t=document.getElementById(`store-prefetch`);if(!t)throw new N(`Failed to get prefetch data`);let n=e.split(`/`).slice(3);if(!n.length)throw new N(`Failed to find video file path`);let{resources:r,rootResourceId:i,environment:{sk:a}}=JSON.parse(t.innerText),o=r[i],s=n.length-1,c=n.filter((e,t)=>t!==s).join(`/`),l=Object.values(r);c.includes(`/`)&&(l=await this.fetchList(`${o.hash}:/${c}`,a));let u=l.find(e=>e.name===n[s]);if(!u)throw new N(`Failed to find resource`);if(u&&u.type===`dir`)throw new N(`Path is dir, but expected file`);let{meta:{short_url:d,mediatype:f,videoDuration:p},path:m,name:h}=u;if(f!==`video`)throw new N(`Resource isn't a video`);let g=this.clearTitle(h),_=Math.round(p/1e3);if(d)return{url:d,duration:_,title:g};let v=await this.getDownloadUrl(m,a);return{url:D(new URL(v)),duration:_,title:g}}catch(t){T.error(`Failed to get yandex disk video data by disk video ID: ${e}`,t.message);return}}async getVideoData(e){return e.startsWith(this.INLINE_PREFIX)||/^\/d\/([^/]+)$/.exec(e)?{url:this.service?.url+e.slice(1)}:(e=decodeURIComponent(e),e.startsWith(this.CLIENT_PREFIX)?await this.getClientVideoData(e):await this.getDiskVideoData(e))}async getVideoId(e){return e.pathname.startsWith(this.CLIENT_PREFIX)?e.pathname+e.search:/\/i\/([^/]+)/.exec(e.pathname)?.[0]||(/\/d\/([^/]+)/.exec(e.pathname)?e.pathname:void 0)}},Br=class extends P{async getVideoId(e){return/v_show\/id_[\w=]+/.exec(e.pathname)?.[0]}},F=class e extends P{static isMobile(){return/^m\.youtube\.com$/.test(window.location.hostname)}static extractVideoId(t){let n=t.hash.replace(/^#/,``);if(n){let r=n.startsWith(`!`)?n.slice(1):n,i=r;try{i=decodeURIComponent(r)}catch{}try{let n=i.startsWith(`http`)?new URL(i):new URL(i.startsWith(`/`)?i:`/${i}`,t.origin),r=e.extractVideoId(n);if(r)return r}catch{let e=/(?:^|[?&#])v=([^&#]+)/.exec(i)?.[1];if(e)return e}}return t.hostname===`youtu.be`?t.pathname.replace(/^\/+/,``).split(`/`)[0]||void 0:(/\/(?:watch|embed|shorts|live|v|e)\/([^/?#]+)/.exec(t.pathname)?.[1]??void 0)||(t.searchParams.get(`v`)??void 0)}static getPlayer(){return window.location.pathname.startsWith(`/shorts/`)&&!e.isMobile()?document.querySelector(`#shorts-player`):document.querySelector(`#movie_player`)}static getPlayerResponse(){return e.getPlayer()?.getPlayerResponse?.call(void 0)}static getPlayerData(){return e.getPlayer()?.getVideoData?.call(void 0)}static getVolume(){let t=e.getPlayer();return t?.getVolume?t.getVolume()/100:1}static setVolume(t){let n=e.getPlayer();return n?.setVolume?(n.setVolume(Math.round(t*100)),!0):!1}static isMuted(){let t=e.getPlayer();return t?.isMuted?t.isMuted():!1}static videoSeek(t,n){T.log(`videoSeek`,n),t.currentTime=(e.getPlayer()?.getProgressState()?.seekableEnd??t.currentTime)-n}static getPoToken(){let t=e.getPlayer();if(!t)return;let n=t.getAudioTrack?.call(void 0);if(!n?.captionTracks?.length)return;let r=n.captionTracks.find(e=>e.url.includes(`&pot=`));if(r)return/&pot=([^&]+)/.exec(r.url)?.[1]}static getGlobalConfig(){return typeof yt<`u`?yt?.config_:typeof ytcfg<`u`?ytcfg?.data_:void 0}static getDeviceParams(){let t=e.getGlobalConfig();if(!t)return`c=WEB`;let n=t.INNERTUBE_CONTEXT?.client,r=new URLSearchParams(t.DEVICE);return r.delete(`ceng`),r.delete(`cengver`),r.set(`c`,n?.clientName??t.INNERTUBE_CLIENT_NAME),r.set(`cver`,n?.clientVersion??t.INNERTUBE_CLIENT_VERSION),r.set(`cplayer`,`UNIPLAYER`),r.toString()}static getSubtitles(t){let n=e.getPlayerResponse()?.captions?.playerCaptionsTracklistRenderer;if(!n)return[];let r=n.captionTracks??[],i=(n.translationLanguages??[]).find(e=>e.languageCode===t),a=r.find(e=>e?.kind===`asr`)?.languageCode??`en`,o=r.reduce((e,n)=>{if(!(`languageCode`in n))return e;let r=n.languageCode?E(n.languageCode):void 0,o=n.baseUrl;if(!r||!o)return e;let s=`${o.startsWith(`http`)?o:`${window.location.origin}/${o}`}&fmt=json3`;return e.push({source:`youtube`,format:`json`,language:r,isAutoGenerated:n?.kind===`asr`,url:s}),i&&n.isTranslatable&&n.languageCode===a&&t!==r&&e.push({source:`youtube`,format:`json`,language:t,isAutoGenerated:n?.kind===`asr`,translatedFromLanguage:r,url:`${s}&tlang=${t}`}),e},[]);return T.log(`youtube subtitles:`,o),o}static getLanguage(){if(!e.isMobile()){let t=e.getPlayer()?.getAudioTrack?.call(void 0)?.getLanguageInfo();if(t&&t.id!==`und`)return E(t.id.split(`.`)[0])}let t=e.getPlayerResponse()?.captions?.playerCaptionsTracklistRenderer.captionTracks.find(e=>e.kind===`asr`&&e.languageCode);return t?E(t.languageCode):void 0}async getVideoData(t){let{title:n}=e.getPlayerData()??{},{shortDescription:r,isLive:i,title:a}=e.getPlayerResponse()?.videoDetails??{},o=e.getSubtitles(this.language),s=e.getLanguage();s&&!bn.includes(s)&&(s=void 0);let c=e.getPlayer()?.getDuration?.call(void 0)??void 0;return{url:this.service?.url+t,isStream:i,title:a,localizedTitle:n,detectedLanguage:s,description:r,subtitles:o,duration:c}}async getVideoId(t){if(t.searchParams.has(`enablejsapi`)){let n=e.getPlayer()?.getVideoUrl();t=n?new URL(n):t}return e.extractVideoId(t)}},Vr=/^\/play\/([^/?#]+)\/([^/?#]+)\/([^/?#]+)\/?$/i,Hr=class extends P{async getVideoId(e){let t=Vr.exec(e.pathname);if(!t)return;let[,n,r,i]=t;return`${n}/${r}/${i}`}},Ur={[k.mailru]:Wn,[k.weverse]:Ir,[k.weibo]:Fr,[k.kodik]:Bn,[k.patreon]:er,[k.reddit]:or,[k.bannedvideo]:fn,[k.kick]:Rn,[k.appledeveloper]:ln,[k.epicgames]:An,[k.odysee]:Xn,[k.coursehunterLike]:yn,[k.twitch]:_r,[k.sap]:dr,[k.jove]:Ln,[k.linkedin]:Vn,[k.vimeo]:Or,[k.yandexdisk]:zr,[k.vk]:kr,[k.trovo]:gr,[k.incestflix]:In,[k.porntn]:ir,[k.googledrive]:Nn,[k.bilibili]:pn,[k.xvideos]:Rr,[k.xhamster]:Lr,[k.spankbang]:fr,[k.rule34video]:cr,[k.picarto]:nr,[k.olympicsreplay]:Qn,[k.watchpornto]:Ar,[k.archive]:un,[k.dailymotion]:wn,[k.youku]:Br,[k.egghead]:kn,[k.newgrounds]:qn,[k.okru]:Zn,[k.peertube]:tr,[k.eporner]:jn,[k.bitchute]:mn,[k.rutube]:ur,[k.facebook]:Mn,[k.rumble]:lr,[k.twitter]:vr,[k.pornhub]:rr,[k.tiktok]:hr,[k.proxitok]:hr,[k.nine_gag]:Yn,[k.youtube]:F,[k.preservetube]:ar,[k.invidious]:F,[k.piped]:F,[k.zdf]:Hr,[k.dzen]:On,[k.bunnystream]:_n,[k.cloudflarestream]:vn,[k.loom]:Un,[k.rtnews]:sr,[k.bitview]:hn,[k.thisvid]:mr,[k.ign]:Pn,[k.bunkr]:gn,[k.imdb]:Fn,[k.telegram]:pr,[k.niconico]:Jn,[j.udemy]:Dr,[j.coursera]:Cn,[j.douyin]:Dn,[j.artstation]:dn,[j.kickstarter]:zn,[j.datacamp]:Tn,[j.oraclelearn]:$n,[j.deeplearningai]:En,[j.netacad]:Kn,[j.mediafile]:Gn},Wr=class{helpersData;constructor(e={}){this.helpersData=e}getHelper(e){return new Ur[e](this.helpersData)}};function Gr(e){return e in Ur}function Kr(e,t){let n=e.replace(/^\/+/,``),r=new URL(`https://vk.com/video`);r.searchParams.set(`z`,n);for(let e of[`list`,`access_key`]){let n=t.searchParams.get(e);n&&r.searchParams.set(e,n)}return r.toString()}function qr(){if(tn.exec(window.location.href))return[];let e=window.location.hostname,t=new URL(window.location.href),n=n=>n instanceof RegExp?n.test(e):typeof n==`string`?e.includes(n):typeof n==`function`?n(t):!1;return cn.filter(e=>!!e.match&&(Array.isArray(e.match)?e.match.some(n):n(e.match))&&e.host&&e.url)}async function Jr(e,t={}){let n=new URL(window.location.href),r=e.host;return Gr(r)?await new Wr(t).getHelper(r).getVideoId(n):r===k.custom?n.href:void 0}async function Yr(e,t={}){let n=new URL(window.location.href),r=await Jr(e,t);if(!r)throw new en(`Entered unsupported link: "${e.host}"`);let i=n.origin;if([k.peertube,k.coursehunterLike,k.bunnystream,k.cloudflarestream].includes(e.host)&&(e.url=i),e.rawResult)return{url:r,videoId:r,host:e.host,duration:void 0};if(!e.needExtraData)return e.host===k.vk?{url:Kr(r,n),videoId:r,host:e.host,duration:void 0}:{url:e.url+r,videoId:r,host:e.host,duration:void 0};if(!Gr(e.host))throw new en(`No helper is available for "${e.host}"`);let a=await new Wr({...t,service:e,origin:i}).getHelper(e.host).getVideoData(r);if(!a)throw new en(`Failed to get video raw url for ${e.host}`);return{...a,url:e.host===k.vk?Kr(r,n):a.url,videoId:r,host:e.host}}var Xr={version:`1.0.6`,debug:!1,fetchFn:(...e)=>{if(typeof globalThis.fetch!=`function`)throw Error(`Fetch API is not available in this environment`);return globalThis.fetch(...e)}},I={log:(...e)=>{if(Xr.debug)return console.log(`%c✦ chaimu.js v${Xr.version} ✦`,`background: #000; color: #fff; padding: 0 8px`,...e)}},Zr=[`playing`,`ratechange`,`play`,`waiting`,`stalled`,`seeking`,`pause`,`ended`,`seeked`];function Qr(){let e=window.AudioContext??window.webkitAudioContext;return e?new e:void 0}var $r=1e4,ei=class{static name=`BasePlayer`;chaimu;fetch;isBuffering=!1;_src;fetchOpts;constructor(e,t){this.chaimu=e,this._src=t,this.fetch=this.chaimu.fetchFn,this.fetchOpts=this.chaimu.fetchOpts}async init(){return this}async clear(){return this}lipSync(e=!1){return this}handleVideoEvent=e=>(I.log(`handle video ${e.type}`),this.lipSync(e.type),this);isPlaybackBlocked(){let e=this.chaimu.video;return this.isBuffering||!e||e.ended||e.seeking||e.readyState{I.log(`[AudioPlayer] idle suspend`),await this.suspendAudioContext()},$r)}cancelSuspend(){this.suspendTimer!==void 0&&(clearTimeout(this.suspendTimer),this.suspendTimer=void 0)}updateAudio(){return this.audio=new Audio(this.src),this.audio.crossOrigin=`anonymous`,this}async init(){return this.updateAudio(),this.initAudioBooster(),this}async resumeAndPlayAudio(){if(!(!this.audio||this.isPlaybackBlocked())&&(this.cancelSuspend(),!(!await this.resumeAudioContext()||this.isPlaybackBlocked())))try{await this.audio.play()}catch(e){this.handlePlaybackError(`play audio element`,e)}}lipSync(e=!1){if(I.log(`[AudioPlayer] lipsync video`,this.chaimu.video),!this.chaimu.video||(this.audio.currentTime=this.chaimu.video.currentTime,this.audio.playbackRate=this.chaimu.video.playbackRate,!e))return this;switch(e){case`play`:case`playing`:case`seeked`:return this.isBuffering=!1,this.chaimu.video.paused||this.syncPlay(),this;case`waiting`:case`stalled`:case`seeking`:return this.isBuffering=!0,this.audio.pause(),this;case`pause`:case`ended`:return this.isBuffering=!1,this.pause(),this;default:return this}}async clear(){return this.cancelSuspend(),this.audio.pause(),this.audio.src=``,this.audio.removeAttribute(`src`),this.disconnectAudioNodes(),await this.suspendAudioContext(),this}syncPlay(){return I.log(`[AudioPlayer] sync play called`),this.resumeAndPlayAudio(),this}async play(){return I.log(`[AudioPlayer] play called`),await this.resumeAndPlayAudio(),this}async pause(){return I.log(`[AudioPlayer] pause called`),this.isBuffering=!1,this.audio&&this.audio.pause(),this.scheduleSuspend(),this}set src(e){if(this._src=e,!e){this.clear();return}this.audio.src=e}get src(){return this._src}get currentSrc(){return this.audio.currentSrc}set volume(e){if(this.gainNode){this.gainNode.gain.value=e;return}this.audio.volume=e}get volume(){return this.gainNode?this.gainNode.gain.value:this.audio.volume}get playbackRate(){return this.audio.playbackRate}set playbackRate(e){this.audio.playbackRate=e}get currentTime(){return this.audio.currentTime}},ni=class extends ei{static name=`ChaimuPlayer`;audioBuffer;audioElement;mediaElementSource;gainNode;blobUrl;isClearing=!1;isInitializing=!1;clearingPromise;suspendTimer;async fetchAudio(){if(!this._src)throw Error(`No audio source provided`);if(!this.chaimu.audioContext)throw Error(`No audio context available`);I.log(`[ChaimuPlayer] Fetching audio from ${this._src}...`);let e;try{let t=await this.fetch(this._src,this.fetchOpts);if(!t.ok)throw Error(`Response status: ${t.status}`);I.log(`[ChaimuPlayer] Decoding fetched audio...`);let n=await t.arrayBuffer(),r=new Blob([n]);e=URL.createObjectURL(r),this.audioBuffer=await this.chaimu.audioContext.decodeAudioData(n),this.blobUrl&&URL.revokeObjectURL(this.blobUrl),this.blobUrl=e,e=void 0}catch(t){throw e&&URL.revokeObjectURL(e),Error(`Failed to fetch audio file, because ${t.message}`)}return this}initAudioBooster(){return this.chaimu.audioContext?(this.disconnectAudioNodes(),this.gainNode=this.chaimu.audioContext.createGain(),this):this}disconnectAudioNodes(){this.mediaElementSource&&=(this.mediaElementSource.disconnect(),void 0),this.gainNode&&=(this.gainNode.disconnect(),void 0)}scheduleSuspend(){this.cancelSuspend(),this.suspendTimer=setTimeout(async()=>{I.log(`[ChaimuPlayer] idle suspend`),await this.suspendAudioContext()},$r)}cancelSuspend(){this.suspendTimer!==void 0&&(clearTimeout(this.suspendTimer),this.suspendTimer=void 0)}async init(){if(this.isInitializing)throw Error(`Initialization already in progress`);this.isInitializing=!0;try{return await this.fetchAudio(),this.initAudioBooster(),this.createAudioElement(),this}finally{this.isInitializing=!1}}createAudioElement(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);if(!this.blobUrl)throw Error(`No blob URL available.`);let e=new Audio(this.blobUrl);e.crossOrigin=`anonymous`,`preservesPitch`in e&&(e.preservesPitch=!0,`mozPreservesPitch`in e&&(e.mozPreservesPitch=!0),`webkitPreservesPitch`in e&&(e.webkitPreservesPitch=!0)),this.audioElement=e;let t=this.gainNode;if(!t)throw Error(`Audio gain node is missing`);this.mediaElementSource=this.chaimu.audioContext.createMediaElementSource(e),this.mediaElementSource.connect(t),t.connect(this.chaimu.audioContext.destination)}lipSync(e=!1){if(I.log(`[ChaimuPlayer] lipsync video`,this.chaimu.video,this),!this.chaimu.video||!e)return this;switch(e){case`play`:case`playing`:case`ratechange`:case`seeked`:return this.isBuffering=!1,this.chaimu.video.paused||this.start(),this;case`waiting`:case`stalled`:case`seeking`:return this.isBuffering=!0,this.audioElement&&this.audioElement.pause(),this;case`pause`:case`ended`:return this.isBuffering=!1,this.pause(),this;default:return this}}async reopenCtx(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);try{this.chaimu.audioContext.state!==`closed`&&await this.chaimu.audioContext.close()}catch(e){I.log(`[ChaimuPlayer] Failed to close audio context:`,e)}return this.chaimu.audioContext=Qr(),this}async clear(){if(this.isClearing&&this.clearingPromise)return this.clearingPromise;if(!this.chaimu.audioContext)throw Error(`No audio context available`);return I.log(`clear audio context`),this.cancelSuspend(),this.isClearing=!0,this.clearingPromise=(async()=>{try{this.audioElement&&=(this.audioElement.pause(),void 0),this.blobUrl&&=(URL.revokeObjectURL(this.blobUrl),void 0);let e=this.gainNode?this.gainNode.gain.value:1;return this.disconnectAudioNodes(),await this.reopenCtx(),this.chaimu.audioContext&&(this.initAudioBooster(),this.volume=e,await this.suspendAudioContext()),this}finally{this.isClearing=!1,this.clearingPromise=void 0}})(),this.clearingPromise}async start(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);if(!this.audioElement)throw Error(`Audio element is missing`);if(this.isClearing&&this.clearingPromise&&(I.log(`The other cleaner is still running, waiting...`),await this.clearingPromise),this.cancelSuspend(),this.isPlaybackBlocked()||(I.log(`starting audio via HTMLAudioElement`),!await this.resumeAudioContext())||this.isPlaybackBlocked())return this;this.chaimu.video&&(this.audioElement.currentTime=this.chaimu.video.currentTime,this.audioElement.playbackRate=this.chaimu.video.playbackRate);try{await this.audioElement.play()}catch(e){this.handlePlaybackError(`play audio element`,e)}return this}async pause(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);return this.isBuffering=!1,this.audioElement&&this.audioElement.pause(),this.scheduleSuspend(),this}async play(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);return this.cancelSuspend(),await this.resumeAudioContext(),this}set src(e){this._src=e}get src(){return this._src}get currentSrc(){return this._src}set volume(e){this.gainNode&&(this.gainNode.gain.value=e)}get volume(){return this.gainNode?this.gainNode.gain.value:0}set playbackRate(e){this.audioElement&&(this.audioElement.playbackRate=e)}get playbackRate(){return this.audioElement?this.audioElement.playbackRate:this.chaimu.video?.playbackRate??1}get currentTime(){return this.chaimu.video?.currentTime??0}},ri=class{_debug=!1;audioContext;player;video;fetchFn;fetchOpts;constructor({url:e,video:t,debug:n=!1,fetchFn:r=Xr.fetchFn,fetchOpts:i={},preferAudio:a=!1}){this._debug=Xr.debug=n,this.fetchFn=r,this.fetchOpts=i,this.audioContext=Qr(),this.player=this.audioContext&&!a?new ni(this,e):new ti(this,e),this.video=t}async init(){await this.player.init(),this.player.addVideoEvents(),this.video.paused||this.video.ended||this.video.seeking||this.video.readyStatetypeof e==`string`&&e.startsWith(`getVideoId:`),extractVideoId:e=>e.pathname.split(`/`).at(-2)??null,responseFormatter:(e,t)=>`${typeof t==`string`?t:``}:${e}`},"https://www.dailymotion.com":{targetOrigin:`https://geo.dailymotion.com`,dataFilter:e=>typeof e==`string`&&e.startsWith(`getVideoId:`),extractVideoId:e=>/(?:^|\/)video\/([^/]+)/.exec(e.pathname)?.[1],responseFormatter:e=>`getVideoId:${e}`}}).find(([e])=>globalThis.location.origin===e)?.[1];e&&globalThis.addEventListener(`message`,t=>{try{if(t.origin!==e.targetOrigin||!e.dataFilter(t.data))return;let n=e.extractVideoId(new URL(globalThis.location.href));if(!n)return;let r=e.responseFormatter(n,t.data);t.source&&`postMessage`in t.source&&t.source.postMessage(r,e.targetOrigin)}catch(e){console.error(`Iframe communication error:`,e)}})}var ui=`api.browser.yandex.ru`,di=`media-proxy.toil.cc/v1/proxy/m3u8`,fi=`vot-new.toil-dump.workers.dev`,pi=`vot-worker.kload.workers.dev`,mi=`https://vot.toil.cc/v1`,hi=`https://translate-backend.transly.workers.dev/v2`,gi=`https://rust-server-531j.onrender.com/detect`,_i=`https://rust-server-531j.onrender.com`,vi=`https://avatars.mds.yandex.net/get-yapic`,yi=`ilyhalight/voice-over-translation`,bi=`https://raw.githubusercontent.com/${yi}`,xi=`https://github.com/${yi}`,Si=`yandexbrowser`,Ci=`yandexbrowser`,wi=[`UA`,`LV`,`LT`],Ti=1e3,Ei=`2025-05-09`,Di=[`auto`,`original`],Oi=`autoTranslate.autoSubtitles.dontTranslateLanguages.enabledDontTranslateLanguages.enabledAutoVolume.enabledSmartDucking.autoVolume.buttonPos.showVideoSlider.syncVolume.downloadWithName.sendNotifyOnComplete.subtitlesMaxLength.subtitlesSmartLayout.highlightWords.subtitlesFontSize.subtitlesFontFamily.subtitlesOpacity.subtitlesDownloadFormat.responseLanguage.responseLanguageSubtitles.defaultVolume.onlyBypassMediaCSP.newAudioPlayer.showPiPButton.translateAPIErrors.translationService.detectService.translationHotkey.subtitlesHotkey.m3u8ProxyHost.proxyWorkerHost.translateProxyEnabled.translateProxyEnabledDefault.audioBooster.useLivelyVoice.autoHideButtonDelay.useAudioDownload.compatVersion.localePhrases.localeLang.localeHash.localeVersion.localeUpdatedAt.localeLangOverride.account`.split(`.`),ki=()=>{},L={log:ki,warn:ki,error:ki};function Ai(){return navigator.language?.substring(0,2).toLowerCase()||`en`}var ji=new Set([`uk`,`be`,`bg`,`mk`,`sr`,`bs`,`hr`,`sl`,`pl`,`sk`,`cs`]);function Mi(e){return xn.includes(e)?e:ji.has(e)?`ru`:`en`}var Ni=Ai(),Pi=Mi(Ni),Fi=3e4,Ii=/\p{Cc}/gu,Li=/[\\/:*?"'<>|]+/g,Ri=/^https?:\/\//i,zi=/-{2,}/g,Bi=/^[.\s-]+|[.\s-]+$/g;function Vi(){return new Date().toISOString().slice(0,10)}function Hi(e){return e.replace(Ii,``)}function Ui(e){let t=new WeakSet;return JSON.stringify(e,(e,n)=>{if(n&&typeof n==`object`){if(t.has(n))return`[Circular]`;if(t.add(n),Array.isArray(n))return n;let e={},r=Object.keys(n).sort();for(let t of r)e[t]=n[t];return e}return n})}function Wi(e){let t=2166136261,n=0;for(;n65535?2:1}return(t>>>0).toString(36)}var Gi=()=>!!document.pictureInPictureEnabled;async function Ki(e,t){try{let n=await e.createWritable();return await n.write(t),await n.close(),!0}catch{return!1}}async function qi(e,t){let n=typeof navigator>`u`?void 0:navigator;if(!n?.share||typeof File>`u`)return`unsupported`;let r;try{r=new File([e],t,{type:e.type||`application/octet-stream`})}catch{return`unsupported`}if(typeof n.canShare==`function`&&!n.canShare({files:[r]}))return`unsupported`;try{return await n.share({files:[r],title:t}),`shared`}catch(e){return e instanceof DOMException&&e.name===`AbortError`?`shared`:`error`}}function Ji(e,t){let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,r.rel=`noopener noreferrer`,r.target=`_blank`,r.style.position=`fixed`,r.style.left=`-9999px`,r.style.top=`0`,(document.body??document.documentElement).append(r);try{return r.click(),!0}catch{return!1}finally{r.remove(),Xi(n)}}async function Yi(e,t,n={}){return n.fileHandle&&await Ki(n.fileHandle,e)?!0:n.preferShare?await qi(e,t)===`shared`:Ji(e,t)}function Xi(e,t=Fi){let n=Number.isFinite(t)&&t>=0?t:Fi;globalThis.setTimeout(()=>URL.revokeObjectURL(e),n)}function Zi(e){let t=e.trim();return t&&Hi(t).replace(Ri,``).replace(Li,`-`).replace(zi,`-`).replace(Bi,``)||Vi()}var Qi=()=>Math.floor(Date.now()/1e3),$i=e=>e?Object.fromEntries(new Headers(e)):{};function R(e,t=0,n=100){return Math.min(Math.max(e,Math.min(t,n)),Math.max(t,n))}function ea(e){let t={},n=Object.entries(e);for(;n.length;){let e=n.pop();if(!e)continue;let[r,i]=e;if(i!==void 0){if(!(typeof i==`object`&&i&&!Array.isArray(i))){t[r]=i;continue}for(let[e,t]of Object.entries(i))n.push([`${r}.${e}`,t])}}return t}var ta=7200*1e3,na=`x-vot-cache-created-at`,ra=`x-vot-cache-key`,ia=`vot-http-cache-v1`,aa=500,oa=`VOTSession`,sa={translation:`translationExpiresAt`,subtitles:`subtitlesExpiresAt`};function ca(){return Math.floor(Date.now()/1e3)}function la(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.expires==`number`&&Number.isFinite(t.expires)&&typeof t.timestamp==`number`&&Number.isFinite(t.timestamp)&&typeof t.uuid==`string`&&t.uuid.length>0&&typeof t.secretKey==`string`&&t.secretKey.length>0}function ua(e){if(!e||typeof e!=`object`)return{};let t=ca(),n=Object.entries(e).flatMap(([e,n])=>!la(n)||n.timestamp+n.expires<=t?[]:[[e,n]]);return Object.fromEntries(n)}function da(e){return Object.keys(e).length>0}var fa=class{constructor(e=B){this.storage=e}getStorageKey(){return oa}async restore(e,t={}){let n=this.getStorageKey(),r=await this.storage.getRaw(n),i=ua(r);return da(i)?{...t,...i}:(r!==void 0&&await this.storage.deleteRaw(n),t)}async persist(e,t){let n=this.getStorageKey(),r=ua(t);if(!da(r)){await this.storage.deleteRaw(n);return}await this.storage.setRaw(n,r)}},pa=class{cache=new Map;clear(){this.cache.clear()}getTranslation(e){return this.getValue(e,`translation`)}setTranslation(e,t){this.setValue(e,`translation`,t)}getSubtitles(e){return this.getValue(e,`subtitles`)}setSubtitles(e,t){this.setValue(e,`subtitles`,t)}deleteSubtitles(e){this.deleteValue(e,`subtitles`)}getValue(e,t){let n=Date.now(),r=this.cache.get(e);if(!r)return;let i=sa[t],a=r[i];if(a!==void 0&&a<=n){r[t]=void 0,r[i]=void 0,this.evictIfEmpty(e,r);return}return r[t]}setValue(e,t,n){let r=Date.now(),i=this.getOrCreateEntry(e),a=r+ta,o=sa[t];i[t]=n,i[o]=a}deleteValue(e,t){let n=this.cache.get(e);if(!n)return;let r=sa[t];n[t]=void 0,n[r]=void 0,this.evictIfEmpty(e,n)}evictIfEmpty(e,t){t.translation===void 0&&t.subtitles===void 0&&this.cache.delete(e)}getOrCreateEntry(e){let t=this.cache.get(e);if(t)return t;let n={};return this.cache.set(e,n),n}},ma=new class{memoryCache=new Map;inFlightRequests=new Map;async execute(e,t,n){if(!t||t.ttlMs<=0)return n();let r=t.key??this.buildDefaultCacheKey(e);if(!r)return n();let i=this.normalizeMethod(e.method),a=t.ttlMs,o=t.cacheName||ia,s=t.useMemory!==!1,c=t.useCacheApi!==!1&&i===`GET`&&this.supportsCacheApi(),l=c?Wi(r):``,u=t.dedupe!==!1,d=t.allowStaleOnError!==!1,f=Date.now(),p=await this.readCachedResponse({key:r,nowMs:f,useMemory:s,useCacheApi:c,cacheName:o,url:e.url,cacheApiKey:l,ttlMs:a,allowStaleOnError:d});if(p.fresh)return p.fresh;if(!u)return await this.runNetworkRequestWithFallback({key:r,cacheName:o,url:e.url,cacheApiKey:l,ttlMs:a,useMemory:s,useCacheApi:c},n,d?p.stale:void 0);let m=this.inFlightRequests.get(r);if(m!==void 0)return(await m).clone();let h=this.runNetworkRequestWithFallback({key:r,cacheName:o,url:e.url,cacheApiKey:l,ttlMs:a,useMemory:s,useCacheApi:c},n,d?p.stale?.clone():void 0);this.inFlightRequests.set(r,h);try{return(await h).clone()}finally{this.inFlightRequests.delete(r)}}async readCachedResponse({key:e,nowMs:t,useMemory:n,useCacheApi:r,cacheName:i,url:a,cacheApiKey:o,ttlMs:s,allowStaleOnError:c}){let l;if(n){let n=this.readMemoryCache(e,t);if(n.fresh)return{fresh:n.fresh};l=n.stale}if(!r)return{stale:l};let u=await this.readCacheApi(i,a,o,s,t,c);return u.fresh?(n&&this.writeMemoryCache(e,u.fresh.clone(),u.expiresAt??t+s),{fresh:u.fresh}):{stale:l??u.stale}}async runNetworkRequestWithFallback(e,t,n){try{return await this.runNetworkRequest(e,t)}catch(e){if(n)return n;throw e}}async runNetworkRequest({key:e,cacheName:t,url:n,cacheApiKey:r,ttlMs:i,useMemory:a,useCacheApi:o},s){let c=await s();if(!c.ok)return c;let l=Date.now(),u=this.computeExpiresAt(l,i);if(a&&this.writeMemoryCache(e,c.clone(),u),o){let e=this.toStorableResponse(c.clone(),l);await this.writeCacheApi(t,n,r,e)}return c}computeExpiresAt(e,t){return!Number.isFinite(t)||t<=0?e:t>=2**53-1-e?2**53-1:e+t}normalizeMethod(e){return(e||`GET`).toUpperCase()}resolveBodyKey(e){if(e==null)return``;if(typeof e==`string`)return e;if(e instanceof URLSearchParams)return e.toString()}buildDefaultCacheKey(e){let t=this.normalizeMethod(e.method);if(t===`GET`)return`${t}:${e.url}`;let n=this.resolveBodyKey(e.body);if(n!==void 0)return`${t}:${e.url}#${Wi(n)}`}supportsCacheApi(){return typeof caches<`u`&&typeof caches.open==`function`}readCreatedAtMs(e){let t=e.headers.get(na);if(!t)return null;let n=Number(t);return Number.isFinite(n)?n:null}ensureVaryByCacheKey(e){let t=e.get(`vary`);if(!t){e.set(`vary`,ra);return}let n=new Set(t.split(`,`).map(e=>e.trim().toLowerCase()));!n.has(`*`)&&!n.has(ra)&&e.set(`vary`,`${t}, ${ra}`)}toStorableResponse(e,t){let n=new Headers(e.headers);return n.set(na,String(t)),this.ensureVaryByCacheKey(n),new Response(e.body,{status:e.status,statusText:e.statusText,headers:n})}readMemoryCache(e,t){let n=this.memoryCache.get(e);return n?n.expiresAt>t?(this.touchMemoryCache(e,n),{fresh:n.response.clone(),expiresAt:n.expiresAt}):(this.memoryCache.delete(e),{stale:n.response.clone(),expiresAt:n.expiresAt}):{}}touchMemoryCache(e,t){this.memoryCache.delete(e),this.memoryCache.set(e,t)}trimMemoryCache(){for(;this.memoryCache.size>aa;){let e=this.memoryCache.keys().next().value;if(typeof e!=`string`)break;this.memoryCache.delete(e)}}writeMemoryCache(e,t,n){this.memoryCache.has(e)&&this.memoryCache.delete(e),this.memoryCache.set(e,{response:t,expiresAt:n}),this.trimMemoryCache()}async readCacheApi(e,t,n,r,i,a){try{let o=new Request(t,{method:`GET`,headers:{[ra]:n}}),s=await caches.open(e),c=await s.match(o);if(!c)return{};let l=this.readCreatedAtMs(c);if(l===null)return await s.delete(o),{};let u=this.computeExpiresAt(l,r);if(u>i)return{fresh:c.clone(),expiresAt:u};if(!a)return await s.delete(o),{};let d=c.clone();return await s.delete(o),{stale:d,expiresAt:u}}catch{return{}}}async writeCacheApi(e,t,n,r){try{let i=new Request(t,{method:`GET`,headers:{[ra]:n}});await(await caches.open(e)).put(i,r)}catch{}}};async function ha(e,t,n){return ma.execute(e,t,n)}function ga(e){let t=new WeakSet;try{return JSON.stringify(e,(e,n)=>typeof n!=`object`||!n?n:t.has(n)?`[Circular]`:(t.add(n),n))??null}catch{return null}}function _a(e){let t=[e?.data?.message,e?.error?.message,e?.message];for(let e of t)if(typeof e==`string`&&e)return e;return null}function va(e,t){let n=_a(e);if(n)return n;let r=ga(e);if(r&&r!==`{}`)return r;let i=e.constructor?.name;return i?`[${i}]`:t}function ya(e,t){return typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`?`${e}`:typeof e==`symbol`?e.description?`Symbol(${e.description})`:`Symbol`:typeof e==`function`?e.name?`[Function ${e.name}]`:`[Function]`:t}function ba(e,t=`Unknown error`){return e instanceof Error?e.message||t:typeof e==`string`?e||t:e==null?t:typeof e==`object`?va(e,t):ya(e,t)}function xa(e){return ba(e,``)}function Sa(e){let t=e;return typeof DOMException<`u`&&t instanceof DOMException&&t.name===`AbortError`||t instanceof Error&&t.name===`AbortError`||t?.message===`AbortError`}function Ca(e=`Aborted`){try{return new DOMException(e,`AbortError`)}catch{let t=Error(e);return t.name=`AbortError`,t}}var wa=new AbortController().signal;function Ta(e){let t=e.throwIfAborted;if(typeof t==`function`)try{t.call(e);return}catch(t){throw e.aborted||Sa(t)?Ca():t instanceof Error?t:Error(String(t))}if(e.aborted)throw Ca()}function Ea(e,t){if(!(Number.isFinite(e)&&e>0))return{signal:t??wa,cleanup:()=>{}};let n=new AbortController,r,i=()=>{r!==void 0&&(clearTimeout(r),r=void 0),n.abort(t?.reason)};return t&&(t.addEventListener(`abort`,i,{once:!0}),t.aborted&&i()),n.signal.aborted||(r=setTimeout(()=>{n.abort(Ca(`Timeout`)),r=void 0},e)),{signal:n.signal,cleanup:()=>{r!==void 0&&(clearTimeout(r),r=void 0),t?.removeEventListener(`abort`,i)}}}var Da=`api.browser.yandex.ru`,Oa=`googlevideo.com`,ka=/^([\w-]+):\s*(.+)$/,Aa=/^[a-zA-Z][a-zA-Z\d+.-]*:/,ja=typeof GM_info>`u`?void 0:GM_info?.scriptHandler;function Ma(){let e=typeof GM_xmlhttpRequest>`u`?globalThis.GM_xmlhttpRequest:GM_xmlhttpRequest;return typeof e==`function`?e:void 0}function Na(){let e=typeof GM>`u`?globalThis.GM:GM,t=e?.xmlHttpRequest??e?.xmlhttpRequest;return typeof t==`function`?t.bind(e):void 0}function Pa(){return!!(Ma()||Na())}var Fa=!(typeof IS_EXTENSION<`u`&&IS_EXTENSION)&&!!ja&&!Pa(),Ia=typeof GM<`u`||globalThis.GM!==void 0,La=Pa();function Ra(e){let t=e.trim();try{return new URL(t).hostname.toLowerCase()}catch{if(!Aa.test(t))try{return new URL(`https://${t}`).hostname.toLowerCase()}catch{}return}}function za(e,t){return e===t||e.endsWith(`.${t}`)}function Ba(e,t,n=!1){if(n)return!0;if(!e){let e=t.toLowerCase();return e.includes(Da)||e.includes(Oa)}return za(e,Da)||za(e,Oa)}function Va(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function Ha(e,t){return t?t.toUpperCase():e instanceof Request?(e.method||`GET`).toUpperCase():`GET`}function Ua(e){return typeof e!=`string`||e.length===0?{}:e.split(/\r?\n/).reduce((e,t)=>{let n=ka.exec(t);if(!n)return e;let[,r,i]=n;return e[r]=i,e},{})}function Wa(e){let t=e;return typeof t?.error==`string`?t.error:typeof t?.statusText==`string`?t.statusText:xa(e)||`Unknown error`}async function Ga(e,t,n){let r=$i(n.headers),i=Ma(),a=Na();if(i)return await new Promise((a,o)=>{let s=!1,c,l=()=>{c&&n.signal?.removeEventListener(`abort`,c)},u=e=>{s||(s=!0,l(),o(e))},d=i({method:n.method||`GET`,url:e,responseType:`blob`,data:n.body,timeout:t,headers:r,onload:t=>{if(s)return;s=!0,l();let n=Ua(t.responseHeaders),r=new Response(t.response,{status:t.status,statusText:typeof t.statusText==`string`?t.statusText:``,headers:n});Object.defineProperty(r,`url`,{value:t.finalUrl??e}),a(r)},ontimeout:()=>u(Error(`Timeout`)),onerror:e=>u(Error(Wa(e))),onabort:()=>u(Ca())});if(c=()=>{try{d?.abort?.()}catch{}u(Ca())},n.signal&&(n.signal.addEventListener(`abort`,c,{once:!0}),n.signal.aborted)){c();return}});if(!a)throw TypeError(`GM_xmlhttpRequest is not available`);let o=a({method:n.method||`GET`,url:e,responseType:`blob`,data:n.body,timeout:t,headers:r}),s;try{let t=new Promise((e,t)=>{n.signal&&(s=()=>{try{o.abort?.()}catch{}t(Ca())},n.signal.addEventListener(`abort`,s,{once:!0}),n.signal.aborted&&s())}),r=await Promise.race([o,t]),i=Ua(r.responseHeaders),a=new Response(r.response,{status:r.status,statusText:typeof r.statusText==`string`?r.statusText:``,headers:i});return Object.defineProperty(a,`url`,{value:r.finalUrl??e}),a}finally{s&&n.signal?.removeEventListener(`abort`,s)}}async function z(e,t={}){let{timeout:n=15e3,forceGmXhr:r=!1,responseCache:i,...a}=t,o=Va(e),s=Ra(o),c=Ha(e,a.method),l=async()=>{if(Ba(s,o,r))return L.log(`GM_fetch: routing request via GM_xmlhttpRequest`,{host:s??`unknown`,reason:r?`forced`:`host-policy`,url:o}),await Ga(o,n,a);let{signal:t,cleanup:i}=Ea(n,a.signal);try{return await fetch(e,{...a,signal:t})}catch(e){if(t.aborted||Sa(e))throw e;return L.log(`GM_fetch preventing CORS by GM_xmlhttpRequest`,xa(e)||`Unknown error`),await Ga(o,n,a)}finally{i()}};return i?await ha({url:o,method:c,body:a.body},i,l):await l()}var Ka=Object.entries({numToBool:[[`autoTranslate`],[`dontTranslateYourLang`,`enabledDontTranslateLanguages`],[`autoSetVolumeYandexStyle`,`enabledAutoVolume`],[`showVideoSlider`],[`syncVolume`],[`downloadWithName`],[`sendNotifyOnComplete`],[`highlightWords`],[`onlyBypassMediaCSP`],[`newAudioPlayer`],[`showPiPButton`],[`translateAPIErrors`],[`audioBooster`],[`useNewModel`,`useLivelyVoice`]],number:[[`autoVolume`]],array:[[`dontTranslateLanguage`,`dontTranslateLanguages`]],string:[[`hotkeyButton`,`translationHotkey`],[`locale-lang-override`,`localeLangOverride`],[`locale-lang`,`localeLang`]]}).flatMap(([e,t])=>t.map(([t,n])=>({category:e,oldKey:t,newKey:n??t,shouldDeleteOldKey:!!n}))),qa=new Map(Ka.map(e=>[e.oldKey,e])),Ja=Array.from(new Set(Ka.map(e=>e.oldKey)));function Ya(e){let t={};for(let n of e)t[n]=void 0;return t}function Xa(e,t){switch(e){case`numToBool`:case`number`:return typeof t==`number`;case`array`:return Array.isArray(t);case`string`:return typeof t==`string`||t===null;default:return!1}}function Za(e,t){switch(e){case`string`:case`array`:case`number`:return t;default:return!!t}}function Qa(e,t){let n=Za(e.category,t);return e.oldKey===`autoVolume`&&typeof t==`number`&&t<1&&(n=Math.round(t*100)),n}function $a(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((e,n)=>Object.is(e,t[n])):Object.is(e,t)}function eo(e){if(e!==null)try{return JSON.parse(e)}catch{return}}async function to(e){if(e.compatVersion===`2025-05-09`)return e;let t=new Set([...Object.keys(e),...Ja]),n=await B.getValues(Ya(t)),r={...e},i=[],a=[];for(let[e,t]of Object.entries(n)){if(t===void 0)continue;let o=qa.get(e);if(!o||!Xa(o.category,t))continue;let s=Qa(o,t);r[o.newKey]=s;let c=n[o.newKey];(o.shouldDeleteOldKey||!$a(c,s))&&i.push(B.set(o.newKey,s)),o.shouldDeleteOldKey&&a.push(B.delete(o.oldKey))}return await Promise.all([...i,...a]),{...r,compatVersion:Ei}}var no=class{support=null;localStorageListeners=new Map;shouldUseSyntheticListeners(e){return!e.promiseAddValueChangeListener&&!e.legacyAddValueChangeListener}getGMRuntime(){return typeof GM<`u`?GM:globalThis.GM}resolveSupport(){if(this.support)return this.support;let e=this.getGMRuntime(),t={legacyGet:typeof GM_getValue==`function`,legacySet:typeof GM_setValue==`function`,legacyDelete:typeof GM_deleteValue==`function`,legacyList:typeof GM_listValues==`function`,legacyAddValueChangeListener:typeof globalThis.GM_addValueChangeListener==`function`,legacyRemoveValueChangeListener:typeof globalThis.GM_removeValueChangeListener==`function`,promiseGet:Ia&&typeof e?.getValue==`function`,promiseGetValues:Ia&&typeof e?.getValues==`function`,promiseSet:Ia&&typeof e?.setValue==`function`,promiseDelete:Ia&&typeof e?.deleteValue==`function`,promiseList:Ia&&typeof e?.listValues==`function`,promiseAddValueChangeListener:Ia&&typeof e?.addValueChangeListener==`function`,promiseRemoveValueChangeListener:Ia&&typeof e?.removeValueChangeListener==`function`};return this.support=t,L.log(`[VOT Storage] GM Promises: ${t.promiseGet} | GM legacy: ${t.legacyGet}`),t}get isSupportOnlyLS(){let e=this.resolveSupport();return!e.legacyGet&&!e.legacySet&&!e.legacyDelete&&!e.legacyList&&!e.promiseGet&&!e.promiseGetValues&&!e.promiseSet&&!e.promiseDelete&&!e.promiseList}syncGetByName(e,t,n){if(n.legacyGet)return GM_getValue(e,t);let r=globalThis.localStorage.getItem(e);if(r===null)return t;try{return JSON.parse(r)}catch{return t}}async getRaw(e,t){let n=this.resolveSupport();return n.promiseGet&&GM.getValue?await GM.getValue(e,t):this.syncGetByName(e,t,n)}async get(e,t){return this.getRaw(e,t)}async getValues(e){let t=this.resolveSupport();if(t.promiseGetValues&&GM.getValues)return await GM.getValues(e);let n=Object.entries(e);if(t.promiseGet&&GM.getValue){let e=await Promise.all(n.map(async([e,t])=>[e,await GM.getValue(e,t)]));return Object.fromEntries(e)}return Object.fromEntries(n.map(([e,n])=>[e,this.syncGetByName(e,n,t)]))}syncSetByName(e,t,n){return n.legacySet?GM_setValue(e,t):globalThis.localStorage.setItem(e,JSON.stringify(t))}async setRaw(e,t){let n=this.resolveSupport(),r=e,i=this.shouldUseSyntheticListeners(n),a=i?await this.getRaw(e):void 0;if(n.promiseSet&&GM.setValue){await GM.setValue(e,t),i&&this.notifyLocalStorageListeners(r,a,t,!1);return}let o=this.syncSetByName(e,t,n);return this.notifyLocalStorageListeners(r,a,t,!1),o}async set(e,t){return this.setRaw(e,t)}syncDeleteByName(e,t){return t.legacyDelete?GM_deleteValue(e):globalThis.localStorage.removeItem(e)}async deleteRaw(e){let t=this.resolveSupport(),n=e,r=this.shouldUseSyntheticListeners(t),i=r?await this.getRaw(e):void 0;if(t.promiseDelete&&GM.deleteValue){await GM.deleteValue(e),r&&this.notifyLocalStorageListeners(n,i,void 0,!1);return}let a=this.syncDeleteByName(e,t);return this.notifyLocalStorageListeners(n,i,void 0,!1),a}async delete(e){return this.deleteRaw(e)}addValueChangeListener(e,t){let n=this.resolveSupport(),r=this.getGMRuntime();if(n.promiseAddValueChangeListener){let i=r?.addValueChangeListener,a=n.promiseRemoveValueChangeListener?r?.removeValueChangeListener:void 0;if(typeof i==`function`){let n=i(e,this.createTypedListener(t));return()=>{typeof a==`function`&&a(n)}}}if(n.legacyAddValueChangeListener){let r=globalThis.GM_addValueChangeListener,i=n.legacyRemoveValueChangeListener?globalThis.GM_removeValueChangeListener:void 0;if(typeof r==`function`){let n=r(e,this.createTypedListener(t));return()=>{typeof i==`function`&&i(n)}}}let i=this.getLocalStorageListeners(e),a=t;i.add(a);let o=t=>{t.storageArea!==globalThis.localStorage||t.key!==e||a(e,eo(t.oldValue),eo(t.newValue),!0)};return globalThis.addEventListener(`storage`,o),()=>{i.delete(a),i.size===0&&this.localStorageListeners.delete(e),globalThis.removeEventListener(`storage`,o)}}createTypedListener(e){return(t,n,r,i)=>{e(t,n,r,i)}}getLocalStorageListeners(e){let t=this.localStorageListeners.get(e);if(t)return t;let n=new Set;return this.localStorageListeners.set(e,n),n}notifyLocalStorageListeners(e,t,n,r){let i=this.localStorageListeners.get(e);if(!(!i||i.size===0))for(let a of i)a(e,t,n,r)}syncList(e){return e.legacyList?GM_listValues():Oi}async list(){let e=this.resolveSupport();return e.promiseList&&GM.listValues?await GM.listValues():this.syncList(e)}},ro=`__VOT_STORAGE_SINGLETON__`,B=(()=>{let e=globalThis,t=e[ro];if(t instanceof no)return t;let n=new no;return e[ro]=n,n})(),io=`vot-auth`,ao=`account-updated`;function oo(){return{source:io,type:ao}}function so(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.source===`vot-auth`&&t.type===`account-updated`}function co(e=globalThis.opener){!e||typeof e.postMessage!=`function`||e.postMessage(oo(),`*`)}function lo(){let e=globalThis._userData;if(!e||typeof e!=`object`)return null;let t=e;return typeof t.avatar_id!=`string`||typeof t.username!=`string`||t.avatar_id.length===0||t.username.length===0?null:{avatar_id:t.avatar_id,username:t.username}}async function uo(){let{access_token:e,expires_in:t}=Object.fromEntries(new URLSearchParams(globalThis.location.hash.slice(1)));if(!e||!t)throw Error(`[VOT] Invalid token response`);let n=Number.parseInt(t,10);if(Number.isNaN(n))throw TypeError(`[VOT] Invalid expires_in value`);await B.set(`account`,{token:e,expires:Date.now()+n*1e3,username:void 0,avatarId:void 0}),co()}async function fo(){let e=lo();if(!e)throw Error(`[VOT] Invalid user data`);let{avatar_id:t,username:n}=e,r=await B.get(`account`);if(!r)throw Error(`[VOT] No account data found`);await B.set(`account`,{...r,username:n,avatarId:t}),co()}async function po(){if(globalThis.location.pathname===`/auth/callback`)return uo();if(globalThis.location.pathname===`/my/profile`)return fo()}var mo={recommended:`recommended`,translateVideo:`Translate video`,disableTranslate:`Turn off`,translationSettings:`Translation settings`,subtitlesSettings:`Subtitles settings`,subtitlesSmartLayout:`Smart subtitle layout`,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`,requestTranslationFailed:`Failed to request video translation`,audioNotReceived:`Audio link not received`,VOTFailedDownloadAudio:`Failed to download audio`,audioFormatNotSupported:`The audio format is not supported`,VOTAutoTranslate:`Translate on open`,VOTAutoSubtitles:`Subtitles on open`,VOTDontTranslateYourLang:`Don't 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`,VOTDisableFromYourLang:`You have disabled the translation of the video in your language`,VOTVideoIsTooLong:`Video is too long`,VOTNoVideoIDFound:`No video ID found`,VOTSubtitles:`Subtitles`,VOTSubtitlesDisabled:`Disabled`,VOTDefaultSubtitlesLanguage:`Default subtitle language`,VOTOriginalVideoLanguage:`Original video language`,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`},streamNoConnectionToServer:`There is no connection to the server`,searchField:`Search...`,VOTTranslateAPIErrors:`Translate errors from the API`,VOTDetectService:`Language detection service`,VOTProxyWorkerHost:`Enter the proxy worker address`,VOTM3u8ProxyHost:`Enter the address of the m3u8 proxy worker`,proxySettings:`Proxy Settings`,translationTakeApproximatelyMinute2:`The translation will take approximately {0} minutes`,VOTAudioBooster:`Extended translation volume increase`,VOTSubtitlesDesign:`Subtitles design`,VOTSubtitlesFont:`Subtitle font`,VOTSubtitlesFontSize:`Font size of subtitles`,VOTSubtitlesOpacity:`Transparency of the subtitle background`,VOTSubtitlesDownloadFormat:`The format for downloading subtitles`,VOTDownloadWithName:`Download files with the video name`,VOTUpdateLocaleFiles:`Update localization files`,VOTLocaleHash:`Locale hash`,VOTUpdatedAt:`Updated at`,VOTNeedWebAudioAPI:`To enable this, you must have a Web Audio API`,VOTMediaCSPEnabledOnSite:`Media CSP is enabled on this site`,VOTOnlyBypassMediaCSP:`Use it only for bypassing Media CSP`,VOTNewAudioPlayer:`Use the new audio player`,VOTUseNewModel:`Use an experimental variation of Yandex voices for some videos`,TranslationDelayed:`The translation is slightly delayed`,VOTTranslationCompletedNotify:`The translation on the {0} has been completed!`,VOTSendNotifyOnComplete:`Send a notification that the video has been translated`,VOTBugReport:`Report a bug`,VOTTranslateProxyDisabled:`Disabled`,VOTTranslateProxyEnabled:`Enabled`,VOTTranslateProxyEverything:`Proxy everything`,VOTTranslateProxyStatus:`Proxying mode`,VOTTranslatedBy:`Translated by {0}`,VOTStreamNotAvailable:`Translate stream isn't available`,VOTTranslationTextService:`Text translation service`,VOTNotAffectToVoice:`Doesn't affect the translation of text in voice over`,DontTranslateSelectedLanguages:`Don't translate from selected languages`,showVideoVolumeSlider:`Display the video volume slider`,hotkeysSettings:`Hotkeys settings`,None:`None`,VOTUseLivelyVoice:`Use lively voices. Speakers sound like native Russians.`,miscSettings:`Misc settings`,services:{yandexbrowser:`Yandex Browser`,msedge:`Microsoft Edge`,"rust-server":`Rust Server`},aboutExtension:`About extension`,appearance:`Appearance`,buttonPosition:`Button position in the player`,position:{left:`Left`,right:`Right`,top:`Top`,default:`Default`},secs:`secs`,autoHideButtonDelay:`Delay before hiding the translate button`,notFound:`not found`,minButtonPositionContainer:`The button position only changes in players larger than 600 pixels.`,VOTTranslateProxyStatusDefault:`Completely disabling proxying in your country may break the extension`,PressTheKeyCombination:`Press the key combination...`,VOTUseAudioDownload:`Use audio download`,VOTUseAudioDownloadWarning:`Disabling audio downloads may affect the functionality of the extension`,VOTAccountRequired:`You need to log in to use this feature`,VOTMyAccount:`My account`,VOTLogin:`Login`,VOTLogout:`Logout`,VOTRefresh:`Refresh`,VOTYandexToken:`Enter the Yandex OAuth Token`,VOTYandexTokenInfo:`You can manually set the account token in this field. Please note that we don't check its validity before sending a translate request`,VOTLoginViaToken:`Login via token`,smartDucking:`Adaptive volume`},ho=[`localePhrases`,`localeLang`,`localeHash`,`localeVersion`,`localeUpdatedAt`,`localeLangOverride`],go=ea(mo),_o=`master`,vo=(()=>{let e=Array.isArray(`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`.split(`.`))?`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`.split(`.`):[`en`];return e.includes(`auto`)?e:[`auto`,...e]})();function yo(e,t){return e||t||`unknown`}function bo(){return yo(`1.11.4`,typeof GM_info<`u`?String(GM_info?.script?.version||``):``)}var V=new class{lang;locale;defaultLocale=go;localesUrl=`${bi}/${_o}/src/localization/locales`;hashesUrl=`${bi}/${_o}/src/localization/hashes.json`;warnedMissingKeys=new Set;_langOverride=`auto`;constructor(){this.lang=this.getLang(),this.locale={}}async init(){let[e,t]=await Promise.all([B.get(`localeLangOverride`,`auto`),B.get(`localePhrases`,``)]);return this._langOverride=e,this.lang=this.getLang(),this.setLocaleFromJsonString(t),this}get langOverride(){return this._langOverride}getLang(){return this.langOverride===`auto`?Ni:this.langOverride}getAvailableLangs(){return[...vo]}async reset(){return await Promise.all(ho.map(e=>B.delete(e))),this}buildUrl(e,t=``,n=!1){return`${e}${t}${n?`?timestamp=${Qi()}`:``}`}async changeLang(e){return this.langOverride===e?!1:(await B.set(`localeLangOverride`,e),this._langOverride=e,this.lang=this.getLang(),await this.update(!0),!0)}async checkUpdates(e=!1){L.log(`Check locale updates...`);try{let t=await z(this.buildUrl(this.hashesUrl,``,e));if(!t.ok)throw t.status;let n=await t.json();if(!n||typeof n!=`object`)throw Error(`Invalid locale hashes payload`);let r=n[this.lang];return typeof r!=`string`||!r||await B.get(`localeHash`,``)===r?!1:r}catch(e){return console.error(`[VOT] [localizationProvider] Failed to get locales hash:`,e),null}}async update(e=!1){let t=bo(),n=await B.get(`localeVersion`,``),r=await this.checkUpdates(e);if(r===null)return this;if(!r)return n!==t&&await B.set(`localeVersion`,t),this;let i=Qi();L.log(`Updating locale...`);try{let n=await z(this.buildUrl(this.localesUrl,`/${this.lang}.json`,e));if(!n.ok)throw n.status;let a=await n.text();this.setLocaleFromJsonString(a),await Promise.all([B.set(`localePhrases`,a),B.set(`localeHash`,r),B.set(`localeLang`,this.lang),B.set(`localeVersion`,t),B.set(`localeUpdatedAt`,i)])}catch(e){console.error(`[VOT] [localizationProvider] Failed to get locale:`,e),this.setLocaleFromJsonString(await B.get(`localePhrases`,``))}return this}setLocaleFromJsonString(e){let t=e.trim();if(!t)return this.locale={},this.warnedMissingKeys.clear(),this;try{let e=JSON.parse(t);if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Locale payload should be a JSON object`);this.locale=ea(e)}catch(e){console.error(`[VOT] [localizationProvider]`,e),this.locale={}}return this.warnedMissingKeys.clear(),this}getFromLocale(e,t,n=`locale`){return e[t]??this.warnMissingKey(e,t,n)}warnMissingKey(e,t,n){let r=`${n}:${t}`;this.warnedMissingKeys.has(r)||(this.warnedMissingKeys.add(r),console.warn(`[VOT] [localizationProvider] locale`,e,`doesn't contain key`,t))}getDefault(e){return this.getFromLocale(this.defaultLocale,e,`default`)??e}get(e){return this.getFromLocale(this.locale,e)??this.getDefault(e)}getLangLabel(e){let t=`langs.${e}`;if(t in this.defaultLocale){let e=this.get(t);if(e)return e}return e.toUpperCase()}},xo=null;function So(){return xo??=V.init(),xo}var Co=()=>globalThis.self!==globalThis.top,wo=!1,To=null;async function Eo(e,t){if(!wo){if(To!==null){await To;return}To=(async()=>{if(t(`Activating runtime`,{reason:e}),globalThis.location.origin===`https://rust-server-531j.onrender.com`){await po(),wo=!0;return}await So(),Co()||await V.update(),L.log(`Selected menu language: ${V.lang}`),wo=!0})();try{await To}finally{To=null}}}var Do=new WeakSet;function Oo(e){let{videoObserver:t,videosWrappers:n,ensureRuntimeActivated:r,getServicesCached:i,findContainer:a,createVideoHandler:o}=e;if(Do.has(t))return;Do.add(t);let s=new WeakSet,c=new WeakMap,l=new WeakMap,u=new WeakMap,d=e=>{let t=l.get(e);return t&&c.get(t)===e&&c.delete(t),l.delete(e),t??void 0},f=e=>{e&&u.delete(e)},p=async(e,t)=>{let r=n.get(e);if(r)try{await r.release()}catch(e){console.error(`[VOT] Failed to release videoHandler (${t})`,e)}finally{n.delete(e)}},m=e=>{for(let t of i()){let n=a(t,e);if(n)return{site:t,container:n}}return null},h=e=>{let t=String(e.host);return t===`peertube`||t===`directlink`?{...e,url:globalThis.location.origin}:e},g=async e=>{if(!e)return;let t=u.get(e);t&&(u.delete(e),!(!t.isConnected||n.has(t)||s.has(t))&&await _(t))},_=async e=>{if(!(n.has(e)||s.has(e))){s.add(e);try{try{await r(`video-detected`)}catch(e){console.error(`[VOT] Failed to activate runtime`,e);return}let t=m(e);if(!t)return;let{site:i,container:a}=t,s=c.get(a);if(s&&s!==e){if(s.isConnected){u.set(a,e);return}await p(s,`stale container`),d(s)}let _=o(e,a,h(i));n.set(e,_),l.set(e,a),c.set(a,e);try{if(await _.init(),n.get(e)!==_)return;try{await _.setCanPlay()}catch(e){console.error(`[VOT] Failed to get video data`,e)}}catch(t){if(n.get(e)===_){await p(e,`init failed`);let t=d(e);f(t),await g(t)}console.error(`[VOT] Failed to initialize videoHandler`,t)}}finally{s.delete(e)}}};t.onVideoAdded.addListener(_),t.onVideoRemoved.addListener(async e=>{let t=d(e);await p(e,`video removed`),s.delete(e),t&&u.get(t)===e&&f(t),await g(t)})}function ko(e){return e.isIframe?e.href===`about:blank`||e.href.startsWith(`about:srcdoc`)||e.origin===`null`:!1}function Ao(e){return ko(e)?`skip`:!e.isIframe&&e.origin===e.authOrigin?`auth-eager`:`lazy`}function jo(e){return e?typeof ShadowRoot<`u`&&e instanceof ShadowRoot?e.host:e.parentNode??null:null}function Mo(e,t){let n=t;for(;n;){if(n===e)return!0;n=jo(n)}return!1}function No(e){return e===document.body||e===document.documentElement}function Po(e,t,n={}){let{allowDocumentViewport:r=!1}=n;if(!(e instanceof HTMLElement)||No(e)&&!r)return null;for(let n of t)if(n&&(Mo(e,n)||Mo(n,e)))return e;return null}function Fo(e,t){return!e||!t?null:Ro(e,t,e instanceof Document?null:e)}function Io(e,t,n){if(!n)return e.querySelector(t);let r=e.querySelectorAll(t);for(let e of r)if(Mo(e,n))return e;return null}function Lo(e){let t=e.getRootNode();if(t instanceof ShadowRoot)return t.host;if(t instanceof Document)return t;if(t!==e){let n=jo(t);if(n&&n!==e&&n instanceof Element)return n}return null}function Ro(e,t,n){return e?e instanceof Document?Io(e,t,n):e.closest(t)||Ro(Lo(e),t,n):null}function zo(e,t){if(!t)return null;let n=Fo(e,t);return n instanceof HTMLElement&&n.isConnected&&Mo(n,e)?n:null}function Bo(e,t){return t.host===`youtube`&&t.additionalData!==`mobile`?e.parentElement??e:e}function Vo(e){let t=Bo(e.container,e.site),n=e.fullscreenRoot??t;return{base:t,root:n,portalContainer:t,subtitlesMountContainer:n}}var H=class{listeners=new Set;get size(){return this.listeners.size}addListener(e){return this.listeners.add(e),this}removeListener(e){return this.listeners.delete(e),this}dispatch(...e){for(let t of this.listeners)try{t(...e)}catch(e){console.error(`[VOT]`,e)}}async dispatchAsync(...e){let t=[];for(let n of this.listeners)try{let r=n(...e);r&&typeof r.then==`function`&&t.push(Promise.resolve(r))}catch(e){console.error(`[VOT]`,e)}if(!t.length)return;let n=await Promise.allSettled(t);for(let e of n)e.status===`rejected`&&console.error(`[VOT]`,e.reason)}clear(){this.listeners.clear()}};function Ho(e,t,n,r){return JSON.stringify({downloadType:e,itag:t,minChunkSize:r,fileSize:n})}function Uo(e){return e?.toLowerCase()??``}function Wo(e){let t=Uo(e);return t.includes(`audio/`)&&!t.includes(`video/`)}function Go(e){let t=Uo(e);return t.includes(`audio/mp4`)&&t.includes(`mp4a.`)}function Ko(e){let t=Uo(e);return t.includes(`audio/webm`)&&t.includes(`opus`)}function qo(e){if(!e)return`mp4a.40.2`;let t=/codecs="([^"]+)"/i.exec(e);if(!t?.[1])return`mp4a.40.2`;let n=t[1].split(`,`).map(e=>e.trim());return n.find(e=>e.toLowerCase().startsWith(`mp4a.`))??n[0]??`mp4a.40.2`}function Jo(e,t){let n=null,r=t===`max`?-1/0:1/0;for(let i of e){let e=i.bitrate??0;(t===`max`&&e>r||t===`min`&&eWo(e.mimeType));if(!n.length)throw Error(`No adaptive audio formats were found in player response`);let r=t===`bestefficiency`?`min`:`max`,i=t===`bestefficiency`?[n.filter(e=>Ko(e.mimeType)),n]:[n.filter(e=>Go(e.mimeType)),n.filter(e=>Ko(e.mimeType)),n];for(let e of i){if(!e.length)continue;let t=Jo(e,r);if(t)return t}throw Error(`No adaptive audio formats were found in player response`)}var Xo=class extends Error{status;constructor(e=403){super(`Failed to load watch page: ${e}`),this.name=`YtWatchContextForbiddenError`,this.status=e}},Zo=/^[a-zA-Z0-9_-]{11}$/,Qo=`https://www.youtube.com`,$o=`19.44.38`,es=`1.60.19`,ts=`19.45.4`,ns=[`ANDROID_VR`,`ANDROID`,`IOS`,`WEB`,`MWEB`],rs={accept:`*/*`,origin:Qo,referer:`${Qo}/`},is=256*1024;function as(e){return e?{signal:e}:{}}function os(e,t,n){switch(e){case`ANDROID`:case`YTMUSIC_ANDROID`:case`YTSTUDIO_ANDROID`:return{clientName:`ANDROID`,clientVersion:$o,hl:`en`,gl:`US`,androidSdkVersion:34,osName:`Android`,osVersion:`14`,platform:`MOBILE`};case`ANDROID_VR`:return{clientName:`ANDROID_VR`,clientVersion:es,hl:`en`,gl:`US`,androidSdkVersion:31,osName:`Android`,osVersion:`12`,platform:`MOBILE`};case`IOS`:return{clientName:`IOS`,clientVersion:ts,hl:`en`,gl:`US`,platform:`MOBILE`,osName:`iPhone`,osVersion:`18.0.0.22A3354`,deviceMake:`Apple`,deviceModel:`iPhone16,2`};case`MWEB`:return{clientName:`MWEB`,clientVersion:t.clientVersion,hl:`en`,gl:`US`,originalUrl:`${Qo}/watch?v=${n}`};default:return{clientName:`WEB`,clientVersion:t.clientVersion,hl:`en`,gl:`US`,utcOffsetMinutes:0,originalUrl:`${Qo}/watch?v=${n}`}}}function ss(e){let t=e.trim();if(Zo.test(t))return t;let n;try{n=new URL(t)}catch{throw Error(`Cannot extract YouTube video id from: ${e}`)}let r=n.hostname.toLowerCase();if(r===`youtu.be`||r.endsWith(`.youtu.be`))return cs(n.pathname.split(`/`).find(Boolean),e);let i=n.searchParams.get(`v`);if(i&&Zo.test(i))return i;let a=ls(n.pathname.split(`/`).filter(Boolean));if(a)return a;throw Error(`Cannot extract YouTube video id from: ${e}`)}function cs(e,t){if(e&&Zo.test(e))return e;throw Error(`Cannot extract YouTube video id from: ${t}`)}function ls(e){for(let t of[`shorts`,`embed`]){let n=e.indexOf(t);if(n===-1)continue;let r=e[n+1];if(r&&Zo.test(r))return r}return null}function us(e){return e.replaceAll(`\\u0026`,`&`).replaceAll(`\\/`,`/`)}function ds(e){let t=e.videoId??e.videoUrl;if(!t)throw Error(`Either videoId or videoUrl is required`);return ss(t)}function fs(e,t){for(let n of t){let t=n.exec(e)?.[1];if(t)return t}}async function ps(e){return new Uint8Array(await e.arrayBuffer())}function ms(e=16){let t=`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_`,n=``;if(typeof crypto<`u`&&typeof crypto.getRandomValues==`function`){let r=new Uint8Array(e);crypto.getRandomValues(r);for(let e of r)n+=t[e%64]??`a`;return n}for(let r=0;ri)return!1;let a=_s(e.headers.get(`content-range`));return a?a.start===n&&a.end===n+t.byteLength-1:e.status===206?t.byteLength===i:e.status===200?n===0&&t.byteLength===i:!1}function bs(e,t){let n=e.headers.get(`content-range`)??`none`,r=e.headers.get(`content-length`)??`none`;return`status=${e.status}; bytes=${t.byteLength}; content-range=${n}; content-length=${r}`}function xs(e){let t=e?.toLowerCase()??``;return t.includes(`audio/webm`)?`audio/webm`:t.includes(`audio/mp4`)?`audio/mp4`:`audio/aac`}function Ss(e){let t=e?[e,...ns]:[...ns],n=new Set;return t.filter(e=>n.has(e)?!1:(n.add(e),!0))}var Cs=class{fetchFn;constructor(e={}){this.fetchFn=e.fetchImplementation??fetch}async fetchRangeChunk(e,t,n,r){let i=`bytes=${t}-${n}`,a=await this.fetchFn(e,{headers:{...rs,range:i},...as(r)});if(!a.ok)throw Error(`Failed to download stream chunk: ${a.status}`);let o=await ps(a);if(!ys(a,o,t,n))throw Error(`Received unexpected stream chunk payload: ${bs(a,o)}`);return o}async downloadStreamByRanges(e,t,n){let r=await this.resolveStreamContentLength(e,t,n,!0),i=new Uint8Array(r),a=0;for(let t=0;ti.byteLength)throw Error(`Downloaded stream chunk exceeds probed stream content length`);i.set(s,a),a+=s.byteLength}return a===i.byteLength?i:i.slice(0,a)}async downloadAudioToChunkStream(e,t){if(t.chunkSize<=0)throw RangeError(`Audio downloader. ytAudio. chunkSize must be > 0`);return this.withResolvedPlayableAudioFormat(e,e.videoQuality??`best`,`Chunk mode requires an adaptive audio stream format`,`Unable to resolve streamable format for chunk mode`,async({resolved:e,signal:n})=>{let r=await this.resolveStreamContentLength(e.streamUrl,e.chosenFormat.contentLength,n,!0),i=Math.max(1,Math.ceil(r/t.chunkSize));return{videoId:e.videoId,fileSize:r,itag:e.chosenFormat.itag??0,mediaPartsLength:i,getMediaBuffers:async function*(){for(let a=0;a{let r=await this.downloadStreamByRanges(e.streamUrl,e.chosenFormat.contentLength,n),i=this.getExtractionHints(e.chosenFormat);return await t.write(r),{videoId:e.videoId,bytesWritten:r.byteLength,mimeType:xs(e.chosenFormat.mimeType),codec:i.codec,sampleRate:i.sampleRate,channels:i.channels}})}async withResolvedPlayableAudioFormat(e,t,n,r,i){let a=ds(e),{signal:o}=e,s=await this.fetchWatchContext(a,o),c=Ss(e.client),l=[];for(let e of c)try{let r=await this.resolvePlayableFormatForClient({videoId:a,watchContext:s,client:e,quality:t,signal:o});if(!Wo(r.chosenFormat.mimeType))throw Error(n);return await i({resolved:r,signal:o})}catch(t){let n=t instanceof Error?t.message:String(t);l.push(`${e}: ${n}`)}throw Error(`${r}. Attempts: ${l.join(` | `)}`)}async resolvePlayableFormatForClient({videoId:e,watchContext:t,client:n,quality:r,signal:i}){let a=((await this.fetchPlayerResponse(e,t,n,i)).streamingData?.adaptiveFormats??[]).filter(e=>!!e.url);if(!a.length)throw Error(`Player response did not contain direct adaptive audio stream URLs`);let o=Yo(a,r);return{videoId:e,chosenFormat:o,streamUrl:this.resolveFormatUrl(o,t.clientVersion)}}async resolveStreamContentLength(e,t,n,r=!1){let i=hs(t);if(i!==null&&!r)return i;let a;try{a=await this.fetchFn(e,{headers:{...rs,range:`bytes=0-0`},...as(n)})}catch(e){if(i!==null)return i;let t=e instanceof Error?e.message:String(e);throw Error(`Failed to probe stream content length: ${t}`)}if(!a.ok){if(i!==null)return i;throw Error(`Failed to probe stream content length: ${a.status}`)}let o=gs(a.headers.get(`content-range`)),s=hs(a.headers.get(`x-goog-stored-content-length`)),c=hs(a.headers.get(`content-length`));if(typeof a.body?.cancel==`function`)try{await a.body.cancel()}catch{}return o??s??i??c??(()=>{throw Error(`Failed to resolve stream content length`)})()}getExtractionHints(e){let t=qo(e.mimeType),n=Number.parseInt(e.audioSampleRate??``,10);return{codec:t,sampleRate:Number.isFinite(n)&&n>0?n:44100,channels:e.audioChannels&&e.audioChannels>0?e.audioChannels:2}}resolveFormatUrl(e,t){if(!e.url)throw Error(`Selected format does not contain a direct stream URL`);let n=new URL(e.url);return n.searchParams.get(`c`)===`WEB`&&n.searchParams.set(`cver`,t),n.searchParams.set(`cpn`,ms()),n.toString()}async fetchWatchContext(e,t){let n=`${Qo}/watch?v=${encodeURIComponent(e)}&hl=en`,r=await this.fetchFn(n,{headers:rs,...as(t)});if(!r.ok)throw r.status===403?new Xo(r.status):Error(`Failed to load watch page: ${r.status}`);let i=await r.text(),a=fs(i,[/"INNERTUBE_API_KEY":"([^"]+)"/,/["']INNERTUBE_API_KEY["']\s*:\s*"([^"]+)"/]),o=fs(i,[/"INNERTUBE_CLIENT_VERSION":"([^"]+)"/,/["']INNERTUBE_CLIENT_VERSION["']\s*:\s*"([^"]+)"/]),s=fs(i,[/"STS":(\d+)/,/["']STS["']\s*:\s*(\d+)/]),c=fs(i,[/"VISITOR_DATA":"([^"]+)"/,/"visitorData":"([^"]+)"/,/["'](?:VISITOR_DATA|visitorData)["']\s*:\s*"([^"]+)"/]);if(!a||!o)throw Error(`Failed to extract required player context from watch page`);let l=s?Number.parseInt(s,10):void 0,u={apiKey:a,clientVersion:o};return typeof l==`number`&&Number.isFinite(l)&&(u.signatureTimestamp=l),c&&(u.visitorData=us(c)),u}async fetchPlayerResponse(e,t,n,r){let i=os(n,t,e);t.visitorData&&(i.visitorData=t.visitorData);let a={context:{client:i},videoId:e,contentCheckOk:!0,racyCheckOk:!0};t.signatureTimestamp&&(a.playbackContext={contentPlaybackContext:{signatureTimestamp:t.signatureTimestamp}});let o=`${Qo}/youtubei/v1/player?key=${encodeURIComponent(t.apiKey)}`,s=await this.fetchFn(o,{method:`POST`,headers:{...rs,"content-type":`application/json`,...t.visitorData?{"x-goog-visitor-id":t.visitorData}:{}},body:JSON.stringify(a),...as(r)});if(!s.ok)throw Error(`Player API request failed with status ${s.status}`);let c=await s.json(),l=!!c.streamingData?.formats?.length,u=!!c.streamingData?.adaptiveFormats?.length;if(!l&&!u)throw Error(`Player response did not contain streaming formats`);return c}},ws=`bestefficiency`,Ts=3e4;function Es(e){if(e<=0)throw RangeError(`Audio downloader. ytAudio. chunkSize must be > 0`)}function Ds({signal:e,timeoutMs:t}){return async(n,r={})=>await z(n,{...r,signal:r.signal??e,forceGmXhr:!0,timeout:t})}function Os(e){return e instanceof Xo?!0:e instanceof Error&&/failed to load watch page:\s*403/i.test(e.message)}async function ks({videoId:e,signal:t},n={}){let r=n.chunkSize??f.minChunkSize;Es(r);let i=Ds({signal:t,timeoutMs:n.fetchTimeoutMs??Ts}),a=n.createDownloader?.(i)??new Cs({fetchImplementation:i});try{let n=await a.downloadAudioToChunkStream({videoId:e,videoQuality:ws,signal:t},{chunkSize:r});return{fileId:Ho(qt.WEB_API_STEAL_SIG_AND_N,n.itag,String(n.fileSize),r),mediaPartsLength:n.mediaPartsLength,getMediaBuffers:n.getMediaBuffers}}catch(e){if(Os(e))throw e;console.warn(`[VOT] ytAudio streaming mode failed, falling back to buffered mode`,e)}let o=(await a.downloadAudioToUint8Array({videoId:e,videoQuality:ws,signal:t})).bytes;if(!o||o.byteLength===0)throw Error(`Audio downloader. ytAudio. Empty audio`);let s=Math.max(1,Math.ceil(o.byteLength/r));return{fileId:Ho(qt.WEB_API_STEAL_SIG_AND_N,0,String(o.byteLength),r),mediaPartsLength:s,async*getMediaBuffers(){for(let e=0;e=Is&&(n+=1),n>=60)return t(`translationTakeMoreThanHour`);if(n<=1)return t(`translationTakeAboutMinute`);let r=String(n);return n!==11&&n%10==1?t(`translationTakeApproximatelyMinute2`).replace(`{0}`,r):![12,13,14].includes(n)&&[2,3,4].includes(n%10)?t(`translationTakeApproximatelyMinute`).replace(`{0}`,r):t(`translationTakeApproximatelyMinutes`).replace(`{0}`,r)}var U=class extends Error{name=`VOTLocalizedError`;unlocalizedMessage;localizedMessage;constructor(e){super(V.getDefault(e)),this.unlocalizedMessage=e,this.localizedMessage=V.get(e)}};function Rs(e){return e??null}async function zs(e,t){let n=await e.translateVideoImpl(t.videoData,t.requestLang,t.responseLang,Rs(t.translationHelp),!t.useAudioDownload,t.signal);return n?.url?{url:n.url,usedLivelyVoice:!!n.usedLivelyVoice}:null}function Bs(e){return{videoId:e.videoId,from:e.requestLang,to:e.responseLang,url:e.downloadTranslationUrl??e.fallbackUrl,useLivelyVoice:e.usedLivelyVoice}}async function Vs(e){return!(e.isActionStale(e.actionContext)||(await e.updateTranslation(e.url,e.actionContext),e.isActionStale(e.actionContext)))}async function Hs(e){let t=await zs(e.requester,{videoData:e.request.videoData,requestLang:e.request.requestLang,responseLang:e.request.responseLang,translationHelp:e.request.translationHelp,useAudioDownload:e.request.useAudioDownload,signal:e.request.signal});return!t||!await Vs({url:t.url,actionContext:e.actionContext,isActionStale:e.isActionStale,updateTranslation:e.updateTranslation})||e.isActionStale(e.actionContext)?null:t}function Us(e){e.setTranslation(e.cacheKey,Bs({videoId:e.videoId,requestLang:e.requestLang,responseLang:e.responseLang,fallbackUrl:e.fallbackUrl,downloadTranslationUrl:e.downloadTranslationUrl,usedLivelyVoice:e.usedLivelyVoice}))}function Ws(e){return e.aborted||!e.translateApiErrorsEnabled||!e.hadAsyncWait?e.hadAsyncWait:(e.notify({videoId:e.videoId,message:e.error}),!1)}function Gs(e){if(!e||typeof e!=`object`)return null;let t=e,n=t.data&&typeof t.data==`object`?t.data:void 0;return{name:t.name,message:t.message,data:n}}function Ks(e){let t=Gs(e)?.data?.message;return typeof t==`string`&&t.length>0?t:void 0}function qs(e){let t=Gs(e);if(!t||t.name!==`VOTJSError`)return e;let n=typeof t.message==`string`?t.message:``,r=typeof t.data?.message==`string`&&t.data.message.length>0;return n===`Yandex couldn't translate video`&&!r||n===`Failed to request video translation`?new U(`requestTranslationFailed`):n===`Audio link wasn't received`||n===`Audio link wasn't received from VOT response`?new U(`audioNotReceived`):e}var Js=class{videoHandler;audioDownloader;downloading;downloadWaiters=new Set;requestedFailAudio=new Set;constructor(e){this.videoHandler=e,this.audioDownloader=new Fs,this.downloading=!1,this.audioDownloader.addEventListener(`downloadedAudio`,this.onDownloadedAudio).addEventListener(`downloadedPartialAudio`,this.onDownloadedPartialAudio).addEventListener(`downloadAudioError`,this.onDownloadAudioError)}onDownloadedAudio=async(e,t)=>{if(L.log(`downloadedAudio`,t),!this.downloading){L.log(`skip downloadedAudio`);return}let{videoId:n,fileId:r,audioData:i}=t,a=this.getCanonicalUrl(n);try{await this.videoHandler.votClient.requestVtransAudio(a,e,{audioFile:i,fileId:r})}catch(e){L.error(`Failed to upload downloaded audio`,e),this.finishDownloadFailure(Error(`Audio downloader failed while uploading full audio`));return}this.finishDownloadSuccess()};onDownloadedPartialAudio=async(e,t)=>{if(L.log(`downloadedPartialAudio`,t),!this.downloading){L.log(`skip downloadedPartialAudio`);return}let{audioData:n,fileId:r,videoId:i,amount:a,version:o,index:s}=t,c=this.getCanonicalUrl(i);try{await this.videoHandler.votClient.requestVtransAudio(c,e,{audioFile:n,chunkId:s},{audioPartsLength:a,fileId:r,version:o})}catch(e){L.error(`Failed to upload downloaded audio chunk`,e),this.finishDownloadFailure(Error(`Audio downloader failed while uploading chunk`));return}s===a-1&&this.finishDownloadSuccess()};onDownloadAudioError=async e=>{if(!this.downloading){L.log(`skip downloadAudioError`);return}L.log(`Failed to download audio ${e}`);let t=this.getCanonicalUrl(e);if(!(this.videoHandler.site.host===`youtube`&&this.videoHandler.data?.useAudioDownload)){this.finishDownloadFailure(new U(`VOTFailedDownloadAudio`));return}try{this.requestedFailAudio.has(t)?L.log(`fail-audio-js request already sent for this video`):(L.log(`Sending fail-audio-js request`),await this.videoHandler.votClient.requestVtransFailAudio(t),this.requestedFailAudio.add(t)),this.finishDownloadSuccess()}catch(e){L.error(`fail-audio-js request failed`,e),this.finishDownloadFailure(new U(`VOTFailedDownloadAudio`))}};finishDownloadSuccess(){this.downloading=!1,this.resolveDownloadWaiters()}finishDownloadFailure(e){this.downloading=!1,this.rejectDownloadWaiters(e)}getCanonicalUrl(e){return`https://youtu.be/${e}`}isLivelyVoiceUnavailableError(e){let t=xa(e);return!!t&&t.toLowerCase().includes(`обычная озвучка`)}scheduleRetry(e,t,n){return new Promise((r,i)=>{let a=null,o=()=>{a!==null&&clearTimeout(a),n.removeEventListener(`abort`,s)},s=()=>{o(),i(Ca())};if(n.addEventListener(`abort`,s,{once:!0}),n.aborted){s();return}a=setTimeout(async()=>{if(n.aborted){s();return}o();try{r(await e())}catch(e){i(e)}},t),a!==null&&(this.videoHandler.autoRetry=a)})}getVideoTranslationRetryDelayMs(e,t){return e>0?25e3:t<=600?6e4:75e3}async translateVideoImpl(e,t,n,r=null,i=!1,a=wa,o={}){let{disableLivelyVoice:s=!1,retryAttempt:c=0}=o;clearTimeout(this.videoHandler.autoRetry),this.finishDownloadSuccess();let l=this.videoHandler.getRequestLangForTranslation(t,n);L.log(e,`Translate video (requestLang: ${t}, requestLangForApi: ${l}, responseLang: ${n})`);let u=s;try{Ta(a);let o=this.videoHandler.isLivelyVoiceAllowed(l,n),s=await this.requestTranslationWithLivelyFallback({videoData:e,requestLangForApi:l,responseLang:n,translationHelp:r,shouldSendFailedAudio:i,livelyDisabled:u,livelyVoiceAllowed:o});u=s.livelyDisabled;let d=s.useLivelyVoice,f=s.response;if(!f)throw Error(`Failed to get translation response`);if(L.log(`Translate video result`,f),Ta(a),f.translated&&f.remainingTime<1)return L.log(`Video translation finished with this data: `,f),{...f,usedLivelyVoice:d};let p=f.message??V.get(`translationTakeFewMinutes`);if(await this.videoHandler.updateTranslationErrorMsg(f.remainingTime>0?Ls(f.remainingTime,e=>V.get(e)):p,a),f.status===Kt.AUDIO_REQUESTED&&this.videoHandler.isYouTubeHosts())return this.videoHandler.hadAsyncWait=!0,L.log(`Start audio download`),this.downloading=!0,await this.audioDownloader.runAudioDownload(e.videoId,f.translationId,a),L.log(`waiting downloading finish`),await this.waitForAudioDownloadCompletion(a,15e3),await this.translateVideoImpl(e,t,n,r,!0,a,{disableLivelyVoice:u,retryAttempt:c})}catch(t){if(Sa(t))return L.log(`aborted video translation`),null;let n=qs(t);return await this.videoHandler.updateTranslationErrorMsg(Ks(n)??n,a),this.videoHandler.hadAsyncWait=Ws({aborted:!!this.videoHandler.actionsAbortController?.signal?.aborted,translateApiErrorsEnabled:!!this.videoHandler.data?.translateAPIErrors,hadAsyncWait:this.videoHandler.hadAsyncWait,videoId:e.videoId,error:t,notify:e=>this.videoHandler.notifier.translationFailed(e)}),console.error(`[VOT]`,t),null}return this.videoHandler.hadAsyncWait=!0,this.scheduleRetry(()=>this.translateVideoImpl(e,t,n,r,i,a,{disableLivelyVoice:u,retryAttempt:c+1}),this.getVideoTranslationRetryDelayMs(c,e.duration),a)}async requestTranslationWithLivelyFallback({videoData:e,requestLangForApi:t,responseLang:n,translationHelp:r,shouldSendFailedAudio:i,livelyDisabled:a,livelyVoiceAllowed:o}){let s=!a&&o&&!!this.videoHandler.data?.useLivelyVoice;for(;;){try{let o=await this.videoHandler.votClient.translateVideo({videoData:e,requestLang:t,responseLang:n,translationHelp:r,extraOpts:{useLivelyVoice:s,videoTitle:this.videoHandler.videoData?.title},shouldSendFailedAudio:i});if(!s||!this.isLivelyVoiceUnavailableError(o))return{response:o,useLivelyVoice:s,livelyDisabled:a};L.log(`[translateVideoImpl] Server responded that lively voices are unavailable. Falling back to standard translation.`,o)}catch(e){if(!s||!this.isLivelyVoiceUnavailableError(e))throw e;L.log(`[translateVideoImpl] Lively voices are unavailable. Falling back to standard translation.`,e)}a=!0,s=!1}}waitForAudioDownloadCompletion(e,t){return this.downloading?new Promise((n,r)=>{let i,a=()=>{s(),r(Ca())},o=setTimeout(()=>{s(),n()},t),s=()=>{clearTimeout(o),e.removeEventListener(`abort`,a),this.downloadWaiters.delete(i)};i={resolve:()=>{s(),n()},reject:e=>{s(),r(e)}},this.downloadWaiters.add(i),e.addEventListener(`abort`,a,{once:!0}),e.aborted&&a()}):Promise.resolve()}resolveDownloadWaiters(){this.forEachDownloadWaiter(e=>e.resolve())}rejectDownloadWaiters(e){this.forEachDownloadWaiter(t=>t.reject(e))}forEachDownloadWaiter(e){if(!this.downloadWaiters.size)return;let t=Array.from(this.downloadWaiters);this.downloadWaiters.clear();for(let n of t)e(n)}},Ys=class{state={status:`idle`};deps;constructor(e){this.deps=e}get currentState(){return this.state}setState(e){this.state=e,L.log(`[TranslationOrchestrator] state`,e)}reset(){this.setState({status:`idle`})}async runAutoTranslationIfEligible(){if(this.state.status===`idle`&&this.deps.isFirstPlay()&&this.deps.isAutoTranslateEnabled()&&this.deps.getVideoId()){if(this.deps.isMobileYouTubeMuted?.()){L.log(`[TranslationOrchestrator] Mobile YouTube video is muted, deferring auto-translate`),this.setState({status:`deferred`,reason:`muted`}),this.deps.setMuteWatcher?.(()=>{L.log(`[TranslationOrchestrator] Video unmuted, running deferred auto-translate`),this.setState({status:`idle`}),this.runAutoTranslationIfEligible()});return}this.setState({status:`pending`,reason:`auto`});try{await this.deps.scheduleAutoTranslate(),this.deps.setFirstPlay(!1),this.reset()}catch(e){throw this.setState({status:`error`,message:e}),e}}}};function Xs(e,t={}){let{requireVideoData:n=!1,clearVideoData:r=!1}=t;n&&!e.videoData||(r&&(e.videoData=void 0),e.stopTranslation(),e.resetSubtitlesWidget())}function Zs(e,t={}){let{hideMenu:n=!1}=t;e?.votButton?.container&&(e.votButton.container.hidden=!0),n&&e?.votMenu&&(e.votMenu.hidden=!0)}function Qs(e,t,n={}){let{requireVideoData:r,clearVideoData:i,hideMenu:a}=n;Xs(e,{requireVideoData:r,clearVideoData:i}),Zs(t,{hideMenu:a})}var $s=class{host;lifecycleGeneration=0;lastSetCanPlaySourceKey=``;activeSetCanPlaySourceKey=``;setCanPlayRequested=!1;setCanPlayLoopPromise;constructor(e){this.host=e}isStale(e){return e!==this.lifecycleGeneration}resetActions(e){if(typeof this.host.resetActionsAbortController==`function`){this.host.resetActionsAbortController(e);return}this.host.actionsAbortController?.abort(e)}invalidateActiveSession(e){this.lifecycleGeneration!==0&&(this.lifecycleGeneration+=1,this.resetActions(`[VideoLifecycle] ${e}`),L.log(`[VideoLifecycle] cancelled active session (active: ${this.lifecycleGeneration})`,{reason:e}))}startSession(e){this.lifecycleGeneration+=1;let t=this.lifecycleGeneration;return this.resetActions(`[VideoLifecycle][session:${t}] ${e}`),L.log(`[VideoLifecycle][session:${t}] started`,{reason:e}),t}shouldAbortHandleSrcChanged(e,t){return this.isStale(e)?(L.log(`[VideoLifecycle][session:${e}] handleSrcChanged aborted at ${t} (active: ${this.lifecycleGeneration})`),!0):!1}showOverlayButton(e){e.votButton.container.hidden=!1,e.votButton.opacity=1,this.host.queueOverlayAutoHide?.()}teardown(){this.setCanPlayRequested=!1,this.invalidateActiveSession(`teardown`)}getCurrentSourceKey(){let e=this.host.video.srcObject?`1`:`0`;if(this.host.site.host===`youtube`){let t=globalThis.location.pathname;return`${`${globalThis.location.origin}${t}${globalThis.location.search}`}||${e}`}let t=this.host.video.currentSrc||this.host.video.src||``;return`${globalThis.location.href}||${t}||${e}`}resolveContainer(){let{site:e,video:t,container:n}=this.host;return e.selector?zo(t,e.selector)||(n.isConnected&&Mo(n,t)?n:t.parentElement??n):t.parentElement??n}async setCanPlay(){if(this.setCanPlayRequested=!0,this.setCanPlayLoopPromise!==void 0){let e=this.getCurrentSourceKey();return this.activeSetCanPlaySourceKey&&e!==this.activeSetCanPlaySourceKey?this.invalidateActiveSession(`setCanPlay source changed while previous trigger is running`):L.log(`[VideoLifecycle] setCanPlay deduplicated for same source`,{sourceKey:e}),await this.setCanPlayLoopPromise}let e=(async()=>{for(;this.setCanPlayRequested;)this.setCanPlayRequested=!1,await this.runSetCanPlayOnce()})();this.setCanPlayLoopPromise=e;try{await e}finally{this.setCanPlayLoopPromise===e&&(this.setCanPlayLoopPromise=void 0)}}async runSetCanPlayOnce(){let e=this.getCurrentSourceKey();if(this.host.videoData?.videoId&&e===this.lastSetCanPlaySourceKey){L.log(`[VideoLifecycle] setCanPlay deduplicated for same source`,{sourceKey:e});return}let t;try{t=await this.host.getVideoData()}catch(t){L.log(`[VideoLifecycle] getVideoData failed for source ${e}`,t),this.host.videoData=void 0,Zs(this.host.uiManager.votOverlayView,{hideMenu:!0});return}if(this.getCurrentSourceKey()!==e){L.log(`[VideoLifecycle] discarded stale getVideoData result after source change`,{sourceKey:e});return}this.host.videoData=t,this.activeSetCanPlaySourceKey=e;let n=this.startSession(`setCanPlay (source: ${e})`);L.log(`[VideoLifecycle][session:${n}] setCanPlay started`,{sourceKey:e});try{if(await this.handleSrcChanged(n,e),this.isStale(n)){L.log(`[VideoLifecycle][session:${n}] setCanPlay aborted after src change (active: ${this.lifecycleGeneration})`);return}let t=this.runAutoSubtitlesIfEnabled(n);if(await this.host.translationOrchestrator.runAutoTranslationIfEligible(),this.isStale(n)){L.log(`[VideoLifecycle][session:${n}] auto-translation result ignored (stale session)`);return}if(await t,this.isStale(n)){L.log(`[VideoLifecycle][session:${n}] auto-subtitles result ignored (stale session)`);return}L.log(`[VideoLifecycle][session:${n}] setCanPlay finished`)}finally{this.activeSetCanPlaySourceKey===e&&(this.activeSetCanPlaySourceKey=``)}}async runAutoSubtitlesIfEnabled(e){if(!(!this.host.data.autoSubtitles||!this.host.videoData?.videoId))try{await this.host.enableSubtitlesForCurrentLangPair()}catch(t){L.log(`[VideoLifecycle][session:${e}] auto-subtitles failed`,t)}}async handleSrcChanged(e,t){let n=typeof e==`number`?e:this.startSession(`manual handleSrcChanged`),r=typeof t==`string`&&t.length>0?t:this.getCurrentSourceKey();if(this.shouldAbortHandleSrcChanged(n,`before start`))return;L.log(`[VideoLifecycle][session:${n}] src changed`,{sourceKey:r}),this.host.translationOrchestrator.reset(),this.host.firstPlay=!0;let i=this.host.uiManager.votOverlayView;Qs(this.host,i,{requireVideoData:!0}),!this.host.video.src&&!this.host.video.currentSrc&&!this.host.video.srcObject&&Zs(i,{hideMenu:!0});let a=this.resolveContainer();if(a!==this.host.container&&(this.host.container=a),this.shouldAbortHandleSrcChanged(n,`before getVideoData`)||(this.showOverlayButton(i),this.shouldAbortHandleSrcChanged(n,`after getVideoData`)))return;if(!this.host.videoData?.videoId){L.log(`[VideoLifecycle][session:${n}] No videoId resolved, hiding overlay`),Zs(i,{hideMenu:!0});return}let o=this.host.getPreferredSubtitlesLanguage(this.host.videoData.detectedLanguage,this.host.videoData.responseLanguage);if(o){let e=this.host.getSubtitlesCacheKey(this.host.videoData.videoId,this.host.videoData.detectedLanguage,o),t=this.host.cacheManager.getSubtitles(e);this.host.subtitles=t??[],this.host.subtitlesCacheKey=t===void 0?null:e}else this.host.subtitles=[],this.host.subtitlesCacheKey=null;await this.host.updateSubtitlesLangSelect(),!this.shouldAbortHandleSrcChanged(n,`after subtitles update`)&&(this.host.translateToLang=this.host.data.responseLanguage??`ru`,this.host.setSelectMenuValues(this.host.videoData.detectedLanguage,this.host.videoData.responseLanguage),this.showOverlayButton(i),this.lastSetCanPlaySourceKey=r,L.log(`[VideoLifecycle][session:${n}] src handling finished`))}};function ec(e,t){let n=()=>e;return{get video(){return n().video},get site(){return n().site},get container(){return n().container},set container(e){n().container!==e&&(n().container=e,n().uiManager.updateMount(t(e)))},get firstPlay(){return n().firstPlay},set firstPlay(e){n().firstPlay=e},stopTranslation:()=>e.stopTranslation(),get uiManager(){return n().uiManager},getVideoData:()=>e.getVideoData(),cacheManager:{getSubtitles:e=>n().cacheManager.getSubtitles(e)},getSubtitlesCacheKey:(t,n,r)=>e.getSubtitlesCacheKey(t,n,r),getPreferredSubtitlesLanguage:(t,n)=>e.getPreferredSubtitlesLanguage(t,n),updateSubtitlesLangSelect:()=>e.updateSubtitlesLangSelect(),enableSubtitlesForCurrentLangPair:()=>e.enableSubtitlesForCurrentLangPair(),setSelectMenuValues:(t,n)=>e.setSelectMenuValues(t,n),get translateToLang(){return n().translateToLang},set translateToLang(e){n().translateToLang=e},get data(){return n().data??{}},get subtitles(){return n().subtitles},set subtitles(e){n().subtitles=e},get subtitlesCacheKey(){return n().subtitlesCacheKey},set subtitlesCacheKey(e){n().subtitlesCacheKey=e},get videoData(){return n().videoData},set videoData(e){n().videoData=e},get actionsAbortController(){return n().actionsAbortController},set actionsAbortController(e){n().actionsAbortController=e},resetActionsAbortController:t=>e.resetActionsAbortController(t),translationOrchestrator:e.translationOrchestrator,resetSubtitlesWidget:()=>e.resetSubtitlesWidget(),queueOverlayAutoHide:()=>e.overlayVisibility?.queueAutoHide()}}var tc=450,nc=new RegExp([String.raw`(?:https?:\/\/|www\.)\S+`,String.raw`#[^\s#]+`,String.raw`auto-generated\s+by\s+youtube`,String.raw`provided\s+to\s+youtube\s+by`,String.raw`released\s+on`,String.raw`\bpaypal\b`,String.raw`\b0x[a-f0-9]{40}\b`,String.raw`\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b`,String.raw`\b(?:bc1|tb1|bcrt1)[ac-hj-np-z02-9]{11,71}\b`,String.raw`\b(?:-1|0):[a-f0-9]{64}\b`].join(`|`),`giu`),rc=/[\p{N}\p{P}\p{S}]+/gu,ic=/\s+/g,ac=/\p{L}/u;function oc(e,t){return e.length<=t?e:e.slice(0,t).trimEnd()}function sc(e,t){let n=`${e??``} ${t??``}`.trim();if(!n)return``;let r=n.normalize(`NFKC`).replace(nc,` `).replace(rc,` `).replace(ic,` `).trim();return ac.test(r)?oc(r,tc):``}var cc=5e3,lc=2**53-1,uc=null,dc=0,fc=null,pc=0;async function mc(){let e=Date.now();if(uc&&e-dci){let t=jc(e,`up`,r);return Math.min(a,t)}return jc(e,`nearest`,r)}var Nc=new Set([`youtube`,`googledrive`]),Pc=Nc,Fc=new Set([`rutube`,`ok`]),Ic=new Set([`youtube`,`invidious`,`piped`]);function Lc(e){return Nc.has(e)}function Rc(e){return Pc.has(e)}function zc(e){return Fc.has(e)}function Bc(e){return Rc(e.host)&&e.additionalData!==`mobile`}function Vc(e){return Ic.has(e)}var Hc={rutube:`ru`,"ok.ru":`ru`,mail_ru:`ru`,weverse:`ko`,niconico:`ja`,youku:`zh`,bilibili:`zh`,weibo:`zh`,zdf:`de`},Uc=`.ytp-volume-panel [aria-valuenow]`,Wc=35,Gc=500,Kc=new Set(bn),qc=new Map;function Jc(e){let t=qc.get(e);if(t)return t;let n={};for(qc.set(e,n);qc.size>Gc;){let e=qc.keys().next().value;if(typeof e!=`string`)break;qc.delete(e)}return n}function Yc(e){if(typeof e!=`string`)return;let t=e.toLowerCase().split(/[-_]/)[0];return Kc.has(t)?t:void 0}function Xc(e){return!!(e&&e!==`auto`)}function Zc(e,t){return sc(typeof e==`string`?e:``,typeof t==`string`?t:void 0)}function Qc(e){let t=Hc[e];if(t)return t;if(e===`vk`){let e=document.getElementsByTagName(`track`)?.[0]?.srclang;return Yc(e)}}function $c(e){if(!Array.isArray(e)||e.length===0)return;let t=t=>{for(let n of e){if(!n||typeof n!=`object`)continue;let e=n;if(e.source!==`youtube`||typeof e.translatedFromLanguage==`string`||t&&e.isAutoGenerated===!0)continue;let r=Yc(e.language);if(Xc(r))return r}};return t(!0)??t(!1)}async function el(e){if(e.isStream)return{detectedLanguage:`auto`};if(e.userOverrideLanguage)return{detectedLanguage:e.userOverrideLanguage};let t=Qc(e.host);if(Xc(t))return{detectedLanguage:t,cacheLanguage:t};let n=Yc(e.possibleLanguage);if(Xc(n))return{detectedLanguage:n,cacheLanguage:n};let r=e.host===`youtube`?$c(e.subtitles):void 0;if(Xc(r))return{detectedLanguage:r,cacheLanguage:r};if(e.cachedDetectedLanguage)return{detectedLanguage:e.cachedDetectedLanguage};if(!e.allowTextLanguageDetection)return{detectedLanguage:`auto`};let i=Zc(e.title,e.description);if(!i||i.length0?i/a*100:i):null}var nl=class{videoHandler;constructor(e){this.videoHandler=e}setDetectedLanguageCache(e,t){Jc(e).detectedLanguage=t}rememberUserLanguageSelection(e,t){let n=Yc(t);if(!Xc(n)){let t=qc.get(e);t&&delete t.userLanguageOverride;return}let r=Jc(e);r.userLanguageOverride=n,r.detectedLanguage=n}rememberDetectedLanguage(e,t){let n=Yc(t);Xc(n)&&(this.setDetectedLanguageCache(e,n),this.videoHandler.videoData?.videoId===e&&(this.videoHandler.videoData.detectedLanguage=n))}async detectLanguageSingleFlight(e,t){let n=Jc(e),r=n.detectInFlight;if(r!==void 0)return r;let i=(async()=>{L.log(`Detecting language text: ${t}`);let e=Yc(await bc(t));return Xc(e)?e:void 0})();n.detectInFlight=i;try{return await i}finally{n.detectInFlight===i&&delete n.detectInFlight}}async ensureDetectedLanguageForTranslation(e){if(!e?.videoId||e.detectedLanguage!==`auto`)return;let t=Jc(e.videoId),{detectedLanguage:n,cacheLanguage:r}=await el({isStream:e.isStream,host:this.videoHandler.site.host,possibleLanguage:e.detectedLanguage,subtitles:e.subtitles,userOverrideLanguage:t.userLanguageOverride,cachedDetectedLanguage:t.detectedLanguage,title:e.title,description:e.description,allowTextLanguageDetection:!0,detectLanguage:async t=>await this.detectLanguageSingleFlight(e.videoId,t)});r&&this.setDetectedLanguageCache(e.videoId,r),!(!n||n===`auto`)&&this.videoHandler.setSelectMenuValues(n,this.videoHandler.translateToLang)}async getVideoData(){let{duration:e,url:t,videoId:n,host:r,title:i,translationHelp:a=null,localizedTitle:o,description:s,detectedLanguage:c,subtitles:l,isStream:u=!1}=await Yr(this.videoHandler.site,{fetchFn:z,video:this.videoHandler.video,language:V.lang}),d=Jc(n),{detectedLanguage:p,cacheLanguage:m}=await el({isStream:u,host:this.videoHandler.site.host,possibleLanguage:c,subtitles:l,userOverrideLanguage:d.userLanguageOverride,cachedDetectedLanguage:d.detectedLanguage,title:i,description:s,allowTextLanguageDetection:!1,detectLanguage:async e=>await this.detectLanguageSingleFlight(n,e)});m&&this.setDetectedLanguageCache(n,m);let h={translationHelp:a,isStream:u,duration:e||this.videoHandler.video?.duration||f.defaultDuration,videoId:n,url:t,host:r,detectedLanguage:p,responseLanguage:this.videoHandler.translateToLang,subtitles:l,title:i,localizedTitle:o,description:s,downloadTitle:o??i??document.title??n};return d.lastLoggedDetectedLanguage!==p&&(console.log(`[VOT] Detected language:`,p),d.lastLoggedDetectedLanguage=p),h}async videoValidator(){let e=this.videoHandler.videoData,t=this.videoHandler.data;if(!e||!t)throw new U(`VOTNoVideoIDFound`);if(L.log(`VideoValidator videoData: `,this.videoHandler.videoData),this.videoHandler.data.enabledDontTranslateLanguages&&this.videoHandler.data.dontTranslateLanguages?.includes(this.videoHandler.videoData.detectedLanguage))throw new U(`VOTDisableFromYourLang`);if(this.videoHandler.videoData.isStream)throw new U(`VOTStreamNotAvailable`);if(this.videoHandler.videoData.duration>14400)throw new U(`VOTVideoIsTooLong`);return!0}getVideoVolume(){let e=this.videoHandler.video;if(e){if(Lc(this.videoHandler.site.host)){let e=tl(Uc);if(e!=null)return kc(e);let t=F.getVolume();if(typeof t==`number`&&Number.isFinite(t))return jc(t)}return jc(e.volume)}}setVideoVolume(e){let t=jc(e),n=t>0;if(!Lc(this.videoHandler.site.host))return n&&(this.videoHandler.video.muted=!1),this.videoHandler.video.volume=t,this;try{let e=F.getPlayer(),r=F.setVolume(t);if(n&&(e?.unMute?.(),this.videoHandler.video.muted=!1),typeof r==`boolean`&&r||typeof r==`number`&&Number.isFinite(r))return this}catch{}return n&&(this.videoHandler.video.muted=!1),this.videoHandler.video.volume=t,this}isMuted(){return Lc(this.videoHandler.site.host)?F.isMuted():this.videoHandler.video?.muted}syncVideoVolumeSlider(){let e=this.videoHandler.uiManager.votOverlayView;if(!e?.isInitialized())return this;let t=Lc(this.videoHandler.site.host)?tl(Uc):null,n=this.isMuted()?0:t??Oc(this.getVideoVolume()??0);return e.videoVolumeSlider.value=n,this.videoHandler.onVideoVolumeSliderSynced?.(n),this}setSelectMenuValues(e,t){let n=this.videoHandler.videoData;if(!n)return this;let r=Yc(e)??`auto`,i=`${r}->${t}`,a=Jc(n.videoId);a.lastLoggedLangPair!==i&&(console.log(`[VOT] Set translation from ${r} to ${t}`),a.lastLoggedLangPair=i),n.detectedLanguage=r,n.responseLanguage=t,this.videoHandler.translateFromLang=r,this.videoHandler.translateToLang=t;let o=this.videoHandler.uiManager.votOverlayView;return o?.isInitialized()?(o.languagePairSelect.fromSelect.selectTitle=V.getLangLabel(r),o.languagePairSelect.toSelect.selectTitle=V.getLangLabel(t),o.languagePairSelect.fromSelect.setSelectedValue(r),o.languagePairSelect.toSelect.setSelectedValue(t),this):this}},rl=globalThis,il=e=>e,al=rl.trustedTypes,ol=al?al.createPolicy(`lit-html`,{createHTML:e=>e}):void 0,sl=`$lit$`,cl=`lit$${Math.random().toFixed(9).slice(2)}$`,ll=`?`+cl,ul=`<${ll}>`,dl=document,fl=()=>dl.createComment(``),pl=e=>e===null||typeof e!=`object`&&typeof e!=`function`,ml=Array.isArray,hl=e=>ml(e)||typeof e?.[Symbol.iterator]==`function`,gl=`[ \f\r]`,_l=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,vl=/-->/g,yl=/>/g,bl=RegExp(`>|${gl}(?:([^\\s"'>=/]+)(${gl}*=${gl}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,`g`),xl=/'/g,Sl=/"/g,Cl=/^(?:script|style|textarea|title)$/i,wl=e=>(t,...n)=>({_$litType$:e,strings:t,values:n}),Tl=wl(1),G=wl(2),El=Symbol.for(`lit-noChange`),K=Symbol.for(`lit-nothing`),Dl=new WeakMap,Ol=dl.createTreeWalker(dl,129);function kl(e,t){if(!ml(e)||!e.hasOwnProperty(`raw`))throw Error(`invalid template strings array`);return ol===void 0?t:ol.createHTML(t)}var Al=(e,t)=>{let n=e.length-1,r=[],i,a=t===2?``:t===3?``:``,o=_l;for(let t=0;t`?(o=i??_l,l=-1):c[1]===void 0?l=-2:(l=o.lastIndex-c[2].length,s=c[1],o=c[3]===void 0?bl:c[3]===`"`?Sl:xl):o===Sl||o===xl?o=bl:o===vl||o===yl?o=_l:(o=bl,i=void 0);let d=o===bl&&e[t+1].startsWith(`/>`)?` `:``;a+=o===_l?n+ul:l>=0?(r.push(s),n.slice(0,l)+sl+n.slice(l)+cl+d):n+cl+(l===-2?t:d)}return[kl(e,a+(e[n]||``)+(t===2?``:t===3?``:``)),r]},jl=class e{constructor({strings:t,_$litType$:n},r){let i;this.parts=[];let a=0,o=0,s=t.length-1,c=this.parts,[l,u]=Al(t,n);if(this.el=e.createElement(l,r),Ol.currentNode=this.el.content,n===2||n===3){let e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;(i=Ol.nextNode())!==null&&c.length0){i.textContent=al?al.emptyScript:``;for(let n=0;n2||n[0]!==``||n[1]!==``?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=K}_$AI(e,t=this,n,r){let i=this.strings,a=!1;if(i===void 0)e=Ml(this,e,t,0),a=!pl(e)||e!==this._$AH&&e!==El,a&&(this._$AH=e);else{let r=e,o,s;for(e=i[0],o=0;o{let r=n?.renderBefore??t,i=r._$litPart$;if(i===void 0){let e=n?.renderBefore??null;r._$litPart$=i=new Pl(t.insertBefore(fl(),e),e,void 0,n??{})}return i._$AI(e),i},Vl=`.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));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:var(--vot-shadow-1);transition:box-shadow var(--vot-duration-medium) var(--vot-easing-standard);outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-4)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:none!important;font-weight:500!important}.vot-button:before,.vot-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-button:before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-button:hover:before{opacity:.08}.vot-button:active:after{opacity:.32;background-size:100% 100%;transition:background-size}.vot-button:hover,.vot-button:active{box-shadow:var(--vot-shadow-2)}.vot-button[disabled=true]{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .12);color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);box-shadow:none;cursor:initial}.vot-button[disabled=true]:before,.vot-button[disabled=true]:after{opacity:0}.vot-outlined-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-theme));background-color:#0000;outline:none;font-size:14px;line-height:34px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-4)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:solid 1px var(--vot-border-color)!important;margin:0!important;font-weight:500!important}.vot-outlined-button:before,.vot-outlined-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-outlined-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-outlined-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-outlined-button:hover:before{opacity:.04}.vot-outlined-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-outlined-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-outlined-button[disabled=true]:before,.vot-outlined-button[disabled=true]:after{opacity:0}.vot-text-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-theme));background-color:#0000;outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-2)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:none!important;margin:0!important;font-weight:500!important}.vot-text-button:before,.vot-text-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-text-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-text-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-text-button:hover:before{opacity:.04}.vot-text-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-text-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-text-button[disabled=true]:before,.vot-text-button[disabled=true]:after{opacity:0}.vot-icon-button{--vot-helper-onsurface:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;width:36px;min-width:36px;height:36px;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:#0000;outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:none!important;border-radius:50%!important;margin:0!important;padding:0!important;font-weight:500!important}.vot-icon-button:before,.vot-icon-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-icon-button:before{background-color:var(--vot-helper-onsurface);transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-icon-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-icon-button:hover:before{opacity:.04}.vot-icon-button:active:after{opacity:.32;background-size:100% 100%;transition:background-size}.vot-icon-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);fill:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-icon-button[disabled=true]:before,.vot-icon-button[disabled=true]:after{opacity:0}.vot-icon-button svg{fill:inherit;stroke:inherit;width:24px;height:36px}.vot-hotkey{justify-content:flex-start;align-items:center;gap:var(--vot-space-3,12px);flex-wrap:wrap;display:flex}.vot-hotkey-label{word-break:break-word;max-width:80%}.vot-hotkey-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;background-color:#0000;outline:none;width:fit-content;min-width:32px;height:fit-content;font-size:15px;line-height:1.5;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-2)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:solid 1px var(--vot-border-color)!important;margin:0!important;font-weight:400!important}.vot-hotkey-button:before,.vot-hotkey-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-hotkey-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-hotkey-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-hotkey-button:hover:before{opacity:.04}.vot-hotkey-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-hotkey-button[data-status=active]{color:rgb(var(--vot-helper-theme))}.vot-hotkey-button[data-status=active]:before{opacity:.04}.vot-hotkey-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-hotkey-button[disabled=true]:before,.vot-hotkey-button[disabled=true]:after{opacity:0}.vot-textfield{display:inline-block;--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), .38)!important;--vot-helper-safari2:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;--vot-helper-safari3:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;text-align:start!important;padding-top:6px!important;font-size:16px!important;line-height:1.5!important;position:relative!important}.vot-textfield>:is(input,textarea){box-sizing:border-box!important;border-style:solid!important;border-width:1px!important;border-color:transparent var(--vot-helper-safari2) var(--vot-helper-safari2)!important;width:100%!important;height:inherit!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;-webkit-text-fill-color:currentColor!important;font-family:inherit!important;font-size:inherit!important;line-height:inherit!important;caret-color:var(--vot-helper-theme)!important;background-color:#0000!important;border-radius:4px!important;margin:0!important;padding:15px 13px!important;transition:border .2s,box-shadow .2s!important;box-shadow:inset 1px 0 #0000,inset -1px 0 #0000,inset 0 -1px #0000!important}.vot-textfield>:is(input,textarea):not(:focus):not(:is(.vot-show-placeholder,.vot-show-placeholer))::placeholder{color:#0000!important}.vot-textfield>:is(input,textarea):not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2)!important}.vot-textfield>:is(input,textarea)+span{font-family:inherit;width:100%!important;max-height:100%!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;cursor:text!important;pointer-events:none!important;font-size:75%!important;line-height:15px!important;transition:color .2s,font-size .2s,line-height .2s!important;display:flex!important;position:absolute!important;top:0!important;left:0!important}.vot-textfield>:is(input,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;box-sizing:border-box!important;border-top:solid 1px var(--vot-helper-safari2)!important;pointer-events:none!important;min-width:10px!important;height:8px!important;margin-top:6px!important;transition:border .2s,box-shadow .2s!important;display:block!important;box-shadow:inset 0 1px #0000!important}.vot-textfield>input+span:before,.vot-textfield>textarea+span:before{border-left:1px solid #0000!important;border-radius:4px 0!important;margin-right:4px!important}.vot-textfield>input+span:after,.vot-textfield>textarea+span:after{border-right:1px solid #0000!important;border-radius:0 4px!important;flex-grow:1!important;margin-left:4px!important}.vot-textfield>input:is(.vot-show-placeholder,.vot-show-placeholer)+span:before,.vot-textfield>textarea:is(.vot-show-placeholder,.vot-show-placeholer)+span:before{margin-right:0!important}.vot-textfield>input:is(.vot-show-placeholder,.vot-show-placeholer)+span:after,.vot-textfield>textarea:is(.vot-show-placeholder,.vot-show-placeholer)+span:after{margin-left:0!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:#0000!important}.vot-textfield:hover>input:not(:disabled),.vot-textfield:hover>textarea:not(:disabled){border-color:transparent var(--vot-helper-safari3) var(--vot-helper-safari3)!important}.vot-textfield:hover>input:not(:disabled)+span:before,.vot-textfield:hover>input:not(:disabled)+span:after,.vot-textfield:hover>textarea:not(:disabled)+span:before,.vot-textfield:hover>textarea:not(:disabled)+span:after{border-top-color:var(--vot-helper-safari3)!important}.vot-textfield:hover>input:not(:disabled):not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:disabled):not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3)!important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:transparent 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:transparent var(--vot-helper-safari1) var(--vot-helper-safari1)!important;color:rgba(var(--vot-onsurface-rgb,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,.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:#0000!important}@media not all and (resolution>=.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-checkbox-label-offset:30px;--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;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);text-align:start;font-size:16px;line-height:1.5;display:inline-block;position:relative;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;text-transform:none!important}.vot-checkbox-sub{padding-left:var(--vot-checkbox-label-offset)!important}.vot-checkbox>input{appearance:none;z-index:10000;box-sizing:border-box;opacity:1;cursor:pointer;background:0 0;outline:none;width:18px;height:18px;transition:border-color .2s,background-color .2s;display:block;position:absolute;border:2px solid!important;border-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;border-radius:2px!important;margin:3px 1px!important;padding:0!important}.vot-checkbox>input+span{box-sizing:border-box;width:inherit;cursor:pointer;font-family:inherit;display:inline-block;position:relative;padding-left:var(--vot-checkbox-label-offset)!important;font-weight:400!important}.vot-checkbox>input+span:before{content:"";background-color:rgb(var(--vot-onsurface-rgb,0, 0, 0));opacity:0;pointer-events:none;width:40px;height:40px;transition:opacity .3s,transform .2s;display:block;position:absolute;top:-8px;left:-10px;transform:scale(1);border-radius:50%!important}.vot-checkbox>input+span:after{content:"";z-index:10000;pointer-events:none;width:10px;height:5px;transition:border-color .2s;display:block;position:absolute;top:3px;left:1px;transform:translate(3px,4px)rotate(-45deg);box-sizing:content-box!important;border:0 solid #0000!important;border-width:0 0 2px 2px!important}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{background-color:rgb(var(--vot-helper-theme));border-color:rgb(var(--vot-helper-theme))!important}.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))!important}.vot-checkbox>input:hover{box-shadow:none!important}.vot-checkbox>input:indeterminate+span:after{transform:translate(4px,3px);border-left-width:0!important}.vot-checkbox:hover>input+span:before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input:not(:disabled){border-color:rgb(var(--vot-helper-theme))!important}.vot-checkbox:active>input:checked{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6);border-color:#0000!important}.vot-checkbox:active>input+span:before{opacity:1;transition:transform,opacity;transform:scale(0)}.vot-checkbox>input:disabled{cursor:initial;border-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);border-color:#0000!important}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial}.vot-checkbox>input:disabled+span:before{opacity:0;transform:scale(0)}html.vot-keyboard-nav .vot-checkbox>input:focus-visible{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav .vot-checkbox>input:focus{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}}.vot-slider{flex-direction:column;gap:6px;display:flex;width:100%!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system)!important;text-align:start!important;font-size:16px!important;line-height:1.5!important}.vot-slider>span{order:1;margin:0!important;display:block!important}.vot-slider .vot-slider-label{flex-wrap:wrap;align-items:baseline;gap:6px;width:100%;display:inline-flex}.vot-slider-label-value{font-variant-numeric:tabular-nums;margin-left:0!important;font-weight:500!important}.vot-slider .vot-slider-label-text{min-width:0}.vot-slider>input{order:2;appearance:none!important;cursor:pointer!important;background-color:#0000!important;border:none!important;width:100%!important;height:32px!important;margin:0!important;padding:0!important;display:block!important;position:relative!important;top:0!important}.vot-slider>input:hover{box-shadow:none!important}.vot-slider>input:before{content:""!important;width:calc(100% * var(--vot-progress,0))!important;background:rgb(var(--vot-primary-rgb,33, 150, 243))!important;height:2px!important;display:block!important;position:absolute!important;top:calc(50% - 1px)!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), .38)!important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-slider>input:disabled::-webkit-slider-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)!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)!important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important}.vot-slider>input:focus{outline:none!important}.vot-slider>input::-webkit-slider-runnable-track{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important;border-radius:1px!important;width:100%!important;height:2px!important;margin:15px 0!important}.vot-slider>input::-moz-range-track{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important;border-radius:1px!important;width:100%!important;height:2px!important;margin:15px 0!important}.vot-slider>input::-webkit-slider-thumb{appearance:none!important;background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;width:2px!important;height:2px!important;box-shadow:none!important;border:none!important;border-radius:50%!important;transition:box-shadow .2s!important;transform:scale(6)!important}.vot-slider>input::-moz-range-thumb{appearance:none!important;background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;width:2px!important;height:2px!important;box-shadow:none!important;border:none!important;border-radius:50%!important;transition:box-shadow .2s!important;transform:scale(6)!important}.vot-slider>input::-webkit-slider-thumb{-webkit-appearance:none!important;margin:0!important}.vot-slider>input::-moz-range-progress{background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;border-radius:1px!important;height:2px!important}.vot-slider>input:focus:not(:focus-visible)::-webkit-slider-thumb{box-shadow:none!important}.vot-slider>input:focus:not(:focus-visible)::-moz-range-thumb{box-shadow:none!important}html.vot-keyboard-nav .vot-slider>input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}html.vot-keyboard-nav .vot-slider>input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav .vot-slider>input:focus::-webkit-slider-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}html.vot-keyboard-nav .vot-slider>input:focus::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}}.vot-select{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);--vot-helper-safari1:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6);--vot-helper-safari2:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme);justify-content:space-between;align-items:center;font-size:14px;line-height:1.5;display:flex;font-weight:400!important}.vot-select-outer{cursor:pointer;justify-content:space-between;align-items:center;width:120px;max-width:120px;display:flex;border:1px solid var(--vot-helper-safari1)!important;border-radius:4px!important;padding:0 5px!important;transition:border .2s!important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2)!important}.vot-select-outer[disabled=true]{opacity:.5;cursor:default}.vot-select-outer[disabled=true]:hover{border-color:var(--vot-helper-safari1)!important}.vot-select-title{text-overflow:ellipsis;white-space:nowrap;font-family:inherit;overflow:hidden}.vot-select-arrow-icon{justify-content:center;align-items:center;width:20px;height:32px;display:flex}.vot-select-arrow-icon svg{fill:inherit;stroke:inherit}.vot-select-content-list{flex-direction:column;display:flex}.vot-select-content-list .vot-select-content-item{cursor:pointer;border-radius:8px!important;padding:5px 10px!important}.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), .2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .1)!important}.vot-select-content-list .vot-select-content-item[inert]{cursor:default;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;line-height:1.5;font-weight:700!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{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;-webkit-user-select:text;user-select:text;font-size:16px;line-height:1.5;display:flex}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), .5);flex:1;margin-left:8px!important}.vot-details{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;cursor:pointer;transition:background var(--vot-duration-medium) var(--vot-easing-standard);justify-content:space-between;align-items:center;font-size:16px;line-height:1.5;display:flex;border-radius:.5em!important;margin:-.5em!important;padding:.5em!important}.vot-details-arrow-icon{width:20px;height:32px;fill:rgba(var(--vot-helper-onsurface-rgb), .87);justify-content:center;align-items:center;display:flex;transform:scale(1.25)rotate(-90deg)}.vot-details:hover{background:rgba(var(--vot-onsurface-rgb,0, 0, 0), .06)}.vot-settings-section{border:1px solid var(--vot-border-color);border-radius:var(--vot-radius-l);padding:var(--vot-space-2);background:rgba(var(--vot-helper-onsurface-rgb), .03);flex-direction:column;display:flex}.vot-settings-section>*{margin:0!important}.vot-settings-section>*+*{margin-top:var(--vot-space-2)!important}.vot-settings-section-header{border-radius:var(--vot-radius-m);margin:0!important;padding:.45em .5em!important}.vot-settings-section-header .vot-details-arrow-icon{transition:transform var(--vot-duration-medium) var(--vot-easing-standard)}.vot-settings-section-header[data-open=true] .vot-details-arrow-icon{transform:scale(1.25)rotate(0)}.vot-settings-section-content{--vot-settings-control-width:200px;--vot-settings-row-gap:var(--vot-space-2);padding:0 var(--vot-space-1) var(--vot-space-1);flex-direction:column;display:flex}.vot-settings-section-content>*{margin:0!important}.vot-settings-section-content>*+*{margin-top:var(--vot-settings-row-gap)!important}.vot-settings-section-content>.vot-checkbox,.vot-settings-section-content>.vot-hotkey,.vot-settings-section-content>.vot-textfield,.vot-settings-section-content>.vot-select,.vot-settings-section-content>.vot-slider{padding:var(--vot-space-1);box-sizing:border-box;width:100%!important}.vot-settings-section-content>.vot-textfield{gap:var(--vot-space-1);flex-direction:column;padding-top:0!important;display:flex!important}.vot-settings-section-content>.vot-textfield>span{order:0;width:auto!important;max-height:none!important;color:rgba(var(--vot-helper-onsurface-rgb), .72)!important;cursor:default!important;pointer-events:none!important;font-size:13px!important;line-height:1.2!important;display:block!important;position:static!important}.vot-settings-section-content>.vot-textfield>span:before,.vot-settings-section-content>.vot-textfield>span:after{content:none!important;display:none!important}.vot-settings-section-content>.vot-textfield>input,.vot-settings-section-content>.vot-textfield>textarea{transition:border-color var(--vot-duration-fast) var(--vot-easing-standard), background-color var(--vot-duration-fast) var(--vot-easing-standard);order:1;width:100%!important;height:36px!important;padding:0 var(--vot-space-3)!important;border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-s)!important;background:rgba(var(--vot-helper-onsurface-rgb), .04)!important;color:rgba(var(--vot-helper-onsurface-rgb), .9)!important;-webkit-text-fill-color:currentColor!important;box-shadow:none!important}.vot-settings-section-content>.vot-textfield>textarea{resize:vertical;height:auto!important;min-height:84px!important;padding:var(--vot-space-2) var(--vot-space-3)!important}.vot-settings-section-content>.vot-textfield>input::placeholder,.vot-settings-section-content>.vot-textfield>textarea::placeholder{color:rgba(var(--vot-helper-onsurface-rgb), .55)!important}.vot-settings-section-content>.vot-textfield:hover>input,.vot-settings-section-content>.vot-textfield:hover>textarea{border-color:var(--vot-border-color-hover)!important}.vot-settings-section-content>.vot-textfield>input:not(:focus):placeholder-shown,.vot-settings-section-content>.vot-textfield>textarea:not(:focus):placeholder-shown{border-color:var(--vot-border-color)!important}.vot-settings-section-content>.vot-textfield>input:focus,.vot-settings-section-content>.vot-textfield>textarea:focus{border-color:rgba(var(--vot-primary-rgb), .7)!important}.vot-lang-select{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);color:var(--vot-helper-theme);fill:var(--vot-helper-theme);justify-content:space-between;align-items:center;display:flex}.vot-lang-select-icon{justify-content:center;align-items:center;width:32px;height:32px;display:flex}.vot-lang-select-icon svg{fill:inherit;stroke:inherit}.vot-segmented-button{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);-webkit-user-select:none;user-select:none;background:rgb(var(--vot-surface-rgb,255, 255, 255));max-width:100vw;height:36px;color:var(--vot-helper-theme);fill:var(--vot-helper-theme);cursor:default;transition:opacity var(--vot-duration-slow) var(--vot-easing-standard);z-index:2147483647;align-items:center;font-size:16px;line-height:1.5;display:flex;position:absolute;top:5rem;left:50%;overflow:hidden;transform:translate(-50%);opacity:1!important;pointer-events:auto!important;touch-action:none!important;border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-s)!important;box-shadow:var(--vot-shadow-1)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important}.vot-segmented-button.vot-segmented-button--hidden{opacity:0!important;pointer-events:none!important}.vot-segmented-button *{box-sizing:border-box!important}.vot-segmented-button .vot-separator{background:rgba(var(--vot-helper-theme-rgb), .1);width:1px;height:50%}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{height:100%;color:inherit;transition:background-color var(--vot-duration-fast) var(--vot-easing-standard);-webkit-tap-highlight-color:transparent;background-color:#0000;outline:none;justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden;padding:0 var(--vot-space-2)!important;border:none!important}.vot-segmented-button .vot-segment:focus,.vot-segmented-button .vot-segment-only-icon:focus{box-shadow:inset 0 0 0 2px var(--vot-focus-ring-color);outline:none}.vot-segmented-button .vot-segment:focus:not(:focus-visible),.vot-segmented-button .vot-segment-only-icon:focus:not(:focus-visible){box-shadow:none}.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:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-segmented-button .vot-segment:before,.vot-segmented-button .vot-segment-only-icon:before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-segmented-button .vot-segment:after,.vot-segmented-button .vot-segment-only-icon:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.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}.vot-segmented-button .vot-segment-only-icon{min-width:36px;padding:0!important}.vot-segmented-button .vot-segment-label{white-space:nowrap;color:inherit;margin-left:var(--vot-space-2)!important;font-weight:400!important}.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[data-loading=true] #vot-loading-icon{display:block!important}.vot-segmented-button[data-loading=true] #vot-translate-icon{display:none!important}.vot-segmented-button[data-direction=column]{flex-direction:column;height:fit-content}.vot-segmented-button[data-direction=column] .vot-segment-label{display:none}.vot-segmented-button[data-direction=column]>.vot-segment-only-icon,.vot-segmented-button[data-direction=column]>.vot-segment{padding:8px!important}.vot-segmented-button[data-direction=column] .vot-separator{width:50%;height:1px}.vot-segmented-button[data-position=left]{top:12.5vh;left:50px}.vot-segmented-button[data-position=right]{top:12.5vh;left:auto;right:0}.vot-segmented-button svg{width:24px;fill:inherit;stroke:inherit}.vot-tooltip{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);--vot-helper-ondialog:rgb(var(--vot-ondialog-rgb,37, 38, 40));--vot-helper-border:rgb(var(--vot-tooltip-border,69, 69, 69));-webkit-user-select:none;user-select:none;background:rgb(var(--vot-surface-rgb,255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);cursor:default;z-index:2147483647;opacity:0;align-items:center;width:max-content;max-width:calc(100vw - 10px);height:max-content;font-size:14px;line-height:1.5;transition:opacity .5s;display:flex;position:absolute;inset:0;overflow:hidden;box-shadow:0 1px 3px #0000001f;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border-radius:4px!important;padding:4px 8px!important}.vot-tooltip[data-trigger=click]{-webkit-user-select:text;user-select:text}.vot-tooltip.vot-tooltip-bordered{border:1px solid var(--vot-helper-border)}.vot-tooltip *{box-sizing:border-box!important;font-family:inherit!important}.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), .87);--vot-settings-control-width:clamp(120px, 45%, 200px);-webkit-user-select:none;user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);cursor:default;z-index:2147483646;visibility:visible;opacity:1;transform-origin:top;width:fit-content;min-width:320px;max-width:min(90vw,560px);transition:opacity var(--vot-duration-medium) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);font-size:16px;line-height:1.5;position:absolute;top:calc(5rem + 48px);left:50%;overflow:hidden;transform:translate(-50%)scale(1);border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-m)!important;box-shadow:var(--vot-shadow-2)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important}.vot-menu *{box-sizing:border-box!important}.vot-menu[hidden]{pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%,-4px)scale(.98);display:block!important}.vot-menu-content-wrapper{min-width:320px;min-height:100px;max-height:calc(var(--vot-container-height,75vh) - (5rem + 32px + 16px) * 2);flex-direction:column;display:flex;overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:center;min-height:31px;display:flex;padding-inline-end:var(--vot-space-2)!important}.vot-menu-header-container:empty{padding:0 0 16px!important}.vot-menu-header-container>.vot-icon-button{margin-inline-end:var(--vot-space-1)!important;margin-top:var(--vot-space-1)!important}.vot-menu-title-container{font-size:inherit;text-align:start;outline:0;flex:1;display:flex;font-weight:inherit!important;margin:0!important}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding:var(--vot-space-4)!important;font-weight:500!important}.vot-menu-body-container{box-sizing:border-box;gap:var(--vot-space-2);overscroll-behavior:contain;flex-direction:column;min-height:1.375rem;display:flex;overflow:auto;padding:0 var(--vot-space-4)!important;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), .1) var(--vot-helper-surface)!important}.vot-menu-body-container::-webkit-scrollbar{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-menu-body-container::-webkit-scrollbar-track{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-menu-body-container::-webkit-scrollbar-thumb{border-radius:1ex;background:rgba(var(--vot-helper-onsurface-rgb), .1)!important;border:5px solid var(--vot-helper-surface)!important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border-width:3px!important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface)!important}.vot-menu-footer-container{flex-shrink:0;justify-content:flex-end;display:flex;padding:var(--vot-space-4)!important}.vot-menu-footer-container:empty{padding:var(--vot-space-4) 0 0 0!important}.vot-menu .vot-select--labeled>.vot-select-outer{margin-left:auto}.vot-menu[data-position=left]{transform-origin:0;top:12.5vh;left:240px}.vot-menu[data-position=right]{transform-origin:100%;top:12.5vh;left:auto;right:-80px}.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), .87);--vot-dialog-viewport-margin:16px;--vot-dialog-max-height:75vh;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width,512px), 100%);border:1px solid var(--vot-border-color);border-radius:var(--vot-radius-l);background-color:var(--vot-helper-surface);height:fit-content;color:var(--vot-helper-onsurface);box-shadow:var(--vot-shadow-2);-webkit-user-select:none;user-select:none;visibility:visible;opacity:1;transform-origin:50%;transition:opacity var(--vot-duration-medium) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);font-size:16px;line-height:1.5;display:block;position:fixed;inset-block:0;inset-inline:0;overflow:auto hidden;transform:scale(1);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;margin:auto!important;padding:0!important}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transition:opacity var(--vot-duration-fast) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);transform:translateY(-4px)scale(.98)}.vot-dialog[data-vertical-align=top]{inset-block-start:var(--vot-dialog-viewport-margin);inset-block-end:auto;margin:0 auto!important}.vot-dialog-container{visibility:visible;z-index:2147483647;position:absolute}.vot-dialog-container[hidden]{pointer-events:none;visibility:hidden;display:block!important}.vot-dialog-container *{box-sizing:border-box!important}.vot-dialog-backdrop{opacity:1;background-color:#0009;transition:opacity .3s;position:fixed;inset:0}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog-content-wrapper{max-height:var(--vot-dialog-max-height,75vh);flex-direction:column;display:flex;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;min-height:31px;display:flex}.vot-dialog-header-container:empty{padding:0 0 20px}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:var(--vot-space-1)!important;margin-top:var(--vot-space-1)!important}.vot-dialog-title-container{font-size:inherit;outline:0;flex:1;display:flex;font-weight:inherit!important;margin:0!important}.vot-dialog-title{flex:1;font-size:115.385%;line-height:1;padding:var(--vot-space-5) var(--vot-space-5) var(--vot-space-4)!important;font-weight:700!important}.vot-dialog-body-container{box-sizing:border-box;gap:var(--vot-space-4);overscroll-behavior:contain;flex-direction:column;min-height:1.375rem;display:flex;overflow:auto;padding:0 var(--vot-space-5)!important;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), .1) var(--vot-helper-surface)!important}.vot-dialog-body-container::-webkit-scrollbar{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-dialog-body-container::-webkit-scrollbar-track{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-dialog-body-container::-webkit-scrollbar-thumb{border-radius:1ex;background:rgba(var(--vot-helper-onsurface-rgb), .1)!important;border:5px solid var(--vot-helper-surface)!important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border-width:3px!important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface)!important}.vot-dialog-footer-container{justify-content:flex-end;gap:var(--vot-space-2);flex-wrap:wrap;flex-shrink:0;display:flex;padding:var(--vot-space-4)!important}.vot-dialog-footer-container:empty{padding:var(--vot-space-5) 0 0 0!important}@media (width<=480px){.vot-dialog-footer-container{flex-direction:column;align-items:stretch}.vot-dialog-footer-container>:is(.vot-button,.vot-outlined-button,.vot-text-button){white-space:normal;text-overflow:clip;text-align:center;justify-content:center;align-items:center;width:100%;height:auto;min-height:36px;padding:8px 16px;line-height:1.2;display:flex;overflow:visible}}.vot-inline-loader{aspect-ratio:5;--vot-loader-bg:no-repeat radial-gradient(farthest-side, rgba(var(--vot-onsurface-rgb,0, 0, 0), .38) 94%, transparent);background:var(--vot-loader-bg), var(--vot-loader-bg), var(--vot-loader-bg), var(--vot-loader-bg);background-size:20% 100%;height:8px;animation:.75s infinite alternate dotsSlide,1.5s infinite alternate dotsFlip}.vot-loader-progress{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));fill:none;stroke:rgb(var(--vot-helper-theme));stroke-width:2px;stroke-linecap:round;transform-origin:50%;transform:rotate(-90deg)}@keyframes dotsSlide{0%,10%{background-position:0 0,0 0,0 0,0 0}33%{background-position:0 0,33.3333% 0,33.3333% 0,33.3333% 0}66%{background-position:0 0,33.3333% 0,66.6667% 0,66.6667% 0}90%,to{background-position:0 0,33.3333% 0,66.6667% 0,100% 0}}@keyframes dotsFlip{0%,49.99%{transform:scale(1)}50%,to{transform:scale(-1)}}.vot-label{font-family:inherit;font-size:16px;line-height:1.5;display:block}.vot-label-text{display:inline}.vot-label-icon{vertical-align:text-bottom;cursor:help;justify-content:center;align-items:center;width:20px;height:20px;margin-left:4px;display:inline-flex}.vot-label-icon>svg{width:20px;height:20px;display:block}.vot-account{justify-content:space-between;align-items:center;gap:1rem;display:flex}.vot-account-container,.vot-account-wrapper,.vot-account-buttons{align-items:center;gap:1rem;display:flex}.vot-account-avatar{min-width:36px;max-width:36px;min-height:36px;max-height:36px;overflow:hidden}.vot-account-avatar-img{object-fit:cover;border-radius:50%;width:36px;height:36px}@property --vot-subtitles-opacity{syntax:"";inherits:true;initial-value:.8}@property --vot-subtitles-scale-compensation{syntax:"";inherits:true;initial-value:1}.vot-subtitles{--vot-subtitles-background:rgba(var(--vot-surface-rgb,46, 47, 52), var(--vot-subtitles-opacity,.8));--vot-subtitles-effective-max-width:var(--vot-subtitles-max-width,var(--vot-subtitles-smart-max-width,70vw));max-width:var(--vot-subtitles-effective-max-width);max-inline-size:var(--vot-subtitles-effective-max-width);background:var(--vot-subtitles-background,#2e2f34cc);width:max-content;inline-size:max-content;color:var(--vot-subtitles-color,#e3e3e3);pointer-events:all;touch-action:none;font-size:calc(var(--vot-subtitles-font-size,clamp(18px, var(--vot-subtitles-smart-font-preferred,2.2vw), 50px)) * var(--vot-subtitles-scale-compensation,1));-webkit-text-stroke:var(--vot-subtitles-text-stroke-width,clamp(1px, .08em, 2px)) var(--vot-subtitles-text-stroke-color,#000000eb);paint-order:stroke fill;text-shadow:var(--vot-subtitles-text-shadow,0 1px 2px #00000073, 0 2px 8px #00000040);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-synthesis:none;position:relative;--vot-subtitles-font-family:var(--vot-subtitles-font-family-custom,var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif))!important;font-family:var(--vot-subtitles-font-family)!important;font-style:normal!important;font-weight:var(--vot-subtitles-font-weight,500)!important;text-transform:none!important;letter-spacing:normal!important;border-radius:.5em!important;padding:.5em .75em!important;line-height:1.25!important}.vot-subtitles,.vot-subtitles *{-webkit-text-stroke:inherit;paint-order:inherit;font-family:var(--vot-subtitles-font-family)!important}.vot-subtitles{box-sizing:border-box;-webkit-user-select:none;user-select:none;contain:layout paint;isolation:isolate;text-align:center;text-wrap:balance;white-space:normal;overflow-wrap:anywhere;unicode-bidi:plaintext;margin:0 auto;display:block}.vot-subtitles-widget{--vot-subtitles-anchor-width:100vw;--vot-subtitles-anchor-height:100vh;--vot-subtitles-effective-max-width:var(--vot-subtitles-max-width,var(--vot-subtitles-smart-max-width,70vw));--vot-subtitles-smart-target-width:48ch;--vot-subtitles-smart-min-width-ratio:.62;--vot-subtitles-smart-max-width-ratio:.78;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0333);--vot-subtitles-smart-max-width:clamp(calc(var(--vot-subtitles-anchor-width) * var(--vot-subtitles-smart-min-width-ratio)), var(--vot-subtitles-smart-target-width), calc(var(--vot-subtitles-anchor-width) * var(--vot-subtitles-smart-max-width-ratio)));box-sizing:border-box;z-index:2147483647;--vot-subtitles-fallback-bottom-inset:calc(env(safe-area-inset-bottom,0px) + clamp(56px, 10vh, 220px) + 10px);left:50%;top:calc(100% - var(--vot-subtitles-fallback-bottom-inset));width:max-content;inline-size:max-content;max-width:var(--vot-subtitles-effective-max-width);max-inline-size:var(--vot-subtitles-effective-max-width);pointer-events:none;will-change:left, top, transform;max-height:100%;display:block;position:absolute;transform:translate(-50%,-100%)}.vot-subtitles-info{flex-direction:column;gap:2px;max-width:100%;display:flex;padding:6px!important}.vot-subtitles-info-service,.vot-subtitles-info-header,.vot-subtitles-info-context{overflow-wrap:anywhere;word-break:break-word;white-space:normal!important}.vot-subtitles-info-service{color:var(--vot-subtitles-context-color,#86919b);margin-bottom:8px!important;font-size:10px!important;line-height:1!important}.vot-subtitles-info-header{color:var(--vot-subtitles-header-color,#fff);margin-bottom:6px!important;font-size:20px!important;font-weight:500!important;line-height:1!important}.vot-subtitles-info-context{color:var(--vot-subtitles-context-color,#86919b);font-size:12px!important;line-height:1.2!important}.vot-subtitles span[data-vot-highlight-index].passed{color:var(--vot-subtitles-passed-color,#2196f3)}.vot-subtitles span[data-vot-token="1"]{cursor:pointer;white-space:normal;overflow-wrap:inherit;word-break:normal;position:relative;font-size:inherit!important;font-family:inherit!important;font-style:inherit!important;font-weight:inherit!important;line-height:inherit!important;text-transform:inherit!important;text-decoration:none!important}.vot-subtitles span[data-vot-token="1"]:before{content:"";z-index:-1;position:absolute;inset:2px -2px;border-radius:4px!important}.vot-subtitles span[data-vot-token="1"]:hover:before{background:var(--vot-subtitles-hover-color,#ffffff8c)}.vot-subtitles span[data-vot-token="1"].selected:before{background:var(--vot-subtitles-passed-color,#2196f3)}.vot-subtitles span[data-vot-style-italic="1"]{font-style:italic!important}.vot-subtitles span[data-vot-style-bold="1"]{font-weight:700!important}.vot-subtitles span[data-vot-style-underline="1"]{text-decoration:underline!important}.vot-subtitles span[data-vot-style-color="1"]{color:var(--vot-subtitles-inline-color)!important}.vot-subtitles-layer{pointer-events:none;z-index:2147483647;contain:layout paint;width:100vw!important;height:100vh!important;position:fixed!important;inset:0!important}.vot-subtitles-guides{pointer-events:none;z-index:2147483646;position:absolute;inset:0}.vot-subtitles-guide{background:rgba(var(--vot-primary-rgb,33, 150, 243), .7);box-shadow:0 0 0 1px rgba(var(--vot-primary-rgb,33, 150, 243), .12);opacity:0;transition:opacity .12s linear;position:absolute}.vot-subtitles-guide[data-visible=true]{opacity:1}.vot-subtitles-guide--vertical{width:2px;transform:translate(-50%)}.vot-subtitles-guide--horizontal{height:2px;transform:translateY(-50%)}@media (aspect-ratio<=1){.vot-subtitles-widget{--vot-subtitles-smart-target-width:28ch;--vot-subtitles-smart-min-width-ratio:.8;--vot-subtitles-smart-max-width-ratio:.92;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0296)}}@media (aspect-ratio>=1) and (aspect-ratio<=7/5){.vot-subtitles-widget{--vot-subtitles-smart-target-width:32ch;--vot-subtitles-smart-min-width-ratio:.55;--vot-subtitles-smart-max-width-ratio:.9;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0333)}}@media (width<=900px) and (pointer:coarse){.vot-subtitles-widget{--vot-subtitles-fallback-bottom-inset:env(safe-area-inset-bottom,0px)}}@media (prefers-contrast:more){.vot-subtitles{--vot-subtitles-background:rgba(var(--vot-surface-rgb,46, 47, 52), .92);--vot-subtitles-text-stroke-width:max(2px, .1em);--vot-subtitles-text-shadow:0 2px 10px #0000008c}}:is(:fullscreen .vot-subtitles-widget,:fullscreen .vot-subtitles-widget){--vot-subtitles-smart-max-width-ratio:.8}:is(:fullscreen .vot-subtitles,:fullscreen .vot-subtitles){font-size:calc(var(--vot-subtitles-font-size,clamp(18px, var(--vot-subtitles-smart-font-preferred,2vw), 50px)) * var(--vot-subtitles-fullscreen-scale,1) * .95 * var(--vot-subtitles-scale-compensation,1))}#vot-subtitles-info.vot-subtitles-info *{-webkit-user-select:text!important;user-select:text!important}:root{--vot-font-family:"Roboto", "Segoe UI", system-ui, sans-serif;--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-color:rgb(var(--vot-onsurface-rgb,227, 227, 227));--vot-subtitles-passed-color:rgb(var(--vot-primary-rgb,33, 150, 243));--vot-space-1:4px;--vot-space-2:8px;--vot-space-3:12px;--vot-space-4:16px;--vot-space-5:20px;--vot-space-6:24px;--vot-radius-xs:6px;--vot-radius-s:10px;--vot-radius-m:14px;--vot-radius-l:18px;--vot-border-color:rgba(var(--vot-onsurface-rgb,227, 227, 227), .14);--vot-border-color-hover:rgba(var(--vot-onsurface-rgb,227, 227, 227), .22);--vot-shadow-1:0 1px 2px #0000002e, 0 8px 24px #00000024;--vot-shadow-2:0 2px 4px #00000038, 0 12px 32px #00000038;--vot-duration-fast:.12s;--vot-duration-medium:.2s;--vot-duration-slow:.32s;--vot-easing-standard:cubic-bezier(.4, 0, .2, 1);--vot-focus-ring-color:rgba(var(--vot-primary-rgb,139, 180, 245), .9);--vot-focus-ring:0 0 0 2px var(--vot-focus-ring-color);--vot-focus-ring-offset:0 0 0 4px rgba(var(--vot-surface-rgb,32, 33, 36), .9)}vot-block,vot-block *{box-sizing:border-box;-webkit-tap-highlight-color:transparent}vot-block[hidden]:not(.vot-menu):not(.vot-dialog-container),vot-block [hidden]:not(.vot-menu):not(.vot-dialog-container){display:none!important}vot-block{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;display:block;--vot-font-family:"Roboto", "Segoe UI", system-ui, sans-serif!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;visibility:visible!important;font-weight:400!important}vot-block *{font-weight:inherit!important}.vot-portal-local,.vot-subtitles-widget{isolation:isolate}vot-block:focus,vot-block :focus{box-shadow:none!important;outline:none!important}html.vot-keyboard-nav vot-block:focus-visible,html.vot-keyboard-nav vot-block :focus-visible{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav vot-block:focus,html.vot-keyboard-nav vot-block :focus{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}}@media (prefers-reduced-motion:reduce){.vot-portal-local *,.vot-portal *,.vot-subtitles-widget *{scroll-behavior:auto!important;transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}.vot-portal{display:inline}.vot-portal-local{z-index:2147483647;position:fixed;top:0;left:0}`;function Hl(e){let t=globalThis.GM_addStyle;if(typeof t==`function`)return t(e);let n=document.createElement(`style`);return n.textContent=e,(document.head||document.documentElement).appendChild(n),n}Hl(Vl);function Ul(){if(globalThis.__votKeyboardNavInitialized)return;globalThis.__votKeyboardNavInitialized=!0;let e=document.documentElement,t=`vot-keyboard-nav`,n=()=>e.classList.add(t),r=()=>e.classList.remove(t);globalThis.addEventListener(`keydown`,e=>{e.key===`Tab`&&n()},!0);for(let e of[`pointerdown`,`mousedown`,`touchstart`])globalThis.addEventListener(e,r,{capture:!0,passive:!0})}Ul();var J={makeButtonLike(e,{ariaLabel:t}={}){e.setAttribute(`role`,`button`),e.hasAttribute(`tabindex`)||(e.tabIndex=0);let n=e.tabIndex,r=()=>{e.getAttribute(`disabled`)===`true`?(e.setAttribute(`aria-disabled`,`true`),e.tabIndex=-1):(e.removeAttribute(`aria-disabled`),e.tabIndex=n)};return r(),new MutationObserver(()=>r()).observe(e,{attributes:!0,attributeFilter:[`disabled`]}),t&&e.setAttribute(`aria-label`,t),e.addEventListener(`keydown`,t=>{e.getAttribute(`disabled`)===`true`||e.getAttribute(`aria-disabled`)===`true`||(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),e.click())}),e},createEl(e,t=[],n=null){let r=document.createElement(e);return t.length&&r.classList.add(...t),n!==null&&r.append(n),r},createHeader(e,t=4){return J.createEl(`vot-block`,[`vot-header`,`vot-header-level-${t}`],e)},createInformation(e,t){let n=J.createEl(`vot-block`,[`vot-info`]),r=J.createEl(`vot-block`);q(e,r);let i=J.createEl(`vot-block`);return q(t,i),n.append(r,i),{container:n,header:r,value:i}},createButton(e){let t=J.createEl(`vot-block`,[`vot-button`],e);return J.makeButtonLike(t)},createTextButton(e){let t=J.createEl(`vot-block`,[`vot-text-button`],e);return J.makeButtonLike(t)},createOutlinedButton(e){let t=J.createEl(`vot-block`,[`vot-outlined-button`],e);return J.makeButtonLike(t)},createIconButton(e,t={}){let n=J.createEl(`vot-block`,[`vot-icon-button`]);return q(e,n),J.makeButtonLike(n,t)},createInlineLoader(){return J.createEl(`vot-block`,[`vot-inline-loader`])},createPortal(e=!1){return J.createEl(`vot-block`,[`vot-portal${e?`-local`:``}`])},createSubtitleInfo(e,t,n){let r=J.createEl(`vot-block`,[`vot-subtitles-info`]);r.id=`vot-subtitles-info`;let i=J.createEl(`vot-block`,[`vot-subtitles-info-service`],V.get(`VOTTranslatedBy`).replace(`{0}`,n)),a=J.createEl(`vot-block`,[`vot-subtitles-info-header`],e),o=J.createEl(`vot-block`,[`vot-subtitles-info-context`],t);return r.append(i,a,o),{container:r,translatedWith:i,header:a,context:o}}},Wl=[`left`,`top`,`right`,`bottom`],Gl=[`hover`,`click`],Y=class e{showed=!1;target;anchor;content;position;preferredPosition;trigger;parentElement;layoutRoot;offsetX;offsetY;_hidden;autoLayout;pageWidth;pageHeight;globalOffsetX;globalOffsetY;maxWidth;backgroundColor;borderRadius;_bordered;container;onResizeObserver;intersectionObserver;scrollListening=!1;positionRafId=null;destroyFallbackTimerId;static DESTROY_FALLBACK_MS=700;tooltipId=typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`vot-tooltip-${Math.random().toString(36).slice(2)}`;prevAriaDescribedBy=null;constructor({target:t,anchor:n=void 0,content:r=``,position:i=`top`,trigger:a=`hover`,offset:o=4,maxWidth:s=void 0,hidden:c=!1,autoLayout:l=!0,backgroundColor:u=void 0,borderRadius:d=void 0,bordered:f=!0,parentElement:p=document.body,layoutRoot:m=document.documentElement}){if(!(t instanceof HTMLElement))throw TypeError(`target must be a valid HTMLElement`);this.target=t,this.anchor=n instanceof HTMLElement?n:t,this.content=r,typeof o==`number`?this.offsetY=this.offsetX=o:(this.offsetX=o.x,this.offsetY=o.y),this._hidden=c,this.autoLayout=l,this.trigger=e.validateTrigger(a)?a:`hover`,this.position=e.validatePos(i)?i:`top`,this.preferredPosition=this.position,this.parentElement=p,this.layoutRoot=m,this.borderRadius=d,this._bordered=f,this.maxWidth=s,this.backgroundColor=u,this.updatePageSize(),this.init()}static validatePos(e){return Wl.includes(e)}static validateTrigger(e){return Gl.includes(e)}setPosition(t){return this.preferredPosition=e.validatePos(t)?t:`top`,this.position=this.preferredPosition,this.schedulePositionUpdate(),this}setContent(e){return this.content=e,this.container?(this.container.replaceChildren(),typeof e==`string`?this.container.textContent=e:this.container.append(e),this.schedulePositionUpdate(),this):this}updateMount({parentElement:e,layoutRoot:t}){return e&&this.parentElement!==e&&(this.parentElement=e,this.container?.isConnected&&e.appendChild(this.container)),t&&this.layoutRoot!==t&&(this.layoutRoot=t),this.schedulePositionUpdate(),this}onResize=()=>{this.schedulePositionUpdate()};onClick=()=>{this.showed?this.destroy():this.create()};onTargetKeyDown=e=>{e.key!==`Escape`||!this.showed||this.destroy()};onScroll=()=>{this.schedulePositionUpdate()};onHoverPointerDown=e=>{e.pointerType!==`mouse`&&this.create()};onHoverPointerUp=e=>{e.pointerType!==`mouse`&&this.destroy()};onMouseEnter=()=>{this.create()};onMouseLeave=e=>{this.isInTooltipContext(e.relatedTarget)||this.destroy()};onTooltipMouseLeave=e=>{this.isInTooltipContext(e.relatedTarget)||this.destroy()};isInTooltipContext(e){return e instanceof Node?this.target.contains(e)||this.container?.contains(e):!1}updatePageSize(){if(this.layoutRoot===document.documentElement)this.globalOffsetX=0,this.globalOffsetY=0;else{let{left:e,top:t}=this.layoutRoot.getBoundingClientRect();this.globalOffsetX=e,this.globalOffsetY=t}return this.pageWidth=this.layoutRoot.clientWidth||document.documentElement.clientWidth,this.pageHeight=this.layoutRoot.clientHeight||document.documentElement.clientHeight,this}onIntersect=([e])=>{if(!e.isIntersecting)return this.destroy(!0)};init(){return this.onResizeObserver=new ResizeObserver(this.onResize),this.intersectionObserver=new IntersectionObserver(this.onIntersect),this.target.addEventListener(`keydown`,this.onTargetKeyDown),this.trigger===`click`?(this.target.addEventListener(`pointerdown`,this.onClick),this):(this.target.addEventListener(`mouseenter`,this.onMouseEnter),this.target.addEventListener(`mouseleave`,this.onMouseLeave),this.target.addEventListener(`focusin`,this.onMouseEnter),this.target.addEventListener(`focusout`,this.onMouseLeave),this.target.addEventListener(`pointerdown`,this.onHoverPointerDown),this.target.addEventListener(`pointerup`,this.onHoverPointerUp),this)}release(){return this.destroy(!0),this.detachScrollListener(),this.target.removeEventListener(`keydown`,this.onTargetKeyDown),this.trigger===`click`?(this.target.removeEventListener(`pointerdown`,this.onClick),this):(this.target.removeEventListener(`mouseenter`,this.onMouseEnter),this.target.removeEventListener(`mouseleave`,this.onMouseLeave),this.target.removeEventListener(`focusin`,this.onMouseEnter),this.target.removeEventListener(`focusout`,this.onMouseLeave),this.target.removeEventListener(`pointerdown`,this.onHoverPointerDown),this.target.removeEventListener(`pointerup`,this.onHoverPointerUp),this)}schedulePositionUpdate(){this.container&&this.positionRafId===null&&(this.positionRafId=requestAnimationFrame(()=>{this.positionRafId=null,this.updatePageSize(),this.updatePos()}))}cancelPositionUpdate(){this.positionRafId!==null&&(cancelAnimationFrame(this.positionRafId),this.positionRafId=null)}clearDestroyFallbackTimer(){this.destroyFallbackTimerId!==void 0&&(globalThis.clearTimeout(this.destroyFallbackTimerId),this.destroyFallbackTimerId=void 0)}create(){return this.destroy(!0),this.showed=!0,this.container=J.createEl(`vot-block`,[`vot-tooltip`],this.content),this.bordered&&this.container.classList.add(`vot-tooltip-bordered`),this.container.setAttribute(`role`,`tooltip`),this.container.id=this.tooltipId,this.container.dataset.trigger=this.trigger,this.container.dataset.position=this.position,this.parentElement.appendChild(this.container),this.schedulePositionUpdate(),this.backgroundColor!==void 0&&(this.container.style.backgroundColor=this.backgroundColor),this.borderRadius!==void 0&&(this.container.style.borderRadius=`${this.borderRadius}px`),this.hidden?this.container.hidden=!0:this.syncAriaDescribedBy(!0),this.container.style.opacity=`1`,this.trigger===`hover`&&this.container.addEventListener(`mouseleave`,this.onTooltipMouseLeave),this.attachScrollListener(),this.onResizeObserver?.observe(this.layoutRoot),this.anchor!==this.layoutRoot&&this.onResizeObserver?.observe(this.anchor),this.intersectionObserver?.observe(this.target),this}updatePos(){if(!this.container)return this;let{top:e,left:t}=this.calcPos(this.autoLayout,this.preferredPosition),n=Math.max(0,this.pageWidth-this.offsetX*2),r=R(this.maxWidth??n,0,n);return this.container.style.transform=`translate(${t}px, ${e}px)`,this.container.dataset.position=this.position,this.container.style.maxWidth=`${r}px`,this}calcPos(e=!0,t=this.preferredPosition){if(!this.container)return{top:0,left:0};let{left:n,right:r,top:i,bottom:a,width:o,height:s}=this.anchor.getBoundingClientRect(),{width:c,height:l}=this.container.getBoundingClientRect(),u=R(c,0,this.pageWidth),d=R(l,0,this.pageHeight),f={left:n-this.globalOffsetX,right:r-this.globalOffsetX,top:i-this.globalOffsetY,bottom:a-this.globalOffsetY,anchorWidth:o,anchorHeight:s},p={width:u,height:d},m=this.resolveTooltipPosition(f,p,t,e),h=this.getTooltipCoordinates(f,p,m);return this.position=m,{top:h.top+this.globalOffsetY,left:h.left+this.globalOffsetX}}resolveTooltipPosition(e,t,n,r){if(!r)return n;switch(n){case`top`:return R(e.top-t.height-this.offsetY,0,this.pageHeight)+this.offsetYthis.pageWidth-this.offsetX?`left`:`right`;case`bottom`:return R(e.bottom+this.offsetY,0,this.pageHeight-t.height)+t.height>this.pageHeight-this.offsetY?`top`:`bottom`;case`left`:return Math.max(0,e.left-t.width-this.offsetX)+t.width>e.left-this.offsetX?`right`:`left`;default:return n}}getTooltipCoordinates(e,t,n){switch(n){case`top`:return{top:R(e.top-t.height-this.offsetY,0,this.pageHeight),left:R(e.left-t.width/2+e.anchorWidth/2,this.offsetX,this.pageWidth-t.width-this.offsetX)};case`right`:return{top:R(e.top+(e.anchorHeight-t.height)/2,this.offsetY,this.pageHeight-t.height-this.offsetY),left:R(e.right+this.offsetX,0,this.pageWidth-t.width)};case`bottom`:return{top:R(e.bottom+this.offsetY,0,this.pageHeight-t.height),left:R(e.left-t.width/2+e.anchorWidth/2,this.offsetX,this.pageWidth-t.width-this.offsetX)};case`left`:return{top:R(e.top+(e.anchorHeight-t.height)/2,this.offsetY,this.pageHeight-t.height-this.offsetY),left:Math.max(0,e.left-t.width-this.offsetX)};default:return{top:0,left:0}}}destroy(t=!1){if(!this.container)return this;let n=this.container;if(this.cancelPositionUpdate(),this.clearDestroyFallbackTimer(),this.showed=!1,this.syncAriaDescribedBy(!1),this.onResizeObserver?.disconnect(),this.intersectionObserver?.disconnect(),this.detachScrollListener(),t)return n.remove(),this.container=void 0,this;n.removeEventListener(`mouseleave`,this.onTooltipMouseLeave),n.style.pointerEvents=`none`,n.style.opacity=`0`;let r=()=>{this.clearDestroyFallbackTimer(),n?.remove(),this.container===n&&(this.container=void 0)};return n.addEventListener(`transitionend`,r,{once:!0}),n.addEventListener(`transitioncancel`,r,{once:!0}),this.destroyFallbackTimerId=globalThis.setTimeout(r,e.DESTROY_FALLBACK_MS),this}syncAriaDescribedBy(e){let t=this.target.getAttribute(`aria-describedby`);if(this.prevAriaDescribedBy??=t,!e){this.prevAriaDescribedBy===null?this.target.removeAttribute(`aria-describedby`):this.target.setAttribute(`aria-describedby`,this.prevAriaDescribedBy),this.prevAriaDescribedBy=null;return}let n=new Set((t??``).split(/\s+/).filter(Boolean));n.add(this.tooltipId),this.target.setAttribute(`aria-describedby`,Array.from(n).join(` `))}set bordered(e){this._bordered=e,this.container?.classList.toggle(`vot-tooltip-bordered`,e)}get bordered(){return this._bordered}set hidden(e){this._hidden=e,this.container&&(this.container.hidden=e),this.showed&&this.syncAriaDescribedBy(!e)}get hidden(){return this._hidden}attachScrollListener(){this.scrollListening||(this.scrollListening=!0,document.addEventListener(`scroll`,this.onScroll,{passive:!0,capture:!0}))}detachScrollListener(){this.scrollListening&&(this.scrollListening=!1,document.removeEventListener(`scroll`,this.onScroll,{capture:!0}))}};function Kl(e,t){return e>=t.startMs&&e{if(e.tokens.length)return e.tokens;let t=e.text.trim();return t?[{text:t,startMs:e.startMs,durationMs:e.durationMs,isWordLike:!!t}]:[]},Jl=e=>(e.text||ql(e).map(e=>e.text).join(``)).replaceAll(/\s+/gu,` `).trim(),Yl=(e,t)=>{let n=e.startMs+Math.max(0,e.durationMs),r=t.startMs+Math.max(0,t.durationMs);return e.startMs{let t=[];for(let n of e){let e=Jl(n.line);e&&(t.some(t=>e===Jl(t.line)&&t.line.speakerId===n.line.speakerId&&Yl(t.line,n.line))||t.push(n))}return t},Zl=(e,t)=>{let n=0,r=t.length-1,i=-1;for(;n<=r;){let a=n+r>>1;if(t[a].startMs<=e){i=a,n=a+1;continue}r=a-1}return i},Ql=(e,t,n=1/0)=>{let r=Zl(e,t);if(r<0)return[];let i=Number.isFinite(n)?Math.max(0,e-Math.max(0,n)):-1/0,a=[];for(let n=r;n>=0;--n){let r=t[n];if(r.startMs{let r=Ql(e,t,n);if(!r.length)return null;let i=Xl(r.map(e=>({index:e,line:t[e]})));if(!i.length)return null;if(i.length===1){let[e]=i;return{line:e.line,lineKey:`${e.index}`}}let a=[],o=[],s=[],c=[],l=1/0,u=0;for(let e of i){let t=ql(e.line);if(t.length){if(a.length>0){let t=Math.max(l,e.line.startMs);a.push({text:` @@ -271,21 +278,45 @@ var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`} `&&!e[n+1]?.isWordLike;)n+=1;return n},wd=(e,t,n)=>{let r=null,i=1/0;for(let a=0;a=e.length-1)continue;let l=c+1,u=l,d=Sd(e,0,l,t),f=Sd(e,u,e.length,t),p=e.slice(0,l).map(e=>e.text).join(``),m=e.slice(u).map(e=>e.text).join(``),h=Math.max(0,d-n)*12+Math.max(0,f-n)*12+Math.abs(f-d)*.4+(cd(m)?260:0)+(ld(p)?70:0);h{let c=Math.max(0,e-o)*12+Math.max(0,t-o)*12,l=Math.abs(t/Math.max(e,1)-1.08)*120,u=i<2?80:0,d=a<2?80:0,f=cd(r)?260:0,p=ld(n)?70:0,m=s===`strong`?-28:s===`soft`?-14:0;return c+l+u+d+f+p+m};function Ed(e,t,n){if(!e.length||e.reduce((e,t)=>e+Number(t.text===` `),0)>0)return{breakAfterTokenIndices:[]};let{slices:r}=_d(e),i=r.filter(e=>!e.forcesLineBreak);if(!i.length||Sd(e,0,e.length,t)<=n)return{breakAfterTokenIndices:[]};let a=null,o=1/0;for(let r=0;re.text).join(``),secondText:e.slice(d).map(e=>e.text).join(``),firstWordCount:r+1,secondWordCount:i.length-(r+1),maxWidthPx:n,boundary:s.boundary});fthis.onPointerDown(e),this.onPointerUpBound=e=>this.onPointerUp(e),this.onPointerMoveBound=e=>this.onPointerMove(e),this.onPlaybackStateChangeBound=()=>this.handlePlaybackStateChange(),this.onVisualViewportChangeBound=()=>this.scheduleReposition(),this.checkerUnsubscribe=this.intervalIdleChecker.subscribe(()=>{this.onCheckerTick()}),this.bindEvents()}updateMount({container:e,tooltipLayoutRoot:t}){let n=this.container!==e,r=this.tooltipLayoutRoot!==t;this.container=e,this.fullscreenLayerController.updateContainer(e),this.tooltipLayoutRoot=t,this.syncWidgetMount(),(n||r)&&this.tokenTooltip?.updateMount({parentElement:this.getTokenTooltipParentElement(),layoutRoot:this.tooltipLayoutRoot??document.documentElement}),this.subtitles&&(this.insetCacheReady=!1,this.lastAppliedLeftPct=null,this.lastAppliedTopPct=null,this.updateContainerRect(),this.requestUpdate())}resetTranslationContext(e=!1){this.strTranslatedTokens=``,e&&this.releaseTooltip()}resetSegmentationMemo(){this.tokenProcessingMemo=null,this.tokenPrecomputeMemo=null,this.lineMeasureMemo=null,this.lastSegmentIndex=0}resetWrapMemo(){this.setBreakAfterTokenIndices([]),this.lastWrapKey=null}resetRenderMemo(){this.lastRenderKey=null}computeAnchorBoxLayout(e){let t={left:0,top:0,w:e.w,h:e.h},n=this.video;if(!n)return t;let r=n.getBoundingClientRect();if(!(r.width>0&&r.height>0))return t;let i=e.rect;if(!(r.right>i.left&&r.lefti.top&&r.top0&&o>0))return t;let s=(r.left-i.left)/e.scaleX,c=(r.top-i.top)/e.scaleY,l=e.w-a,u=e.h-o;return{left:l>=0?Nu(s,0,l):(e.w-a)/2,top:u>=0?Nu(c,0,u):(e.h-o)/2,w:a,h:o}}readSmartCssMetrics(){let e=this.subtitlesBlock;if(!e)return null;let t=getComputedStyle(e),n=Number.parseFloat(t.fontSize),r=Number.parseFloat(t.maxWidth);if(!Number.isFinite(n)||!Number.isFinite(r)||n<=0||r<=0)return null;this.subtitleMaxWidthPx=r;let i=Number.parseFloat(t.paddingLeft)||0,a=Number.parseFloat(t.paddingRight)||0,o=Math.max(0,r-i-a);return o<=0?null:{fontSizePx:n,maxWidthPx:o}}ensureSmartLayout(e){if(!this.smartLayoutEnabled)return null;let t=this.readSmartCssMetrics(),n=t?.fontSizePx??this.smartFontSizePx,r=td(e,t),i=r.maxWidthPx??this.smartMaxWidthPx,a=`${Math.round(n)}|${Math.round(i)}|${Math.round(r.maxWidthPx??0)}`,o=Math.abs(n-this.smartFontSizePx)>.5,s=Math.abs(i-this.smartMaxWidthPx)>.5;return a!==this.lastSmartLayoutKey&&(this.lastSmartLayoutKey=a,this.smartFontSizePx=n,this.smartMaxWidthPx=i,this.resetRenderMemo()),this.setSubtitlesContainerVar(`--vot-subtitles-max-width`,r.maxWidthPx&&r.maxWidthPx>0?`${r.maxWidthPx}px`:null),(o||s)&&this.lastWrapTokens&&(this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute()),r}scheduleReposition(){this.abortController.signal.aborted||this.subtitles&&(this.repositionPending=!0,this.intervalIdleChecker.markActivity(`subtitles-reposition`),this.intervalIdleChecker.requestImmediateTick())}setSubtitlesContainerVar(e,t){let n=this.subtitlesContainer;if(n){if(t===null){n.style.removeProperty(e);return}n.style.setProperty(e,t)}}applyOpacityStyle(){this.setSubtitlesContainerVar(`--vot-subtitles-opacity`,this.opacity)}applyManualFontSizeStyle(){if(!this.smartLayoutEnabled&&this.fontSizeOverridden){this.setSubtitlesContainerVar(`--vot-subtitles-font-size`,`${this.fontSize}px`);return}this.setSubtitlesContainerVar(`--vot-subtitles-font-size`,null)}applyFontFamilyStyle(){let e=this.fontFamily;this.setSubtitlesContainerVar(`--vot-subtitles-font-family-custom`,_u(e)),bu(e,{forceGmXhr:!0,onLoaded:()=>{this.fontFamily===e&&(this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute(),this.scheduleReposition())}})}syncVisualStyleVars(){this.applyOpacityStyle(),this.applyManualFontSizeStyle(),this.applyFontFamilyStyle()}ensureGuidesLayer(){if(this.guidesLayer)return this.guidesLayer;let e=document.createElement(`vot-block`);e.classList.add(`vot-subtitles-guides`);let t=document.createElement(`vot-block`);t.classList.add(`vot-subtitles-guide`,`vot-subtitles-guide--vertical`);let n=document.createElement(`vot-block`);return n.classList.add(`vot-subtitles-guide`,`vot-subtitles-guide--horizontal`),e.append(t,n),this.guidesLayer=e,this.verticalGuide=t,this.horizontalGuide=n,this.hideSnapGuides(),e}hideSnapGuides(){this.verticalGuide?.removeAttribute(`data-visible`),this.horizontalGuide?.removeAttribute(`data-visible`)}updateSnapGuides(e,t){let{showVerticalCenter:n=!1,showHorizontalCenter:r=!1}=t;this.ensureGuidesLayer().isConnected||this.syncGuideLayerMount(),this.verticalGuide&&(this.verticalGuide.style.left=`${e.left+e.w/2}px`,this.verticalGuide.style.top=`${e.top}px`,this.verticalGuide.style.height=`${e.h}px`,n?this.verticalGuide.dataset.visible=`true`:delete this.verticalGuide.dataset.visible),this.horizontalGuide&&(this.horizontalGuide.style.left=`${e.left}px`,this.horizontalGuide.style.top=`${e.top+e.h/2}px`,this.horizontalGuide.style.width=`${e.w}px`,r?this.horizontalGuide.dataset.visible=`true`:delete this.horizontalGuide.dataset.visible)}syncGuideLayerMount(){let e=this.fullscreenLayerController.getWidgetParentElement(),t=this.ensureGuidesLayer();t.parentElement!==e&&e.appendChild(t)}syncWidgetMount(){this.fullscreenLayerController.syncWidgetContainer(this.subtitlesContainer),this.syncGuideLayerMount()}getTokenTooltipParentElement(){let e=this.fullscreenLayerController.getWidgetParentElement();return e===this.container?document.documentElement:e}createSubtitlesContainer(){if(this.subtitlesContainer)return this.subtitlesContainer;let e=document.createElement(`vot-block`);return e.classList.add(`vot-subtitles-widget`),this.subtitlesContainer=e,this.syncWidgetMount(),e.addEventListener(`pointerdown`,this.onPointerDownBound,{signal:this.abortController.signal,passive:!0}),this.syncVisualStyleVars(),this.insetCacheReady=!1,this.updateContainerRect(),e}bindEvents(){let{signal:e}=this.abortController,t={signal:e};this.video?.addEventListener(`play`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`pause`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`seeking`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`seeked`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`ended`,this.onPlaybackStateChangeBound,t),this.resizeObserver=new ResizeObserver(()=>this.onResize()),this.resizeObserver.observe(this.container),this.video&&this.resizeObserver.observe(this.video),globalThis.visualViewport?.addEventListener(`resize`,this.onVisualViewportChangeBound,t),globalThis.visualViewport?.addEventListener(`scroll`,this.onVisualViewportChangeBound,t)}getUpdateMinIntervalMs(){return this.highlightWords?this.updateMinIntervalHighlightMs:this.updateMinIntervalMs}requestUpdate(e,t=performance.now()){if(this.abortController.signal.aborted||!this.subtitles)return;typeof e==`number`&&Number.isFinite(e)?this.lastPlaybackTimeMs=Math.max(0,e):this.video&&(this.lastPlaybackTimeMs=Math.max(0,this.video.currentTime*1e3));let n=this.getUpdateMinIntervalMs();t-this.lastUpdateRequestTs{if(this.videoFrameRequestId=null,this.abortController.signal.aborted)return;let n=this.video;if(!n||n.paused||n.ended||!this.subtitles)return;let r=typeof t.mediaTime==`number`&&Number.isFinite(t.mediaTime)?t.mediaTime*1e3:void 0;this.requestUpdate(r,e),this.startVideoFrameLoop()};onCheckerTick(){this.abortController.signal.aborted||(this.repositionPending&&(this.repositionPending=!1,this.updateContainerRect(),this.updatePending=!0),this.wrapPending&&(this.wrapPending=!1,this.recomputeWrapNow()),this.positionRefreshPending&&(this.positionRefreshPending=!1,this.applySubtitlePosition()),this.updatePending&&(this.updatePending=!1,this.update()))}attachDragDocumentListeners(){this.dragDocListenersAttached||(this.dragDocListenersAttached=!0,document.addEventListener(`pointermove`,this.onPointerMoveBound,{passive:!1}),document.addEventListener(`pointerup`,this.onPointerUpBound),document.addEventListener(`pointercancel`,this.onPointerUpBound))}detachDragDocumentListeners(){this.dragDocListenersAttached&&(this.dragDocListenersAttached=!1,document.removeEventListener(`pointermove`,this.onPointerMoveBound),document.removeEventListener(`pointerup`,this.onPointerUpBound),document.removeEventListener(`pointercancel`,this.onPointerUpBound))}onResize(){this.syncWidgetMount(),this.scheduleReposition()}updateContainerRect(){let e=this.getLayoutSize();if(!e.w||!e.h)return;let t=this.computeAnchorBoxLayout(e);!t.w||!t.h||(this.refreshBottomInsetNow(e,t),this.applySubtitlePositionWithLayout(e,t))}getLayoutSize(){let e=this.fullscreenLayerController.getLayoutRootElement(),t=e.getBoundingClientRect(),n=e.clientWidth||t.width,r=e.clientHeight||t.height;return{w:n,h:r,rect:t,scaleX:t.width&&n?t.width/n:1,scaleY:t.height&&r?t.height/r:1}}ensureSafeAreaProbe(){if(this.safeAreaProbeEl)return;let e=document.createElement(`div`);e.style.position=`fixed`,e.style.left=`0`,e.style.right=`0`,e.style.bottom=`0`,e.style.height=`env(safe-area-inset-bottom, 0px)`,e.style.pointerEvents=`none`,e.style.opacity=`0`,e.style.zIndex=`-1`,document.documentElement.appendChild(e),this.safeAreaProbeEl=e}getSafeAreaBottomInsetPx(){return this.ensureSafeAreaProbe(),this.safeAreaProbeEl&&this.safeAreaProbeEl.offsetHeight||0}refreshInsetCache(){let e=this.fullscreenLayerController.getLayoutRootElement();this.safeAreaBottomInsetCachedPx=this.getSafeAreaBottomInsetPx(),this.containerPaddingBottomCachedPx=Number.parseFloat(getComputedStyle(e).paddingBottom||`0`)||0,this.insetCacheReady=!0}isMobileViewport(){return typeof globalThis.matchMedia==`function`?globalThis.matchMedia(`(max-width: 900px) and (pointer: coarse)`).matches:!1}getBottomInsetPreset(){let e=document,t=e.fullscreenElement??e.webkitFullscreenElement;if(!(t instanceof Element))return this.bottomInsetByMode.normal;let{container:n,video:r}=this;return t===n||t.contains(n)||n.contains(t)||r&&(t===r||t.contains(r)||r.contains(t))?this.bottomInsetByMode.fullscreen:this.bottomInsetByMode.normal}computeReservedBottomInsetPx(e,t=this.getBottomInsetPreset()){return Nu(e*t.ratio,t.minPx,t.maxPx)}refreshBottomInsetNow(e,t){this.refreshInsetCache();let n=t?.h??this.computeAnchorBoxLayout(e??this.getLayoutSize()).h;if(!n){this.bottomInsetCachedPx=0;return}let r=this.getBottomInsetPreset();this.bottomInsetCachedPx=this.computeReservedBottomInsetPx(n,r)}getBottomInsetPx(e,t){this.insetCacheReady||this.refreshInsetCache();let n=this.getBottomInsetPreset(),r=this.safeAreaBottomInsetCachedPx,i=this.containerPaddingBottomCachedPx;if(this.isMobileViewport())return Math.max(i,r);let a=t?.h??this.computeAnchorBoxLayout(e??this.getLayoutSize()).h,o=a?this.computeReservedBottomInsetPx(a,n):n.minPx,s=Math.max(this.bottomInsetCachedPx,o);return Math.max(i,r,s)+n.gapPx}onPointerDown(e){let t=this.subtitlesContainer;if(!t)return;let n=e.target;if(!(n instanceof Node)||!t.contains(n)||!e.isPrimary||e.pointerType===`mouse`&&e.button!==0)return;let r=this.getLayoutSize(),{rect:i,w:a,h:o,scaleX:s,scaleY:c}=r;if(!a||!o)return;let l=this.computeAnchorBoxLayout(r);if(!l.w||!l.h)return;this.lastPositionRefreshTs=performance.now();let u=t.getBoundingClientRect(),d=(e.clientX-i.left)/s-l.left,f=(e.clientY-i.top)/c-l.top,p=(u.left-i.left+u.width/2)/s-l.left,m=(u.top-i.top+u.height)/c-l.top;this.dragging.pointerId=e.pointerId,this.dragging.candidate=!0,this.dragging.active=!1,this.dragging.moved=!1,this.dragging.startClientX=e.clientX,this.dragging.startClientY=e.clientY,this.dragging.offset.x=p-d,this.dragging.offset.y=m-f,this.hideSnapGuides(),this.attachDragDocumentListeners();let h=this.subtitlesBlock??(n instanceof Element?n:null);try{h?.setPointerCapture(e.pointerId)}catch{}}onPointerUp(e){this.dragging.pointerId!==null&&e.pointerId===this.dragging.pointerId&&(this.dragging.moved&&(this.suppressTokenClicksUntil=performance.now()+450),this.dragging.pointerId=null,this.dragging.candidate=!1,this.dragging.active=!1,this.dragging.moved=!1,this.hideSnapGuides(),this.detachDragDocumentListeners())}onPointerMove(e){if(!this.dragging.candidate||this.dragging.pointerId===null||e.pointerId!==this.dragging.pointerId)return;if(this.dragging.active)this.dragging.moved=!0;else{if(!Pu(this.dragging.startClientX,this.dragging.startClientY,e.clientX,e.clientY,this.dragStartThresholdPx))return;this.dragging.active=!0,this.dragging.moved=!0,this.suppressTokenClicksUntil=performance.now()+450,this.releaseTooltip()}e.preventDefault(),e.stopPropagation();let t=this.getLayoutSize(),{rect:n,w:r,h:i,scaleX:a,scaleY:o}=t;if(!r||!i)return;let s=this.computeAnchorBoxLayout(t);if(!s.w||!s.h)return;let c=(e.clientX-n.left)/a-s.left,l=(e.clientY-n.top)/o-s.top,u=c+this.dragging.offset.x,d=l+this.dragging.offset.y,f=this.subtitlesContainer?.offsetWidth??0,p=this.subtitlesContainer?.offsetHeight??0,m=this.getBottomInsetPx(t,s),h=zu({current:u,candidates:[s.w/2],thresholdPx:this.snapThresholdPx});h.snapped&&(u=h.value);let g=s.h/2+p/2,_=zu({current:d,candidates:[g],thresholdPx:this.snapThresholdPx});_.snapped&&(d=_.value),{anchorX:u,anchorY:d}=Ru({anchorX:u,anchorY:d,elementWidth:f,elementHeight:p,boxWidth:s.w,boxHeight:s.h,bottomInset:m}),this.positionPreset=`custom`,this.customVerticalAnchorState=Iu({anchorY:d,elementHeight:p,boxHeight:s.h,bottomInset:m}),this.position.left=u/s.w*100,this.position.top=d/s.h*100,this.updateSnapGuides(s,{showVerticalCenter:h.snapped,showHorizontalCenter:_.snapped}),this.applySubtitlePositionWithLayout(t,s)}applySubtitlePosition(){if(!this.subtitlesContainer)return;let e=this.getLayoutSize();if(!e.w||!e.h)return;let t=this.computeAnchorBoxLayout(e);!t.w||!t.h||this.applySubtitlePositionWithLayout(e,t)}applySubtitlePositionWithLayout(e,t){let n=this.subtitlesContainer;if(!n)return;this.applyScaleCompensation(n,e),this.syncAnchorDimensions(n,t),this.smartLayoutEnabled&&this.ensureSmartLayout(t);let r=n.offsetWidth,i=n.offsetHeight,a=this.getBottomInsetPx(e,t),o=this.resolveCurrentAnchorPosition(t,r,i,a),s=this.clampContainerPosition(t,o.anchorX,o.anchorY,r,i,a),c=s.anchorX,l=s.anchorY,u=t.left+c,d=t.top+l,f=u/e.w*100,p=d/e.h*100;this.updateContainerPosition(n,f,p),this.tokenTooltip?.updatePos()}applyScaleCompensation(e,t){let n=Math.min(t.scaleX||1,t.scaleY||1),r=n>0&&n<.999?Math.min(1/n,3):1;if(Math.abs(r-1)<.001){e.style.removeProperty(`--vot-subtitles-scale-compensation`);return}e.style.setProperty(`--vot-subtitles-scale-compensation`,r.toFixed(3))}syncAnchorDimensions(e,t){let n=Math.max(1,Math.round(t.w)),r=Math.max(1,Math.round(t.h));(n!==this.smartAnchorWidthPx||r!==this.smartAnchorHeightPx)&&(this.smartAnchorWidthPx=n,this.smartAnchorHeightPx=r,e.style.setProperty(`--vot-subtitles-anchor-width`,`${n}px`),e.style.setProperty(`--vot-subtitles-anchor-height`,`${r}px`),this.lastWrapTokens&&(this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute()))}resolveCurrentAnchorPosition(e,t,n,r){let i=this.position.left/100*e.w,a=this.position.top/100*e.h;if(this.positionPreset===`custom`)return a=Lu({state:this.customVerticalAnchorState,elementHeight:n,boxHeight:e.h,bottomInset:r}),{anchorX:i,anchorY:a};let o=this.resolvePresetAnchorPosition({preset:this.positionPreset,anchorBox:e,elementWidth:t,elementHeight:n,bottomInset:r});return i=o.anchorX,a=o.anchorY,e.w>0&&(this.position.left=i/e.w*100),e.h>0&&(this.position.top=a/e.h*100),{anchorX:i,anchorY:a}}clampContainerPosition(e,t,n,r,i,a){let o=t-r/2,s=n-i,c=e.w-r,l=e.h-a-i;return o=c>=0?Nu(o,0,c):c/2,s=l>=0?Nu(s,0,l):0,{anchorX:o+r/2,anchorY:s+i}}updateContainerPosition(e,t,n){(this.lastAppliedLeftPct===null||Math.abs(t-this.lastAppliedLeftPct)>=.01)&&(e.style.left=`${t}%`,this.lastAppliedLeftPct=t),(this.lastAppliedTopPct===null||Math.abs(n-this.lastAppliedTopPct)>=.01)&&(e.style.top=`${n}%`,this.lastAppliedTopPct=n)}resolvePresetAnchorPosition({preset:e,anchorBox:t,elementWidth:n,elementHeight:r,bottomInset:i}){let a=t.w/2,o=t.h-i;switch(e){case`top-center`:o=r;break;case`center`:o=t.h/2+r/2;break;case`bottom-left`:a=n/2;break;case`bottom-right`:a=t.w-n/2;break;case`bottom-center`:case`custom`:break}return Ru({anchorX:a,anchorY:o,elementWidth:n,elementHeight:r,boxWidth:t.w,boxHeight:t.h,bottomInset:i})}applyPositionAfterContentRender(){let e=this.getLayoutSize();if(e.w&&e.h){let t=this.computeAnchorBoxLayout(e);if(t.w&&t.h){this.refreshBottomInsetNow(e,t),this.applySubtitlePositionWithLayout(e,t);return}this.refreshBottomInsetNow(e),this.applySubtitlePosition();return}this.refreshBottomInsetNow(),this.applySubtitlePosition()}trimEdgeWhitespaceTokens(e){if(!e.length)return e;let t=0,n=e.length;for(;tt&&!e[n-1]?.text.trim();)--n;return t===0&&n===e.length?e:t>=n?[]:e.slice(t,n)}selectTokensByMaxLength(e,t){if(!e.length)return e;let n=0,r=0,i=!1,a=0,o=e.length,s=!1,c=!1,l=(n,r)=>{if(r<=n||(s||=(a=n,o=r,!0),c))return;let i=e[n],l=e[r-1];if(!i||!l)return;let u=(rthis.maxLength&&t>n){i=!0,l(n,t),n=t,r=a.text.length;continue}r=e}return i?(l(n,e.length),this.trimEdgeWhitespaceTokens(e.slice(a,o))):this.trimEdgeWhitespaceTokens(e)}buildTokenPrecomputeInput(e){let t=this.tokenPrecomputeMemo;if(t?.tokens===e)return t.value;let{slices:n,key:r}=_d(e),i={wordSlices:n,normalizedWordsKey:r};return this.tokenPrecomputeMemo={tokens:e,value:i},i}getTokenLayoutInputs(e){let t=this.subtitlesBlock;if(t){let n=getComputedStyle(t),r=`${n.fontStyle} ${n.fontVariant} ${n.fontWeight} ${n.fontSize} ${n.fontFamily}`;e.font=r;let i=Number.parseFloat(n.maxWidth),a=Number.parseFloat(n.paddingLeft)||0,o=Number.parseFloat(n.paddingRight)||0,s=Number.isFinite(i)?i:this.subtitleMaxWidthPx||globalThis.innerWidth*.8;return Number.isFinite(s)&&s>0&&(this.subtitleMaxWidthPx=s),{fontKey:r,maxWidthPx:Math.max(0,s-a-o)}}let n=Number.parseFloat(getComputedStyle(document.documentElement).fontSize)||16,r=Math.min(n*52,this.subtitleMaxWidthPx||globalThis.innerWidth*.8),i=this.fontSizeOverridden?this.fontSize:Math.min(24,Math.max(14,globalThis.innerWidth*.016)),a=`normal normal 500 ${i}px ${_u(this.fontFamily)}`;return e.font=a,{fontKey:a,maxWidthPx:Math.max(0,r-i)}}getActiveLineKey(e){return this.lastActiveLineKey===null?`${e[0]?.startMs??0}:${e[0]?.durationMs??0}:${e.length}`:this.lastActiveLineKey}getLineMeasureMemo(e,t){let{wordSlices:n,normalizedWordsKey:r}=this.buildTokenPrecomputeInput(e);if(!n.length)return null;let i=this.getMeasureContext();if(!i)return null;let{fontKey:a,maxWidthPx:o}=this.getTokenLayoutInputs(i);if(!Number.isFinite(o)||o<24)return null;let s=`${t}|${a}|${Math.round(o)}|${r}`;if(this.lineMeasureMemo?.key===s)return this.lineMeasureMemo;let c={key:s,metrics:vd(n,e=>i.measureText(e).width),maxWidthPx:o};return this.lineMeasureMemo=c,c}buildTokenProcessingMemo(e,t){let n=this.getLineMeasureMemo(e,t);if(!n)return null;let r=`${n.key}|${this.maxLength}`;if(this.tokenProcessingMemo?.key===r)return this.tokenProcessingMemo;let i=Ad(n.maxWidthPx),a={key:r,segmentRanges:xd(e,n.metrics,i,this.maxLength)};return this.tokenProcessingMemo=a,this.lastSegmentIndex=0,a}selectSegmentIndexFromRanges(e,t){if(!e.length)return-1;let n=this.lastSegmentIndex;for(n>=e.length&&(n=0);n=e[n].endMs;)n+=1;for(;n>0&&t=e[n].startMs&&tt>=e.startMs&&t=0?r:t{if(performance.now()i[e];return r.length=i.length,r}renderTokens(e){return Yu(e,e.length-1,this.breakAfterTokenIndexSet).map(e=>this.renderPlanPart(e))}renderStyledSpan(e,t,n=!1,r){return!t&&!n&&r===void 0?e:Tl`e.type===`captions`)}}catch{return{playlistUrl:r,subtitles:[]}}}async getVideoData(e){let t=e.split(`:`)?.[1],n=await this.getPostInfo(t);if(!n)return;let r=this.getVideoBlock();if(!r)return;let{playlistUrl:i,subtitles:a}=r,{title:o,description:s}=n;return{url:i,title:o,description:s,subtitles:a.map(e=>({language:E(e.srclang),source:`epicgames`,format:`vtt`,url:e.src}))}}async getVideoId(e){return new Promise(e=>{let t=`https://dev.epicgames.com`,n=btoa(window.location.href);window.addEventListener(`message`,n=>{if(n.origin===t&&typeof n.data==`string`&&n.data.startsWith(`getVideoId:`))return e(n.data.replace(`getVideoId:`,``))}),window.top?.postMessage(`getVideoId:${n}`,t)})}},An=class extends P{async getVideoId(e){return/video-([^/]+)\/([^/]+)/.exec(e.pathname)?.[0]}},jn=class extends P{async getVideoId(e){return e.pathname.slice(1)}},Mn=class extends P{getPlayerData(){return document.querySelector(`#movie_player`)?.getVideoData?.()??void 0}async getVideoId(e){return this.getPlayerData()?.video_id}},Nn=class extends P{getVideoDataBySource(e){let t=document.querySelector(`.icms.video > source[type="video/mp4"][data-quality="360"]`)?.src;return t?{url:D(t)}:this.returnBaseData(e)}getVideoDataByNext(e){try{let e=document.getElementById(`__NEXT_DATA__`)?.textContent;if(!e)throw new $t(`Not found __NEXT_DATA__ content`);let{props:{pageProps:{page:{description:t,title:n,video:{videoMetadata:{duration:r},assets:i}}}}}=JSON.parse(e),a=i.find(e=>e.height===360&&e.url.includes(`.mp4`))?.url;if(!a)throw new $t(`Not found video URL in assets`);return{url:D(a),duration:r,title:n,description:t}}catch(t){return T.warn(`Failed to get ign video data by video ID: ${e}, because ${t.message}. Using clear link instead...`),this.returnBaseData(e)}}async getVideoData(e){return document.getElementById(`__NEXT_DATA__`)?this.getVideoDataByNext(e):this.getVideoDataBySource(e)}async getVideoId(e){return/([^/]+)\/([\d]+)\/video\/([^/]+)/.exec(e.pathname)?.[0]??/\/videos\/([^/]+)/.exec(e.pathname)?.[0]}},Pn=class extends P{async getVideoId(e){return/video\/([^/]+)/.exec(e.pathname)?.[1]}},Fn=class extends P{async getVideoData(e){try{let e=document.querySelector(`#incflix-stream source:first-of-type`);if(!e)throw new N(`Failed to find source element`);let t=e.getAttribute(`src`);if(!t)throw new N(`Failed to find source link`);let n=new URL(t.startsWith(`//`)?`https:${t}`:t);return n.searchParams.append(`media-proxy`,`video.mp4`),{url:D(n)}}catch(t){T.error(`Failed to get Incestflix data by videoId: ${e}`,t.message);return}}async getVideoId(e){return/\/watch\/([^/]+)/.exec(e.pathname)?.[1]}},In=class extends P{async getVideoId(e){let t=/^\/(?:[a-z]{2}\/)?v\/(?\d+)\/(?[^/?#]+)\/?$/i.exec(e.pathname)?.groups;if(!t)return;let{id:n,slug:r}=t;return`v/${n}/${r}`}},Ln=class extends P{API_ORIGIN=`https://kick.com/api`;async getClipInfo(e){try{let{clip_url:t,duration:n,title:r}=(await(await this.fetch(`${this.API_ORIGIN}/v2/clips/${e}`)).json()).clip;return{url:t,duration:n,title:r}}catch(t){T.error(`Failed to get kick clip info by clipId: ${e}.`,t.message);return}}async getVideoInfo(e){try{let{source:t,livestream:n}=await(await this.fetch(`${this.API_ORIGIN}/v1/video/${e}`)).json(),{session_title:r,duration:i}=n;return{url:t,duration:Math.round(i/1e3),title:r}}catch(t){T.error(`Failed to get kick video info by videoId: ${e}.`,t.message);return}}async getVideoData(e){return e.startsWith(`videos`)?await this.getVideoInfo(e.replace(`videos/`,``)):await this.getClipInfo(e.replace(`clips/`,``))}async getVideoId(e){return/([^/]+)\/((videos|clips)\/([^/]+))/.exec(e.pathname)?.[2]}},Rn=class extends P{async getVideoData(e){try{let e=document.querySelector(`.ksr-video-player > video`),t=e?.querySelector(`source[type^='video/mp4']`)?.src;if(!t)throw new N(`Failed to find video URL`);let n=e?.querySelectorAll(`track`)??[];return{url:t,subtitles:Array.from(n).reduce((e,t)=>{let n=t.getAttribute(`srclang`),r=t.getAttribute(`src`);return!n||!r||e.push({language:E(n),url:r,format:`vtt`,source:`kickstarter`}),e},[])}}catch(t){T.error(`Failed to get Kickstarter data by videoId: ${e}`,t.message);return}}async getVideoId(e){return e.pathname.slice(1)}},zn=class extends P{API_ORIGIN=window.location.origin;getSecureData(e){try{let[t,n,r]=e.split(`/`).filter(e=>e),i=Array.from(document.getElementsByTagName(`script`)),a=i.filter(e=>e.innerHTML.includes(`videoId = "${n}"`)||e.innerHTML.includes(`serialId = Number(${n})`));if(!a.length)throw new N(`Failed to find secure script`);let o=a[0]?.textContent?.trim();if(!o)throw new N(`Secure script content is empty`);let s=/'{[^']+}'/.exec(o)?.[0];if(!s)throw new N(`Secure json wasn't found in secure script`);let c=JSON.parse(s.replaceAll(`'`,``));if(t!==`serial`)return{videoType:t,videoId:n,hash:r,...c};let l=i.find(e=>e.innerHTML.includes(`var videoInfo = {}`))?.textContent?.trim();if(!l)throw new N(`Failed to find videoInfo content`);let u=/videoInfo\.type\s+?=\s+?'([^']+)'/.exec(l)?.[1],d=/videoInfo\.id\s+?=\s+?'([^']+)'/.exec(l)?.[1],f=/videoInfo\.hash\s+?=\s+?'([^']+)'/.exec(l)?.[1];if(!u||!d||!f)throw new N(`Failed to parse videoInfo content`);return{videoType:u,videoId:d,hash:f,...c}}catch(t){return T.error(`Failed to get kodik secure data by videoPath: ${e}.`,t.message),!1}}async getFtor(e){let{videoType:t,videoId:n,hash:r,d:i,d_sign:a,pd:o,pd_sign:s,ref:c,ref_sign:l}=e;try{return await(await this.fetch(`${this.API_ORIGIN}/ftor`,{method:`POST`,headers:{"User-Agent":f.userAgent,Origin:this.API_ORIGIN,Referer:`${this.API_ORIGIN}/${t}/${n}/${r}/360p`},body:new URLSearchParams({d:i,d_sign:a,pd:o,pd_sign:s,ref:decodeURIComponent(c),ref_sign:l,bad_user:`false`,cdn_is_working:`true`,info:`{}`,type:t,hash:r,id:n})})).json()}catch(e){return T.error(`Failed to get kodik video data (type: ${t}, id: ${n}, hash: ${r})`,e.message),!1}}decryptUrl(e){return`${atob(e.replace(/[a-zA-Z]/g,e=>{let t=e.charCodeAt(0)+18,n=e<=`Z`?90:122;return String.fromCharCode(n>=t?t:t-26)}))}`}async getVideoData(e){let t=this.getSecureData(e);if(!t)return;let n=await this.getFtor(t);if(!n)return;let r=Object.entries(n.links[n.default.toString()]).find(([,e])=>e.type===`application/x-mpegURL`)?.[1];if(r)return{url:r.src.startsWith(`//`)?`${r.src}`:this.decryptUrl(r.src)}}async getVideoId(e){return/\/(uv|video|seria|episode|season|serial)\/([^/]+)\/([^/]+)\/([\d]+)p/.exec(e.pathname)?.[0]}},Bn=class extends xn{SUBTITLE_SOURCE=`linkedin`;async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let{url:n,duration:r,subtitles:i}=t;return{url:D(new URL(n)),duration:r,subtitles:i}}async getVideoId(e){return/\/learning\/(([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},Vn;(function(e){e.Channel=`Channel`,e.Video=`Video`})(Vn||={});var Hn=class extends P{getClientVersion(){if(!(typeof SENTRY_RELEASE>`u`))return SENTRY_RELEASE.id}async getVideoData(e){try{let t=this.getClientVersion();if(!t)throw new N(`Failed to get client version`);let n=await this.fetch(`https://www.loom.com/graphql`,{headers:{"User-Agent":f.userAgent,"content-type":`application/json`,"x-loom-request-source":`loom_web_${t}`,"apollographql-client-name":`web`,"apollographql-client-version":t,"Alt-Used":`www.loom.com`},body:`{"operationName":"FetchCaptions","variables":{"videoId":"${e}"},"query":"query FetchCaptions($videoId: ID!, $password: String) {\\n fetchVideoTranscript(videoId: $videoId, password: $password) {\\n ... on VideoTranscriptDetails {\\n id\\n captions_source_url\\n language\\n __typename\\n }\\n ... on GenericError {\\n message\\n __typename\\n }\\n __typename\\n }\\n}"}`,method:`POST`});if(n.status!==200)throw new N(`Failed to get data from graphql`);let r=(await n.json()).data.fetchVideoTranscript;if(r.__typename===`GenericError`)throw new N(r.message);return{url:this.service?.url+e,subtitles:[{format:`vtt`,language:E(r.language),source:`loom`,url:r.captions_source_url}]}}catch(t){return T.error(`Failed to get Loom video data, because: ${t.message}`),this.returnBaseData(e)}}async getVideoId(e){return/(embed|share)\/([^/]+)?/.exec(e.pathname)?.[2]}},Un=class extends P{API_ORIGIN=`https://my.mail.ru`;async getVideoMeta(e){try{return await(await this.fetch(`${this.API_ORIGIN}/+/video/meta/${e}?xemail=&ajax_call=1&func_name=&mna=&mnb=&ext=1&_=${Date.now()}`)).json()}catch(e){T.error(`Failed to get mail.ru video data`,e.message);return}}async getVideoId(e){let t=e.pathname;if(/\/(v|mail|bk|inbox)\//.exec(t))return t.slice(1);let n=/video\/embed\/([^/]+)/.exec(t)?.[1];if(!n)return;let r=await this.getVideoMeta(n);if(r)return r.meta.url.replace(`//my.mail.ru/`,``)}},Wn=class extends P{DEFAULT_SITE_ORIGIN=`https://mediafile.cc`;SITE_ORIGIN=this.service?.url?.slice(0,-1)??this.DEFAULT_SITE_ORIGIN;getVideoSrc(){let e=this.video instanceof HTMLVideoElement?this.video:document.querySelector(`video`);return e?.src||e?.currentSrc||e?.querySelector(`source[src]`)?.src||void 0}async getVideoData(e){let t=this.getVideoSrc();if(t)return{url:`${this.SITE_ORIGIN}/${e}`,video_url:t,translationHelp:[{target:`video_file_url`,targetUrl:t}]}}async getVideoId(e){return e.pathname.replace(/^\/+/,``)||void 0}},Gn=class extends xn{SUBTITLE_SOURCE=`netacad`;async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let{url:n,duration:r,subtitles:i}=t;return{url:D(new URL(n)),duration:r,subtitles:i}}async getVideoId(e){return e.pathname+e.search}},Kn=class extends P{async getVideoId(e){return/([^/]+)\/(view)\/([^/]+)/.exec(e.pathname)?.[0]}},qn=class extends P{async getVideoId(e){return e.hostname===`nico.ms`?e.pathname.replace(/^\//,``).split(`/`)[0]||void 0:/\/watch\/([^/?#]+)/.exec(e.pathname)?.[1]}},Jn=class extends P{async getVideoData(e){let t=this.returnBaseData(e);if(!t)return t;try{if(!this.video)throw Error(`Video element not found`);let e=this.video.querySelector(`source[type^="video/mp4"], source[type^="video/webm"]`)?.src;if(!e||!/^https?:\/\//.test(e))throw Error(`Video source not found`);return{...t,translationHelp:[{target:`video_file_url`,targetUrl:e}]}}catch{return t}}async getVideoId(e){return/gag\/([^/]+)/.exec(e.pathname)?.[1]}},Yn=class extends P{API_ORIGIN=`https://odysee.com`;async getVideoData(e){return{url:`${this.API_ORIGIN}/${e}`.replace(/:[a-zA-Z0-9]+$/,``)}}async getVideoId(e){return e.pathname.slice(1)}},Xn=class extends P{async getVideoId(e){return/\/video\/(\d+)/.exec(e.pathname)?.[1]}},Zn=class extends P{async getVideoId(e){return/\/([a-z]{2}\/(?:[a-z0-9-]+\/)?(?:replay|videos?|original-series\/episode)\/[\w-]+)\/?$/i.exec(e.pathname)?.[1]}},Qn=class extends xn{SUBTITLE_SOURCE=`oraclelearn`;async getVideoData(e){let t=this.getVideoDataByPlayer(e);if(!t)return;let{url:n,duration:r,subtitles:i}=t,a=this.returnBaseData(e),o=D(new URL(n));return a?{url:a.url,duration:r,subtitles:i,translationHelp:[{target:`video_file_url`,targetUrl:o}]}:{url:o,duration:r,subtitles:i}}async getVideoId(e){return/\/ou\/course\/(([^/]+)\/(\d+)\/(\d+))/.exec(e.pathname)?.[1]}},$n=class extends P{API_ORIGIN=`https://www.patreon.com/api`;async getPosts(e){try{return await(await this.fetch(`${this.API_ORIGIN}/posts/${e}?json-api-use-default-includes=false`)).json()}catch(t){return T.error(`Failed to get patreon posts by postId: ${e}.`,t.message),!1}}async getVideoData(e){let t=await this.getPosts(e);if(!t)return;let n=t.data.attributes.post_file.url;if(n)return{url:n}}async getVideoId(e){let t=/posts\/([^/]+)/.exec(e.pathname)?.[1];if(t)return t.replace(/[^\d.]/g,``)}},er=class extends P{async getVideoId(e){let t=e.pathname.replace(/\/+$/,``),n=/\/videos\/watch\/([^/]+)/.exec(t)?.[1];if(n)return`/videos/watch/${n}`;let r=/\/w\/([^/]+)/.exec(t)?.[1];if(r)return`/videos/watch/${r}`}},tr=class extends P{async getVideoId(e){return/\/((?:videopopout|[^/]+(?:\/profile)?\/videos)\/[^/?#&/]+)\/?$/.exec(e.pathname)?.[1]??/^\/([^/#?]+)\/?$/.exec(e.pathname)?.[1]}},nr=class extends P{async getVideoId(e){return e.searchParams.get(`viewkey`)??/embed\/([^/]+)/.exec(e.pathname)?.[1]}},rr=class extends P{async getVideoData(e){try{if(typeof flashvars>`u`)return;let{rnd:e,video_url:t,video_title:n}=flashvars;if(!t||!e)throw new N(`Failed to find video source or rnd`);let r=new URL(t);r.searchParams.append(`rnd`,e),T.log(`PornTN get_file link`,r.href);let i=await this.fetch(r.href,{method:`head`}),a=new URL(i.url);return T.log(`PornTN cdn link`,a.href),{url:D(a),title:n}}catch(t){T.error(`Failed to get PornTN data by videoId: ${e}`,t.message);return}}async getVideoId(e){return/\/videos\/(([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},ir=class extends P{async getVideoData(e){try{if(!e)throw new N(`Failed to find PreserveTube video ID`);return{url:`https://s3.archive.party/preservetube/${e}.mp4`}}catch(t){T.error(`Failed to get PreserveTube data by videoId: ${e}`,t.message);return}}async getVideoId(e){return e.searchParams.get(`v`)??void 0}},ar=class extends P{API_ORIGIN=`https://www.reddit.com`;async getDashAudioUrl(e){let t=await fetch(e);if(!t.ok)return;let n=await t.text(),r=new DOMParser().parseFromString(n,`application/xml`),i=r.querySelector(`AdaptationSet[contentType="audio"] BaseURL`)?.textContent??r.querySelector(`Representation[id="AUDIO-1"] BaseURL`)?.textContent;if(!i)return;let a=new URL(e);return new URL(i,a).href}async getVideoData(e){try{let t=await fetch(`${this.API_ORIGIN}/r/${e}.json`,{headers:{Accept:`application/json`}});if(!t.ok)throw new N(`Reddit API error: ${t.status}`);let n=(await t.json())?.[0]?.data?.children?.[0]?.data,r=n?.secure_media?.reddit_video??n?.media?.reddit_video??n?.crosspost_parent_list?.[0]?.secure_media?.reddit_video??n?.crosspost_parent_list?.[0]?.media?.reddit_video;if(!r)throw new N(`No reddit_video found in post`);let i=r.dash_url?.replaceAll(`&`,`&`);if(!i)throw new N(`No dash_url in reddit_video`);let a=await this.getDashAudioUrl(i);if(!a)throw new N(`Failed to extract audio URL from DASH MPD`);return{url:a}}catch(t){T.error(`Failed to get reddit video data by video ID: ${e}`,t.message);return}}async getVideoId(e){return/\/r\/(([^/]+)\/([^/]+)\/([^/]+)\/([^/]+))/.exec(e.pathname)?.[1]}},or=class extends P{async getVideoData(e){let t=document.querySelector(`.jw-video, .media__video_noscript`);if(!t)return;let n=t.getAttribute(`src`);if(n)return n.endsWith(`.MP4`)&&(n=D(n)),{videoId:e,url:n}}async getVideoId(e){return e.pathname.slice(1)}},sr=class extends P{async getVideoId(e){let t=/\/videos?\/(\d+)(?:\/(.+))?\/?$/.exec(e.pathname);if(!t)return;let[,n,r]=t;return r?`${n}/${r.replace(/\/+$/,``)}/`:n}},cr=class extends P{async getVideoId(e){return e.pathname.slice(1)}},lr=class extends P{async getVideoId(e){return/(?:video|embed)\/([^/]+)/.exec(e.pathname)?.[1]}},ur=class extends P{API_ORIGIN=`https://learning.sap.com/`;async requestKaltura(e,t,n){try{return await(await this.fetch(`https://${e}/api_v3/service/multirequest`,{method:`POST`,body:JSON.stringify({1:{service:`session`,action:`startWidgetSession`,widgetId:`_${t}`},2:{service:`baseEntry`,action:`list`,ks:`{1:result:ks}`,filter:{redirectFromEntryId:n},responseProfile:{type:1,fields:`id,referenceId,name,description,dataUrl,duration,flavorParamsIds,type,dvrStatus,externalSourceType,createdAt,updatedAt,endDate,plays,views,downloadUrl,creatorId`}},3:{service:`baseEntry`,action:`getPlaybackContext`,entryId:`{2:result:objects:0:id}`,ks:`{1:result:ks}`,contextDataParams:{objectType:`KalturaContextDataParams`,flavorTags:`all`}},apiVersion:`3.3.0`,format:1,ks:``,clientTag:`html5:v3.17.22`,partnerId:t}),headers:{"Content-Type":`application/json`}})).json()}catch(e){T.error(`Failed to request kaltura data`,e.message);return}}async getKalturaData(e){try{let t=document.querySelector(`script[data-nscript="beforeInteractive"]`);if(!t)throw new N(`Failed to find script element`);let n=/https:\/\/([^"]+)\/p\/([^"]+)\/embedPlaykitJs\/uiconf_id\/([^"]+)/.exec(t?.src);if(!n)throw new N(`Failed to get sap data for videoId: ${e}`);let[,r,i]=n,a=document.querySelector(`#shadow`)?.firstChild?.getAttribute(`id`);if(!a){let e=document.querySelector(`#__NEXT_DATA__`);if(!e)throw new N(`Failed to find next data element`);a=/"sourceId":\s?"([^"]+)"/.exec(e.innerText)?.[1]}if(!r||Number.isNaN(+i)||!a)throw new N(`One of the necessary parameters for getting a link to a sap video in wasn't found for ${e}. Params: kalturaDomain = ${r}, partnerId = ${i}, entryId = ${a}`);return await this.requestKaltura(r,i,a)}catch(e){T.error(`Failed to get kaltura data`,e.message);return}}async getVideoData(e){let t=await this.getKalturaData(e);if(!t)return;let[,n,r]=t,{duration:i}=n.objects[0],a=r.sources.find(e=>e.format===`url`&&e.protocols===`http,https`&&e.url.includes(`.mp4`))?.url;if(a)return{url:a,subtitles:r.playbackCaptions.map(e=>({language:E(e.languageCode),source:`sap`,format:`vtt`,url:e.webVttUrl,isAutoGenerated:e.label.includes(`auto-generated`)})),duration:i}}async getVideoId(e){return/((courses|learning-journeys)\/([^/]+)(\/[^/]+)?)/.exec(e.pathname)?.[1]}},dr=class extends P{async getVideoId(e){return/\/([\da-z]+\/(?:video|play|embed)(?:\/[^/]+)?)\/?$/i.exec(e.pathname)?.[1]??/\/([\da-z]+-[\da-z]+\/playlist\/[^/]+)\/?$/i.exec(e.pathname)?.[1]}},fr=class e extends P{static getMediaViewer(){if(!(typeof appMediaViewer>`u`))return appMediaViewer}async getVideoId(t){let n=e.getMediaViewer();if(!n||n.live)return;let r=n.target.message;if(r.peer_id._!==`peerChannel`)return;let i=r.media;if(i._!==`messageMediaDocument`||i.document.type!==`video`)return;let a=r.mid&4294967295;return`${await n.managers.appPeersManager.getPeerUsername(r.peerId)}/${a}`}},pr=class extends P{async getVideoId(e){return/(videos|embed)\/[^/]+/.exec(e.pathname)?.[0]}},mr=class extends P{async getVideoId(e){return/([^/]+)\/video\/([^/]+)/.exec(e.pathname)?.[0]}},hr=class extends P{async getVideoId(e){let t=e.searchParams.get(`vid`),n=/([^/]+)\/([\d]+)/.exec(e.pathname)?.[0];if(!(!t||!n))return`${n}?vid=${t}`}},gr=class extends P{API_ORIGIN=`https://clips.twitch.tv`;async getClipLink(e,t){let n=document.querySelector(`script[type='application/ld+json']`),r=e.slice(1);if(n){let e=JSON.parse(n.innerText)[`@graph`].find(e=>e[`@type`]===`VideoObject`)?.creator.url;if(!e)throw new N(`Failed to find channel link`);return`${e.replace(`https://www.twitch.tv/`,``)}/clip/${r}`}let i=r===`embed`,a=document.querySelector(i?`.tw-link[data-test-selector='stream-info-card-component__stream-avatar-link']`:`.clips-player a:not([class])`);if(a)return`${a.href.replace(`https://www.twitch.tv/`,``)}/clip/${i?t:r}`}async getVideoData(e){let t=document.querySelector(`[data-a-target="stream-title"], [data-test-selector="stream-info-card-component__subtitle"]`)?.innerText,n=!!document.querySelector(`[data-a-target="animated-channel-viewers-count"], .channel-status-info--live, .top-bar--pointer-enabled .tw-channel-status-text-indicator`);return{url:this.service?.url+e,isStream:n,title:t}}async getVideoId(e){let t=e.pathname;if(/^m\.twitch\.tv$/.test(t))return/videos\/([^/]+)/.exec(e.href)?.[0]??t.slice(1);if(/^player\.twitch\.tv$/.test(e.hostname))return`videos/${e.searchParams.get(`video`)}`;let n=/([^/]+)\/(?:clip)\/([^/]+)/.exec(t);if(n)return n[0];if(/^clips\.twitch\.tv$/.test(e.hostname))return await this.getClipLink(t,e.searchParams.get(`clip`));let r=/(?:videos)\/([^/]+)/.exec(t);if(r)return r[0];let i=document.querySelector(`.home-offline-hero .tw-link`);if(i?.href){let e=new URL(i.href);return/(?:videos)\/([^/]+)/.exec(e.pathname)?.[0]}return document.querySelector(`.persistent-player`)?t:void 0}},_r=class extends P{async getVideoId(e){let t=/status\/([^/]+)/.exec(e.pathname)?.[1];if(t)return t;let n=(this.video?.closest(`[data-testid="tweet"]`))?.querySelector(`a[role="link"][aria-label]`)?.href;return n?/status\/([^/]+)/.exec(n)?.[1]:void 0}};function vr(e){return typeof e==`object`&&!!e}function yr(e){return typeof e==`object`&&!!e}function br(e){if(Array.isArray(e))return e.filter(yr);if(typeof e!=`object`||!e)return[];let t=e;return(Array.isArray(t.Video)?t.Video:Array.isArray(t.video)?t.video:[]).filter(yr)}function xr(e){if(!vr(e))return[];let t=[];for(let[n,r]of Object.entries(e))!vr(r)||typeof r.url!=`string`||t.push({src:r.url,type:typeof r.type==`string`?r.type:void 0,label:typeof r.height==`number`||typeof r.height==`string`?r.height:n});return t}function Sr(e){if(typeof e==`number`&&Number.isFinite(e))return e;let t=String(e??``).match(/(\d{3,4})/);return Number(t?.[1]??0)}function Cr(e){if(typeof e.file==`string`)return e.file;if(typeof e.src==`string`)return e.src}function wr(e,t){return e.includes(`mpegurl`)||/\.m3u8(?:$|[?#])/i.test(t)}function Tr(e,t){return e.includes(`dash`)||/\.mpd(?:$|[?#])/i.test(t)}var Er=class extends P{API_ORIGIN=`${window.location.origin}/api-2.0`;getModuleData(){let e=(document.querySelector(`.ud-app-loader[data-module-id='course-taking']`)??document.querySelector(`[data-module-id='course-taking']`))?.dataset?.moduleArgs;if(e)try{return JSON.parse(e)}catch{return}}getLectureId(e){let t=/(?:\/learn\/(?:v4\/t\/)?lecture\/|#\/?lecture\/)(\d+)/i,n=/\/lecture\/view\/\?/i,r=window.location.href,i=n.test(r)?new URL(r).searchParams:void 0,a=i?(()=>{for(let[e,t]of i){let n=e.toLowerCase();if(n===`lectureid`||n===`lecture_id`)return t}})():void 0;return t.exec(r)?.[1]??a??(e?t.exec(`/${e}`)?.[1]:void 0)}getCourseId(e){let t=e,n=this.normalizeId(t?.courseId??t?.course_id??t?.course?.id);if(n)return n;let r=this.normalizeId(document.querySelector(`[data-course-id]`)?.getAttribute(`data-course-id`));if(r)return r;let i=document.documentElement?.innerHTML??``;return/data-course-id=["'](\d+)/i.exec(i)?.[1]??/"courseId"\s*:\s*(\d+)/i.exec(i)?.[1]??/"courseId"\s*:\s*(\d+)/i.exec(i)?.[1]}normalizeId(e){if(typeof e==`number`&&Number.isFinite(e))return String(e);if(typeof e==`string`)return/^\d+$/.test(e)?e:void 0}parseJson(e){try{return JSON.parse(e)}catch{let t=e.replaceAll(`"`,`"`).replaceAll(`"`,`"`).replaceAll(`'`,`'`).replaceAll(`'`,`'`);try{return JSON.parse(t)}catch{return}}}getViewHtmlCandidates(e){if(typeof e!=`string`||!e.trim())return[];let t=new DOMParser().parseFromString(e,`text/html`),n=[];for(let e of Array.from(t.querySelectorAll(`source`))){let t=e.getAttribute(`src`);t&&n.push({src:t,type:e.getAttribute(`type`)??void 0,label:e.getAttribute(`data-res`)??void 0})}for(let e of Array.from(t.querySelectorAll(`[videojs-setup-data]`))){let t=e.getAttribute(`videojs-setup-data`);if(!t)continue;let r=this.parseJson(t);r&&n.push(...br(r.sources))}return n}isErrorData(e){return Object.hasOwn(e,`error`)||Object.hasOwn(e,`detail`)&&!Object.hasOwn(e,`_class`)}async getLectureData(e,t){try{let n=await(await this.fetch(`${this.API_ORIGIN}/users/me/subscribed-courses/${e}/lectures/${t}/?`+new URLSearchParams({"fields[lecture]":`title,description,view_html,asset,download_url,is_free,last_watched_second`,"fields[asset]":`asset_type,length,stream_url,media_sources,stream_urls,download_urls,external_url,captions,data,thumbnail_sprite,slides,slide_urls,course_is_drmed,media_license_token`}).toString())).json();if(this.isErrorData(n))throw new N(n.detail??`unknown error`);return n}catch(n){T.error(`Failed to get lecture data by courseId: ${e} and lectureId: ${t}`,n.message);return}}async getCourseLang(e){try{let t=await(await this.fetch(`${this.API_ORIGIN}/users/me/subscribed-courses/${e}?`+new URLSearchParams({"fields[course]":`locale`}).toString())).json();if(!this.isErrorData(t))return t;let n=await(await this.fetch(`${this.API_ORIGIN}/courses/${e}/?`+new URLSearchParams({"fields[course]":`locale`}).toString())).json();if(this.isErrorData(n))throw new N(n.detail??`unknown error`);return n}catch(t){T.error(`Failed to get course lang by courseId: ${e}`,t.message);return}}findVideoUrl(e,t,n,r,i,a,o){let s=[],c=Array.isArray(e)?e:[];for(let e of c)s.push({src:e.src,type:e.type,label:e.label});s.push(...br(t)),s.push(...br(n)),s.push(...xr(a)),typeof o==`string`&&s.push(...this.getViewHtmlCandidates(o)),typeof r==`string`&&s.push({src:r}),typeof i==`string`&&s.push({src:i});let l=this.video?.currentSrc||this.video?.src;typeof l==`string`&&l&&s.push({src:l});let u=new Map;for(let e of s){let t=Cr(e);if(!t||/^javascript:/i.test(t))continue;let n=Sr(e.label??e.quality??e.height),r=String(e.type??``).toLowerCase(),i=u.get(t);(!i||n>i.quality)&&u.set(t,{url:t,type:r,quality:n,isYouTubeWatch:/:\/\/(?:www\.)?youtube\.com\/watch\?/i.test(t)})}let d=Array.from(u.values());if(!d.length)return;let f=d.filter(e=>e.type.includes(`mp4`)||/\.mp4(?:$|[?#])/i.test(e.url));return f.length?(f.sort((e,t)=>t.quality-e.quality),f[0]?.url):d.find(e=>wr(e.type,e.url))?.url||d.find(e=>Tr(e.type,e.url))?.url||d.find(e=>!e.isYouTubeWatch)?.url||d[0]?.url}getCaptionLocale(e){let t=typeof e.locale_id==`string`?e.locale_id:typeof e.locale?.locale==`string`?e.locale.locale:void 0;return t?E(t):void 0}findSubtitleUrl(e,t){if(!Array.isArray(e))return;let n=e.filter(e=>vr(e)&&(typeof e.url==`string`||typeof e.download_url==`string`)),r=n.find(e=>this.getCaptionLocale(e)===t)??n.find(e=>this.getCaptionLocale(e)===`en`)??n[0];return r?.url??r?.download_url}async getVideoData(e){let t=this.getModuleData(),n=this.getCourseId(t),r=this.getLectureId(e);if(T.log(`[Udemy] courseId: ${n}, lectureId: ${r}`),!r||!n)return;let i=await this.getLectureData(n,r);if(!i)return;let{title:a,description:o,asset:s,view_html:c}=i,{length:l,media_sources:u,captions:d}=s,f=s,p=f.stream_urls,m=f.download_urls,h=this.findVideoUrl(u,p,m,f.stream_url??f.streamUrl,f.external_url,f.data?.outputs,c);if(!h){T.log(`Failed to find video file in asset sources`,s);return}let g=`en`,_=(await this.getCourseLang(n))?.locale?.locale;typeof _==`string`&&(g=E(_)),yn.includes(g)||(g=`en`);let v=this.findSubtitleUrl(d,g);return v||T.log(`Failed to find subtitle file in captions`,d),{...v?{url:this.service?.url+e,translationHelp:[{target:`subtitles_file_url`,targetUrl:v},{target:`video_file_url`,targetUrl:h}],detectedLanguage:g}:{url:h,translationHelp:null},duration:l,title:a,description:o}}async getVideoId(e){return e.pathname.slice(1)}},Dr=class extends P{API_KEY=``;DEFAULT_SITE_ORIGIN=`https://vimeo.com`;SITE_ORIGIN=this.service?.url?.slice(0,-1)??this.DEFAULT_SITE_ORIGIN;isErrorData(e){return Object.hasOwn(e,`error`)}isPrivatePlayer(){return this.referer&&!this.referer.includes(`vimeo.com`)&&this.origin.endsWith(`player.vimeo.com`)}toPublicUrl(e){let[t,n]=e.split(`:`,2);return n?`${this.DEFAULT_SITE_ORIGIN}/${t}/${n}`:`${this.DEFAULT_SITE_ORIGIN}/${t}`}returnPublicBaseData(e){let t=this.returnBaseData(e);if(t)return{...t,url:this.toPublicUrl(e)}}normalizePublicVideoUrl(e,t){try{let n=new URL(e);if(n.hostname===`player.vimeo.com`)return this.toPublicUrl(t);if(n.hostname.endsWith(`vimeo.com`)){let e=/^\/(\d+):([a-z0-9]+)$/i.exec(n.pathname);if(e)return`${this.DEFAULT_SITE_ORIGIN}/${e[1]}/${e[2]}`}}catch{}return e}async getViewerData(){try{let e=await(await this.fetch(`https://vimeo.com/_next/viewer`)).json(),{apiUrl:t,jwt:n}=e;return this.API_ORIGIN=`https://${t}`,this.API_KEY=`jwt ${n}`,e}catch(e){return T.error(`Failed to get default viewer data.`,e.message),!1}}async getVideoInfo(e){try{let t=new URLSearchParams({fields:`name,link,description,duration`}).toString(),n=await(await this.fetch(`${this.API_ORIGIN}/videos/${e}?${t}`,{headers:{Authorization:this.API_KEY}})).json();if(this.isErrorData(n))throw Error(n.developer_message??n.error);return n}catch(t){return T.error(`Failed to get video info by video ID: ${e}`,t.message),!1}}async getPrivateVideoSource(e){try{let{default_cdn:t,cdns:n}=e.dash,r=n[t].url,i=await this.fetch(r);if(i.status!==200)throw new N(await i.text());let a=await i.json(),o=new URL(a.base_url,r),s=a.audio.find(e=>e.mime_type===`audio/mp4`&&e.format===`dash`);if(!s)throw new N(`Failed to find video data`);let c=s.segments?.[0]?.url;if(!c)throw new N(`Failed to find first segment url`);let[l,u]=c.split(`?`,2),d=new URLSearchParams(u);return d.delete(`range`),new URL(`${s.base_url}${l}?${d.toString()}`,o).href}catch(e){return T.error(`Failed to get private video source`,e.message),!1}}async getPrivateVideoInfo(e){try{if(typeof playerConfig>`u`)return;let t=await this.getPrivateVideoSource(playerConfig.request.files);if(!t)throw new N(`Failed to get private video source`);let{video:{title:n,duration:r},request:{text_tracks:i}}=playerConfig;return{url:`${this.SITE_ORIGIN}/${e}`,video_url:t,title:n,duration:r,subs:i}}catch(t){return T.error(`Failed to get private video info by video ID: ${e}`,t.message),!1}}async getSubsInfo(e){try{let t=new URLSearchParams({per_page:`100`,fields:`language,type,link`}).toString(),n=await(await this.fetch(`${this.API_ORIGIN}/videos/${e}/texttracks?${t}`,{headers:{Authorization:this.API_KEY}})).json();if(this.isErrorData(n))throw Error(n.developer_message??n.error);return n.data}catch(t){return T.error(`Failed to get subtitles info by video ID: ${e}`,t.message),[]}}async getVideoData(e){if(this.isPrivatePlayer()){let t=await this.getPrivateVideoInfo(e);if(!t)return;let{url:n,subs:r,video_url:i,title:a,duration:o}=t,s=r.map(e=>({language:E(e.lang),source:`vimeo`,format:`vtt`,url:new URL(e.url,this.SITE_ORIGIN).href,isAutoGenerated:e.lang.includes(`autogenerated`)})),c=s.length?[{target:`video_file_url`,targetUrl:i},{target:`subtitles_file_url`,targetUrl:s[0].url}]:null;return{...c?{url:n,translationHelp:c}:{url:i},subtitles:s,title:a,duration:o}}if(!this.extraInfo||(e.includes(`/`)&&(e=e.replace(`/`,`:`)),!await this.getViewerData()))return this.returnPublicBaseData(e);let t=await this.getVideoInfo(e);if(!t)return this.returnPublicBaseData(e);let n=(await this.getSubsInfo(e)).map(e=>({language:E(e.language),source:`vimeo`,format:`vtt`,url:e.link,isAutoGenerated:e.language.includes(`autogen`)})),{link:r,duration:i,name:a,description:o}=t;return{url:this.normalizePublicVideoUrl(r,e),title:a,description:o,subtitles:n,duration:i}}async getVideoId(e){let t=e.pathname.replace(/\/+$/,``),n=/video\/[^/]+$/.exec(t)?.[0];if(this.isPrivatePlayer())return n;if(n){let t=e.searchParams.get(`h`),r=n.replace(`video/`,``);return t?`${r}/${t}`:r}return(/channels\/[^/]+\/([^/]+)/.exec(t)?.[1]??/groups\/[^/]+\/videos\/([^/]+)/.exec(t)?.[1]??/(showcase|album)\/[^/]+\/video\/([^/]+)/.exec(t)?.[2])||/([^/]+\/)?[^/]+$/.exec(t)?.[0]}},Or=class e extends P{static getPlayer(){if(!(typeof Videoview>`u`))return Videoview?.getPlayerObject?.call(void 0)}async getVideoData(t){let n=e.getPlayer();if(!n)return this.returnBaseData(t);try{let{description:e,duration:r,md_title:i}=n.vars,a=new DOMParser().parseFromString(e,`text/html`),o=Array.from(a.body.childNodes).filter(e=>e.nodeName!==`BR`).map(e=>e.textContent).join(` +`),s;return Object.hasOwn(n.vars,`subs`)&&(s=n.vars.subs.map(e=>({language:E(e.lang),source:`vk`,format:`vtt`,url:e.url,isAutoGenerated:!!e.is_auto}))),{url:this.service?.url+t,title:i,description:o,duration:r,subtitles:s}}catch(e){return T.error(`Failed to get VK video data, because: ${e.message}`),this.returnBaseData(t)}}async getVideoId(e){let t=/^\/(video|clip)-?\d{8,9}_\d{9}$/.exec(e.pathname);if(t)return t[0].slice(1);let n=/\/playlist\/[^/]+\/(video-?\d{8,9}_\d{9})/.exec(e.pathname);if(n)return n[1];let r=e.searchParams.get(`z`);if(r)return r.split(`/`)[0];let i=e.searchParams.get(`oid`),a=e.searchParams.get(`id`);if(i&&a)return`video-${Math.abs(parseInt(i,10))}_${a}`}},kr=class extends P{async getVideoId(e){return/(video|embed)\/(\d+)(\/[^/]+\/)?/.exec(e.pathname)?.[0]}},Ar=/^\d+:(?:[\da-f]{32}|\d{16,})$/i,jr=/^[A-Za-z0-9]+$/,Mr=/^(?:www\.)?weibo\.com$/,Nr=/^\/newlogin\/?$/,Pr=class extends P{async getVideoId(e){if(e.hostname===`video.weibo.com`){let t=e.searchParams.get(`fid`);return!t||!Ar.test(t)?void 0:`tv/show/${t}`}if(Mr.test(e.host)&&Nr.test(e.pathname)){let t=e.searchParams.get(`url`);if(t)try{let n=new URL(t,e.origin);if(n.href!==e.href){let e=await this.getVideoId(n);if(e)return e}}catch{}let n=e.searchParams.get(`layerid`);if(n&&jr.test(n))return`0/${n}`}let t=e.pathname.replace(/\/+$/,``);if(/^\/\d+\/[A-Za-z0-9]+$/.test(t)||/^\/0\/[A-Za-z0-9]+$/.test(t)||/^\/tv\/show\/\d+:(?:[\da-f]{32}|\d{16,})$/i.test(t))return t.slice(1)}},Fr=class extends P{API_ORIGIN=`https://global.apis.naver.com/weverse/wevweb`;API_APP_ID=`be4d79eb8fc7bd008ee82c8ec4ff6fd4`;API_HMAC_KEY=`1b9cb6378d959b45714bec49971ade22e6e24e42`;HEADERS={Accept:`application/json, text/plain, */*`,Origin:`https://weverse.io`,Referer:`https://weverse.io/`};getURLData(){return{appId:this.API_APP_ID,language:`en`,os:`WEB`,platform:`WEB`,wpf:`pc`}}async createHash(e){let t=Date.now(),n=e.substring(0,Math.min(255,e.length))+t,r=await Tt(this.API_HMAC_KEY,n);if(!r)throw new N(`Failed to get weverse HMAC signature`);return{wmsgpad:t.toString(),wmd:r}}async getHashURLParams(e){let t=await this.createHash(e);return new URLSearchParams(t).toString()}async getPostPreview(e){let t=`/post/v1.0/post-${e}/preview?`+new URLSearchParams({fieldSet:`postForPreview`,...this.getURLData()}).toString();try{let e=await this.getHashURLParams(t);return await(await this.fetch(`${this.API_ORIGIN+t}&${e}`,{headers:this.HEADERS})).json()}catch(t){return T.error(`Failed to get weverse post preview by postId: ${e}`,t.message),!1}}async getVideoInKey(e){let t=`/video/v1.1/vod/${e}/inKey?`+new URLSearchParams({gcc:`RU`,...this.getURLData()}).toString();try{let e=await this.getHashURLParams(t);return await(await this.fetch(`${this.API_ORIGIN+t}&${e}`,{method:`POST`,headers:this.HEADERS})).json()}catch(t){return T.error(`Failed to get weverse InKey by videoId: ${e}`,t.message),!1}}async getVideoInfo(e,t,n){let r=Date.now();try{let i=new URLSearchParams({key:t,sid:n,nonce:r.toString(),devt:`html5_pc`,prv:`N`,aup:`N`,stpb:`N`,cpl:`en`,env:`prod`,lc:`en`,adi:JSON.stringify([{adSystem:null}]),adu:`/`}).toString();return await(await this.fetch(`https://global.apis.naver.com/rmcnmv/rmcnmv/vod/play/v2.0/${e}?`+i,{headers:this.HEADERS})).json()}catch(r){return T.error(`Failed to get weverse video info (infraVideoId: ${e}, inkey: ${t}, serviceId: ${n}`,r.message),!1}}extractVideoInfo(e){return e.find(e=>e.useP2P===!1&&e.source.includes(`.mp4`))}async getVideoData(e){let t=await this.getPostPreview(e);if(!t)return;let{videoId:n,serviceId:r,infraVideoId:i}=t.extension.video;if(!(n&&r&&i))return;let a=await this.getVideoInKey(n);if(!a)return;let o=await this.getVideoInfo(i,a.inKey,r);if(!o)return;let s=this.extractVideoInfo(o.videos.list);if(s)return{url:s.source,duration:s.duration}}async getVideoId(e){return/([^/]+)\/(live|media)\/([^/]+)/.exec(e.pathname)?.[3]}},Ir=class extends P{async getVideoId(e){return/\/(videos\/[^/]+-[\dA-Za-z]+)\/?$/.exec(e.pathname)?.[1]}},Lr=class extends P{async getVideoId(e){return/[^/]+\/[^/]+$/.exec(e.pathname)?.[0]}},Rr=class extends P{API_ORIGIN=window.location.origin;CLIENT_PREFIX=`/client/disk`;INLINE_PREFIX=`/i/`;DISK_PREFIX=`/d/`;isErrorData(e){return Object.hasOwn(e,`error`)}async getClientVideoData(e){let t=new URL(window.location.href).searchParams.get(`idDialog`);if(!t)return;let n=document.querySelector(`#preloaded-data`);if(n)try{let{idClient:e,sk:r}=JSON.parse(n.innerText).config,i=await(await this.fetch(`${this.API_ORIGIN}/models-v2?m=mpfs/info`,{method:`POST`,body:JSON.stringify({apiMethod:`mpfs/info`,connection_id:e,requestParams:{path:t},sk:r}),headers:{"Content-Type":`application/json`}})).json();if(this.isErrorData(i))throw new N(i.error?.message??i.error?.code);if(i?.type!==`file`)throw new N(`Failed to get resource info`);let{meta:{short_url:a,video_info:o},name:s}=i;if(!o)throw new N(`There's no video open right now`);if(!a)throw new N(`Access to the video is limited`);return{url:a,title:this.clearTitle(s),duration:Math.round(o.duration/1e3)}}catch(t){T.error(`Failed to get yandex disk video data by video ID: ${e}, because ${t.message}`);return}}clearTitle(e){return e.replace(/(\.[^.]+)$/,``)}getBodyHash(e,t){let n=JSON.stringify({hash:e,sk:t});return encodeURIComponent(n)}async fetchList(e,t){let n=this.getBodyHash(e,t),r=await(await this.fetch(`${this.API_ORIGIN}/public/api/fetch-list`,{method:`POST`,body:n})).json();if(Object.hasOwn(r,`error`))throw new N(`Failed to fetch folder list`);return r.resources}async getDownloadUrl(e,t){let n=this.getBodyHash(e,t),r=await(await this.fetch(`${this.API_ORIGIN}/public/api/download-url`,{method:`POST`,body:n})).json();if(r.error)throw new N(`Failed to get download url`);return r.data.url}async getDiskVideoData(e){try{let t=document.getElementById(`store-prefetch`);if(!t)throw new N(`Failed to get prefetch data`);let n=e.split(`/`).slice(3);if(!n.length)throw new N(`Failed to find video file path`);let{resources:r,rootResourceId:i,environment:{sk:a}}=JSON.parse(t.innerText),o=r[i],s=n.length-1,c=n.filter((e,t)=>t!==s).join(`/`),l=Object.values(r);c.includes(`/`)&&(l=await this.fetchList(`${o.hash}:/${c}`,a));let u=l.find(e=>e.name===n[s]);if(!u)throw new N(`Failed to find resource`);if(u&&u.type===`dir`)throw new N(`Path is dir, but expected file`);let{meta:{short_url:d,mediatype:f,videoDuration:p},path:m,name:h}=u;if(f!==`video`)throw new N(`Resource isn't a video`);let g=this.clearTitle(h),_=Math.round(p/1e3);if(d)return{url:d,duration:_,title:g};let v=await this.getDownloadUrl(m,a);return{url:D(new URL(v)),duration:_,title:g}}catch(t){T.error(`Failed to get yandex disk video data by disk video ID: ${e}`,t.message);return}}async getVideoData(e){return e.startsWith(this.INLINE_PREFIX)||/^\/d\/([^/]+)$/.exec(e)?{url:this.service?.url+e.slice(1)}:(e=decodeURIComponent(e),e.startsWith(this.CLIENT_PREFIX)?await this.getClientVideoData(e):await this.getDiskVideoData(e))}async getVideoId(e){return e.pathname.startsWith(this.CLIENT_PREFIX)?e.pathname+e.search:/\/i\/([^/]+)/.exec(e.pathname)?.[0]||(/\/d\/([^/]+)/.exec(e.pathname)?e.pathname:void 0)}},zr=class extends P{async getVideoId(e){return/v_show\/id_[\w=]+/.exec(e.pathname)?.[0]}},F=class e extends P{static isMobile(){return/^m\.youtube\.com$/.test(window.location.hostname)}static extractVideoId(t){let n=t.hash.replace(/^#/,``);if(n){let r=n.startsWith(`!`)?n.slice(1):n,i=r;try{i=decodeURIComponent(r)}catch{}try{let n=i.startsWith(`http`)?new URL(i):new URL(i.startsWith(`/`)?i:`/${i}`,t.origin),r=e.extractVideoId(n);if(r)return r}catch{let e=/(?:^|[?&#])v=([^&#]+)/.exec(i)?.[1];if(e)return e}}return t.hostname===`youtu.be`?t.pathname.replace(/^\/+/,``).split(`/`)[0]||void 0:(/\/(?:watch|embed|shorts|live|v|e)\/([^/?#]+)/.exec(t.pathname)?.[1]??void 0)||(t.searchParams.get(`v`)??void 0)}static getPlayer(){return window.location.pathname.startsWith(`/shorts/`)&&!e.isMobile()?document.querySelector(`#shorts-player`):document.querySelector(`#movie_player`)}static getPlayerResponse(){return e.getPlayer()?.getPlayerResponse?.call(void 0)}static getPlayerData(){return e.getPlayer()?.getVideoData?.call(void 0)}static getVolume(){let t=e.getPlayer();return t?.getVolume?t.getVolume()/100:1}static setVolume(t){let n=e.getPlayer();return n?.setVolume?(n.setVolume(Math.round(t*100)),!0):!1}static isMuted(){let t=e.getPlayer();return t?.isMuted?t.isMuted():!1}static videoSeek(t,n){T.log(`videoSeek`,n),t.currentTime=(e.getPlayer()?.getProgressState()?.seekableEnd??t.currentTime)-n}static getPoToken(){let t=e.getPlayer();if(!t)return;let n=t.getAudioTrack?.call(void 0);if(!n?.captionTracks?.length)return;let r=n.captionTracks.find(e=>e.url.includes(`&pot=`));if(r)return/&pot=([^&]+)/.exec(r.url)?.[1]}static getGlobalConfig(){return typeof yt<`u`?yt?.config_:typeof ytcfg<`u`?ytcfg?.data_:void 0}static getDeviceParams(){let t=e.getGlobalConfig();if(!t)return`c=WEB`;let n=t.INNERTUBE_CONTEXT?.client,r=new URLSearchParams(t.DEVICE);return r.delete(`ceng`),r.delete(`cengver`),r.set(`c`,n?.clientName??t.INNERTUBE_CLIENT_NAME),r.set(`cver`,n?.clientVersion??t.INNERTUBE_CLIENT_VERSION),r.set(`cplayer`,`UNIPLAYER`),r.toString()}static getSubtitles(t){let n=e.getPlayerResponse()?.captions?.playerCaptionsTracklistRenderer;if(!n)return[];let r=n.captionTracks??[],i=(n.translationLanguages??[]).find(e=>e.languageCode===t),a=r.find(e=>e?.kind===`asr`)?.languageCode??`en`,o=r.reduce((e,n)=>{if(!(`languageCode`in n))return e;let r=n.languageCode?E(n.languageCode):void 0,o=n.baseUrl;if(!r||!o)return e;let s=`${o.startsWith(`http`)?o:`${window.location.origin}/${o}`}&fmt=json3`;return e.push({source:`youtube`,format:`json`,language:r,isAutoGenerated:n?.kind===`asr`,url:s}),i&&n.isTranslatable&&n.languageCode===a&&t!==r&&e.push({source:`youtube`,format:`json`,language:t,isAutoGenerated:n?.kind===`asr`,translatedFromLanguage:r,url:`${s}&tlang=${t}`}),e},[]);return T.log(`youtube subtitles:`,o),o}static getLanguage(){if(!e.isMobile()){let t=e.getPlayer()?.getAudioTrack?.call(void 0)?.getLanguageInfo();if(t&&t.id!==`und`)return E(t.id.split(`.`)[0])}let t=e.getPlayerResponse()?.captions?.playerCaptionsTracklistRenderer.captionTracks.find(e=>e.kind===`asr`&&e.languageCode);return t?E(t.languageCode):void 0}async getVideoData(t){let{title:n}=e.getPlayerData()??{},{shortDescription:r,isLive:i,title:a}=e.getPlayerResponse()?.videoDetails??{},o=e.getSubtitles(this.language),s=e.getLanguage();s&&!yn.includes(s)&&(s=void 0);let c=e.getPlayer()?.getDuration?.call(void 0)??void 0;return{url:this.service?.url+t,isStream:i,title:a,localizedTitle:n,detectedLanguage:s,description:r,subtitles:o,duration:c}}async getVideoId(t){if(t.searchParams.has(`enablejsapi`)){let n=e.getPlayer()?.getVideoUrl();t=n?new URL(n):t}return e.extractVideoId(t)}},Br=/^\/play\/([^/?#]+)\/([^/?#]+)\/([^/?#]+)\/?$/i,Vr=class extends P{async getVideoId(e){let t=Br.exec(e.pathname);if(!t)return;let[,n,r,i]=t;return`${n}/${r}/${i}`}},Hr={[k.mailru]:Un,[k.weverse]:Fr,[k.weibo]:Pr,[k.kodik]:zn,[k.patreon]:$n,[k.reddit]:ar,[k.bannedvideo]:dn,[k.kick]:Ln,[k.appledeveloper]:cn,[k.epicgames]:kn,[k.odysee]:Yn,[k.coursehunterLike]:vn,[k.twitch]:gr,[k.sap]:ur,[k.jove]:In,[k.linkedin]:Bn,[k.vimeo]:Dr,[k.yandexdisk]:Rr,[k.vk]:Or,[k.trovo]:hr,[k.incestflix]:Fn,[k.porntn]:rr,[k.googledrive]:Mn,[k.bilibili]:fn,[k.xvideos]:Lr,[k.xhamster]:Ir,[k.spankbang]:dr,[k.rule34video]:sr,[k.picarto]:tr,[k.olympicsreplay]:Zn,[k.watchpornto]:kr,[k.archive]:ln,[k.dailymotion]:Cn,[k.youku]:zr,[k.egghead]:On,[k.newgrounds]:Kn,[k.okru]:Xn,[k.peertube]:er,[k.eporner]:An,[k.bitchute]:pn,[k.rutube]:lr,[k.facebook]:jn,[k.rumble]:cr,[k.twitter]:_r,[k.pornhub]:nr,[k.tiktok]:mr,[k.proxitok]:mr,[k.nine_gag]:Jn,[k.youtube]:F,[k.preservetube]:ir,[k.invidious]:F,[k.piped]:F,[k.zdf]:Vr,[k.dzen]:Dn,[k.bunnystream]:gn,[k.cloudflarestream]:_n,[k.loom]:Hn,[k.rtnews]:or,[k.bitview]:mn,[k.thisvid]:pr,[k.ign]:Nn,[k.bunkr]:hn,[k.imdb]:Pn,[k.telegram]:fr,[k.niconico]:qn,[j.udemy]:Er,[j.coursera]:Sn,[j.douyin]:En,[j.artstation]:un,[j.kickstarter]:Rn,[j.datacamp]:wn,[j.oraclelearn]:Qn,[j.deeplearningai]:Tn,[j.netacad]:Gn,[j.mediafile]:Wn},Ur=class{helpersData;constructor(e={}){this.helpersData=e}getHelper(e){return new Hr[e](this.helpersData)}};function Wr(e){return e in Hr}function Gr(){if(en.exec(window.location.href))return[];let e=window.location.hostname,t=new URL(window.location.href),n=n=>n instanceof RegExp?n.test(e):typeof n==`string`?e.includes(n):typeof n==`function`?n(t):!1;return sn.filter(e=>!!e.match&&(Array.isArray(e.match)?e.match.some(n):n(e.match))&&e.host&&e.url)}async function Kr(e,t={}){let n=new URL(window.location.href),r=e.host;return Wr(r)?await new Ur(t).getHelper(r).getVideoId(n):r===k.custom?n.href:void 0}async function qr(e,t={}){let n=new URL(window.location.href),r=await Kr(e,t);if(!r)throw new $t(`Entered unsupported link: "${e.host}"`);let i=n.origin;if([k.peertube,k.coursehunterLike,k.bunnystream,k.cloudflarestream].includes(e.host)&&(e.url=i),e.rawResult)return{url:r,videoId:r,host:e.host,duration:void 0};if(!e.needExtraData)return{url:e.url+r,videoId:r,host:e.host,duration:void 0};if(!Wr(e.host))throw new $t(`No helper is available for "${e.host}"`);let a=await new Ur({...t,service:e,origin:i}).getHelper(e.host).getVideoData(r);if(!a)throw new $t(`Failed to get video raw url for ${e.host}`);return{...a,url:a.url,videoId:r,host:e.host}}var Jr={version:`1.0.6`,debug:!1,fetchFn:(e,t)=>globalThis.fetch(e,t)},I={log:(...e)=>{if(Jr.debug)return console.log(`%c✦ chaimu.js v${Jr.version} ✦`,`background: #000; color: #fff; padding: 0 8px`,...e)}},Yr=[`playing`,`ratechange`,`play`,`waiting`,`pause`,`seeked`],Xr=new Set([`play`,`playing`,`seeked`]),Zr=new Set([`pause`,`waiting`]),Qr=new Set([`ratechange`]);function $r(){let e=window.AudioContext??window.webkitAudioContext;return e?new e:void 0}var ei=class{static name=`BasePlayer`;chaimu;fetch;_src;fetchOpts;constructor(e,t){this.chaimu=e,this._src=t,this.fetch=this.chaimu.fetchFn,this.fetchOpts=this.chaimu.fetchOpts}async init(){return this}async clear(){return this}lipSync(e=!1){return this}handleVideoEvent=e=>(I.log(`handle video ${e.type}`),this.lipSync(e.type),this);removeVideoEvents(){for(let e of Yr)this.chaimu.video?.removeEventListener(e,this.handleVideoEvent);return this}addVideoEvents(){for(let e of Yr)this.chaimu.video?.addEventListener(e,this.handleVideoEvent);return this}async play(){return this}async pause(){return this}get name(){return this.constructor.name}set src(e){this._src=e}get src(){return this._src}get currentSrc(){return this._src}set volume(e){}get volume(){return 0}get playbackRate(){return 0}set playbackRate(e){}get currentTime(){return 0}shouldResumeFromVideo(e,t){return!!(e&&(Xr.has(e)||t?.has(e)))}shouldPauseFromVideo(e){return!!(e&&Zr.has(e))}},ti=class extends ei{static name=`AudioPlayer`;audio;gainNode;audioSource;gainValue=1;constructor(e,t){super(e,t),this.updateAudio()}initAudioBooster(){if(!this.chaimu.audioContext)return this;this.disconnectAudioNodes();let e=this.chaimu.audioContext.createGain();return this.gainNode=e,e.gain.value=this.gainValue,e.connect(this.chaimu.audioContext.destination),this.audioSource=this.chaimu.audioContext.createMediaElementSource(this.audio),this.audioSource.connect(e),this}disconnectAudioNodes(){this.audioSource&&=(this.audioSource.disconnect(),void 0),this.gainNode&&=(this.gainNode.disconnect(),void 0)}updateAudio(){return this.audio?.pause(),this.audio=new Audio(this.src),this.audio.crossOrigin=`anonymous`,this.audio.volume=this.gainValue,this}async init(){return this.updateAudio(),this.initAudioBooster(),this}audioErrorHandle=e=>{console.error(`[AudioPlayer]`,e)};syncAudioToVideo(){return this.chaimu.video?(this.audio.currentTime=this.chaimu.video.currentTime,this.audio.playbackRate=this.chaimu.video.playbackRate,!0):!1}lipSync(e=!1){return I.log(`[AudioPlayer] lipsync video`,this.chaimu.video),this.syncAudioToVideo()?e?(I.log(`[AudioPlayer] lipsync mode is ${e}`),this.shouldResumeFromVideo(e)&&!this.chaimu.video.paused?(this.play(),this):(this.shouldPauseFromVideo(e)&&this.pause(),this)):(I.log(`[AudioPlayer] lipsync mode isn't set`),this):this}async clear(){return this.audio.pause(),this.audio.src=``,this.audio.removeAttribute(`src`),this.disconnectAudioNodes(),this}async play(){return I.log(`[AudioPlayer] play called`),this.audio&&await this.audio.play().catch(this.audioErrorHandle),this}async pause(){return I.log(`[AudioPlayer] pause called`),this.audio&&this.audio.pause(),this}set src(e){if(this._src=e,!e){this.clear();return}this.audio.src=e}get src(){return this._src}get currentSrc(){return this.audio.currentSrc}set volume(e){if(this.gainValue=e,this.gainNode){this.gainNode.gain.value=e;return}this.audio.volume=e}get volume(){return this.gainNode?this.gainNode.gain.value:this.audio.volume}get playbackRate(){return this.audio.playbackRate}set playbackRate(e){this.audio.playbackRate=e}get currentTime(){return this.audio.currentTime}},ni=class extends ei{static name=`ChaimuPlayer`;audioElement;mediaElementSource;gainNode;blobUrl;gainValue=1;async createBlobUrl(){if(!this._src)throw Error(`No audio source provided`);I.log(`[ChaimuPlayer] Fetching audio from ${this._src}...`);let e=await this.fetch(this._src,this.fetchOpts);if(!e.ok)throw Error(`Failed to fetch audio file: ${e.status} ${e.statusText}`.trim());let t=await e.blob();return URL.createObjectURL(t)}initAudioBooster(){return this.chaimu.audioContext?(this.disconnectAudioNodes(),this.gainNode=this.chaimu.audioContext.createGain(),this.gainNode.gain.value=this.gainValue,this):this}disconnectAudioNodes(){this.mediaElementSource&&=(this.mediaElementSource.disconnect(),void 0),this.gainNode&&=(this.gainNode.disconnect(),void 0)}revokeBlobUrl(){this.blobUrl&&=(URL.revokeObjectURL(this.blobUrl),void 0)}async init(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);await this.clear();let e=await this.createBlobUrl();try{return this.initAudioBooster(),this.createAudioElement(e),this.blobUrl=e,this}catch(t){throw URL.revokeObjectURL(e),t}}createAudioElement(e){if(!this.chaimu.audioContext)throw Error(`No audio context available`);let t=new Audio(e);t.crossOrigin=`anonymous`,`preservesPitch`in t&&(t.preservesPitch=!0,`mozPreservesPitch`in t&&(t.mozPreservesPitch=!0),`webkitPreservesPitch`in t&&(t.webkitPreservesPitch=!0)),this.audioElement=t;let n=this.gainNode;if(!n)throw Error(`Audio gain node is missing`);this.mediaElementSource=this.chaimu.audioContext.createMediaElementSource(t),this.mediaElementSource.connect(n),n.connect(this.chaimu.audioContext.destination)}syncAudioToVideo(){return!this.audioElement||!this.chaimu.video?!1:(this.audioElement.currentTime=this.chaimu.video.currentTime,this.audioElement.playbackRate=this.chaimu.video.playbackRate,!0)}lipSync(e=!1){return I.log(`[ChaimuPlayer] lipsync video`,this.chaimu.video,this),this.chaimu.video?e?(I.log(`[ChaimuPlayer] lipsync mode is ${e}`),this.shouldResumeFromVideo(e,Qr)&&!this.chaimu.video.paused?(this.play(),this):(this.shouldPauseFromVideo(e)&&this.pause(),this)):(I.log(`[ChaimuPlayer] lipsync mode isn't set`),this):this}async clear(){return this.audioElement&&=(this.audioElement.pause(),this.audioElement.src=``,this.audioElement.removeAttribute(`src`),this.audioElement.load(),void 0),this.revokeBlobUrl(),this.disconnectAudioNodes(),this}async resumeContext(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);if(this.chaimu.audioContext.state===`closed`)throw Error(`Audio context is closed`);this.chaimu.audioContext.state===`suspended`&&await this.chaimu.audioContext.resume()}async pause(){if(!this.chaimu.audioContext)throw Error(`No audio context available`);return this.audioElement&&this.audioElement.pause(),this.chaimu.audioContext.state===`running`&&await this.chaimu.audioContext.suspend(),this}async play(){if(!this.audioElement)throw Error(`Audio element is missing`);await this.resumeContext(),this.syncAudioToVideo();try{await this.audioElement.play()}catch(e){I.log(`[ChaimuPlayer] Play audioElement failed:`,e)}return this}set src(e){this._src=e,e||this.clear()}get src(){return this._src}get currentSrc(){return this._src}set volume(e){this.gainValue=e,this.gainNode&&(this.gainNode.gain.value=e)}get volume(){return this.gainNode?this.gainNode.gain.value:this.gainValue}set playbackRate(e){this.audioElement&&(this.audioElement.playbackRate=e)}get playbackRate(){return this.audioElement?this.audioElement.playbackRate:this.chaimu.video?.playbackRate??1}get currentTime(){return this.audioElement?.currentTime??this.chaimu.video?.currentTime??0}},ri=class{_debug=!1;audioContext;player;video;fetchFn;fetchOpts;constructor({url:e,video:t,debug:n=!1,fetchFn:r=Jr.fetchFn,fetchOpts:i={},preferAudio:a=!1}){this._debug=Jr.debug=n,this.fetchFn=r,this.fetchOpts=i,this.audioContext=$r(),this.player=this.audioContext&&!a?new ni(this,e):new ti(this,e),this.video=t}async init(){await this.player.init(),this.video&&!this.video.paused&&this.player.lipSync(`play`),this.player.addVideoEvents()}set debug(e){this._debug=Jr.debug=e}get debug(){return this._debug}},ii=`__VOT_MAIN_BOOT_STATE__`;function ai(e){return e===`idle`||e===`booting`||e===`booted`||e===`failed`}function oi(e){return!e||typeof e!=`object`?!1:ai(e.status)}function si(e=ii){let t=globalThis,n=t[e];if(oi(n))return n;let r={status:`idle`,promise:null,error:null};return t[e]=r,r}var ci=!1;function li(){if(ci)return;ci=!0;let e=Object.entries({"https://dev.epicgames.com":{targetOrigin:`https://dev.epicgames.com`,dataFilter:e=>typeof e==`string`&&e.startsWith(`getVideoId:`),extractVideoId:e=>e.pathname.split(`/`).at(-2)??null,responseFormatter:(e,t)=>`${typeof t==`string`?t:``}:${e}`},"https://www.dailymotion.com":{targetOrigin:`https://geo.dailymotion.com`,dataFilter:e=>typeof e==`string`&&e.startsWith(`getVideoId:`),extractVideoId:e=>/(?:^|\/)video\/([^/]+)/.exec(e.pathname)?.[1],responseFormatter:e=>`getVideoId:${e}`}}).find(([e])=>globalThis.location.origin===e)?.[1];e&&globalThis.addEventListener(`message`,t=>{try{if(t.origin!==e.targetOrigin||!e.dataFilter(t.data))return;let n=e.extractVideoId(new URL(globalThis.location.href));if(!n)return;let r=e.responseFormatter(n,t.data);t.source&&`postMessage`in t.source&&t.source.postMessage(r,e.targetOrigin)}catch(e){console.error(`Iframe communication error:`,e)}})}var ui=`api.browser.yandex.ru`,di=`media-proxy.toil.cc/v1/proxy/m3u8`,fi=`vot-new.toil-dump.workers.dev`,pi=`vot-worker.kload.workers.dev`,mi=`https://vot.toil.cc/v1`,hi=`https://translate-backend.transly.workers.dev/v2`,gi=`https://rust-server-531j.onrender.com/detect`,_i=`https://rust-server-531j.onrender.com`,vi=`https://avatars.mds.yandex.net/get-yapic`,yi=`ilyhalight/voice-over-translation`,bi=`https://raw.githubusercontent.com/${yi}`,xi=`https://github.com/${yi}`,Si=`yandexbrowser`,Ci=`yandexbrowser`,wi=[`UA`,`LV`,`LT`],Ti=1e3,Ei=`2025-05-09`,Di=[`auto`,`original`],Oi=`autoTranslate.autoSubtitles.dontTranslateLanguages.enabledDontTranslateLanguages.enabledAutoVolume.enabledSmartDucking.autoVolume.buttonPos.showVideoSlider.syncVolume.downloadWithName.sendNotifyOnComplete.subtitlesMaxLength.subtitlesSmartLayout.highlightWords.subtitlesFontSize.subtitlesFontFamily.subtitlesOpacity.subtitlesDownloadFormat.responseLanguage.responseLanguageSubtitles.defaultVolume.onlyBypassMediaCSP.newAudioPlayer.showPiPButton.translateAPIErrors.translationService.detectService.translationHotkey.subtitlesHotkey.m3u8ProxyHost.proxyWorkerHost.translateProxyEnabled.translateProxyEnabledDefault.audioBooster.useLivelyVoice.autoHideButtonDelay.useAudioDownload.compatVersion.localePhrases.localeLang.localeHash.localeVersion.localeUpdatedAt.localeLangOverride.account`.split(`.`),L={log:(...e)=>{console.log(`%c[VOT DEBUG]`,`background: #3700ffff; color: #fff; padding: 5px;`,...e)},warn:(...e)=>{console.warn(`%c[VOT DEBUG]`,`background: #e1ff00ff; color: #fff; padding: 5px;`,...e)},error:(...e)=>{console.error(`%c[VOT DEBUG]`,`background: #F2452D; color: #fff; padding: 5px;`,...e)}};function ki(){return navigator.language?.substring(0,2).toLowerCase()||`en`}var Ai=new Set([`uk`,`be`,`bg`,`mk`,`sr`,`bs`,`hr`,`sl`,`pl`,`sk`,`cs`]);function ji(e){return bn.includes(e)?e:Ai.has(e)?`ru`:`en`}var Mi=ki(),Ni=ji(Mi),Pi=3e4,Fi=/\p{Cc}/gu,Ii=/[\\/:*?"'<>|]+/g,Li=/^https?:\/\//i,Ri=/-{2,}/g,zi=/^[.\s-]+|[.\s-]+$/g;function Bi(){return new Date().toISOString().slice(0,10)}function Vi(e){return e.replace(Fi,``)}function Hi(e){let t=new WeakSet;return JSON.stringify(e,(e,n)=>{if(n&&typeof n==`object`){if(t.has(n))return`[Circular]`;if(t.add(n),Array.isArray(n))return n;let e={},r=Object.keys(n).sort();for(let t of r)e[t]=n[t];return e}return n})}function Ui(e){let t=2166136261,n=0;for(;n65535?2:1}return(t>>>0).toString(36)}var Wi=()=>!!document.pictureInPictureEnabled;async function Gi(e,t){try{let n=await e.createWritable();return await n.write(t),await n.close(),!0}catch{return!1}}async function Ki(e,t){let n=typeof navigator>`u`?void 0:navigator;if(!n?.share||typeof File>`u`)return`unsupported`;let r;try{r=new File([e],t,{type:e.type||`application/octet-stream`})}catch{return`unsupported`}if(typeof n.canShare==`function`&&!n.canShare({files:[r]}))return`unsupported`;try{return await n.share({files:[r],title:t}),`shared`}catch(e){return e instanceof DOMException&&e.name===`AbortError`?`shared`:`error`}}function qi(e,t){let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,r.rel=`noopener noreferrer`,r.target=`_blank`,r.style.position=`fixed`,r.style.left=`-9999px`,r.style.top=`0`,(document.body??document.documentElement).append(r);try{return r.click(),!0}catch{return!1}finally{r.remove(),Yi(n)}}async function Ji(e,t,n={}){return n.fileHandle&&await Gi(n.fileHandle,e)||n.preferShare&&await Ki(e,t)===`shared`?!0:qi(e,t)}function Yi(e,t=Pi){let n=Number.isFinite(t)&&t>=0?t:Pi;globalThis.setTimeout(()=>URL.revokeObjectURL(e),n)}function Xi(e){let t=e.trim();return t&&Vi(t).replace(Li,``).replace(Ii,`-`).replace(Ri,`-`).replace(zi,``)||Bi()}var Zi=()=>Math.floor(Date.now()/1e3),Qi=e=>e?Object.fromEntries(new Headers(e)):{};function R(e,t=0,n=100){return Math.min(Math.max(e,Math.min(t,n)),Math.max(t,n))}function $i(e){let t={},n=Object.entries(e);for(;n.length;){let e=n.pop();if(!e)continue;let[r,i]=e;if(i!==void 0){if(!(typeof i==`object`&&i&&!Array.isArray(i))){t[r]=i;continue}for(let[e,t]of Object.entries(i))n.push([`${r}.${e}`,t])}}return t}var ea=7200*1e3,ta=`x-vot-cache-created-at`,na=`x-vot-cache-key`,ra=`vot-http-cache-v1`,ia=500,aa=`VOTSession`,oa={translation:`translationExpiresAt`,subtitles:`subtitlesExpiresAt`};function sa(){return Math.floor(Date.now()/1e3)}function ca(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.expires==`number`&&Number.isFinite(t.expires)&&typeof t.timestamp==`number`&&Number.isFinite(t.timestamp)&&typeof t.uuid==`string`&&t.uuid.length>0&&typeof t.secretKey==`string`&&t.secretKey.length>0}function la(e){if(!e||typeof e!=`object`)return{};let t=sa(),n=Object.entries(e).flatMap(([e,n])=>!ca(n)||n.timestamp+n.expires<=t?[]:[[e,n]]);return Object.fromEntries(n)}function ua(e){return Object.keys(e).length>0}var da=class{constructor(e=B){this.storage=e}getStorageKey(){return aa}async restore(e,t={}){let n=this.getStorageKey(),r=await this.storage.getRaw(n),i=la(r);return ua(i)?{...t,...i}:(r!==void 0&&await this.storage.deleteRaw(n),t)}async persist(e,t){let n=this.getStorageKey(),r=la(t);if(!ua(r)){await this.storage.deleteRaw(n);return}await this.storage.setRaw(n,r)}},fa=class{cache=new Map;clear(){this.cache.clear()}getTranslation(e){return this.getValue(e,`translation`)}setTranslation(e,t){this.setValue(e,`translation`,t)}getSubtitles(e){return this.getValue(e,`subtitles`)}setSubtitles(e,t){this.setValue(e,`subtitles`,t)}deleteSubtitles(e){this.deleteValue(e,`subtitles`)}getValue(e,t){let n=Date.now(),r=this.cache.get(e);if(!r)return;let i=oa[t],a=r[i];if(a!==void 0&&a<=n){r[t]=void 0,r[i]=void 0,this.evictIfEmpty(e,r);return}return r[t]}setValue(e,t,n){let r=Date.now(),i=this.getOrCreateEntry(e),a=r+ea,o=oa[t];i[t]=n,i[o]=a}deleteValue(e,t){let n=this.cache.get(e);if(!n)return;let r=oa[t];n[t]=void 0,n[r]=void 0,this.evictIfEmpty(e,n)}evictIfEmpty(e,t){t.translation===void 0&&t.subtitles===void 0&&this.cache.delete(e)}getOrCreateEntry(e){let t=this.cache.get(e);if(t)return t;let n={};return this.cache.set(e,n),n}},pa=new class{memoryCache=new Map;inFlightRequests=new Map;async execute(e,t,n){if(!t||t.ttlMs<=0)return n();let r=t.key??this.buildDefaultCacheKey(e);if(!r)return n();let i=this.normalizeMethod(e.method),a=t.ttlMs,o=t.cacheName||ra,s=t.useMemory!==!1,c=t.useCacheApi!==!1&&i===`GET`&&this.supportsCacheApi(),l=c?Ui(r):``,u=t.dedupe!==!1,d=t.allowStaleOnError!==!1,f=Date.now(),p=await this.readCachedResponse({key:r,nowMs:f,useMemory:s,useCacheApi:c,cacheName:o,url:e.url,cacheApiKey:l,ttlMs:a,allowStaleOnError:d});if(p.fresh)return p.fresh;if(!u)return await this.runNetworkRequestWithFallback({key:r,cacheName:o,url:e.url,cacheApiKey:l,ttlMs:a,useMemory:s,useCacheApi:c},n,d?p.stale:void 0);let m=this.inFlightRequests.get(r);if(m!==void 0)return(await m).clone();let h=this.runNetworkRequestWithFallback({key:r,cacheName:o,url:e.url,cacheApiKey:l,ttlMs:a,useMemory:s,useCacheApi:c},n,d?p.stale?.clone():void 0);this.inFlightRequests.set(r,h);try{return(await h).clone()}finally{this.inFlightRequests.delete(r)}}async readCachedResponse({key:e,nowMs:t,useMemory:n,useCacheApi:r,cacheName:i,url:a,cacheApiKey:o,ttlMs:s,allowStaleOnError:c}){let l;if(n){let n=this.readMemoryCache(e,t);if(n.fresh)return{fresh:n.fresh};l=n.stale}if(!r)return{stale:l};let u=await this.readCacheApi(i,a,o,s,t,c);return u.fresh?(n&&this.writeMemoryCache(e,u.fresh.clone(),u.expiresAt??t+s),{fresh:u.fresh}):{stale:l??u.stale}}async runNetworkRequestWithFallback(e,t,n){try{return await this.runNetworkRequest(e,t)}catch(e){if(n)return n;throw e}}async runNetworkRequest({key:e,cacheName:t,url:n,cacheApiKey:r,ttlMs:i,useMemory:a,useCacheApi:o},s){let c=await s();if(!c.ok)return c;let l=Date.now(),u=this.computeExpiresAt(l,i);if(a&&this.writeMemoryCache(e,c.clone(),u),o){let e=this.toStorableResponse(c.clone(),l);await this.writeCacheApi(t,n,r,e)}return c}computeExpiresAt(e,t){return!Number.isFinite(t)||t<=0?e:t>=2**53-1-e?2**53-1:e+t}normalizeMethod(e){return(e||`GET`).toUpperCase()}resolveBodyKey(e){if(e==null)return``;if(typeof e==`string`)return e;if(e instanceof URLSearchParams)return e.toString()}buildDefaultCacheKey(e){let t=this.normalizeMethod(e.method);if(t===`GET`)return`${t}:${e.url}`;let n=this.resolveBodyKey(e.body);if(n!==void 0)return`${t}:${e.url}#${Ui(n)}`}supportsCacheApi(){return typeof caches<`u`&&typeof caches.open==`function`}readCreatedAtMs(e){let t=e.headers.get(ta);if(!t)return null;let n=Number(t);return Number.isFinite(n)?n:null}ensureVaryByCacheKey(e){let t=e.get(`vary`);if(!t){e.set(`vary`,na);return}let n=new Set(t.split(`,`).map(e=>e.trim().toLowerCase()));!n.has(`*`)&&!n.has(na)&&e.set(`vary`,`${t}, ${na}`)}toStorableResponse(e,t){let n=new Headers(e.headers);return n.set(ta,String(t)),this.ensureVaryByCacheKey(n),new Response(e.body,{status:e.status,statusText:e.statusText,headers:n})}readMemoryCache(e,t){let n=this.memoryCache.get(e);return n?n.expiresAt>t?(this.touchMemoryCache(e,n),{fresh:n.response.clone(),expiresAt:n.expiresAt}):(this.memoryCache.delete(e),{stale:n.response.clone(),expiresAt:n.expiresAt}):{}}touchMemoryCache(e,t){this.memoryCache.delete(e),this.memoryCache.set(e,t)}trimMemoryCache(){for(;this.memoryCache.size>ia;){let e=this.memoryCache.keys().next().value;if(typeof e!=`string`)break;this.memoryCache.delete(e)}}writeMemoryCache(e,t,n){this.memoryCache.has(e)&&this.memoryCache.delete(e),this.memoryCache.set(e,{response:t,expiresAt:n}),this.trimMemoryCache()}async readCacheApi(e,t,n,r,i,a){try{let o=new Request(t,{method:`GET`,headers:{[na]:n}}),s=await caches.open(e),c=await s.match(o);if(!c)return{};let l=this.readCreatedAtMs(c);if(l===null)return await s.delete(o),{};let u=this.computeExpiresAt(l,r);if(u>i)return{fresh:c.clone(),expiresAt:u};if(!a)return await s.delete(o),{};let d=c.clone();return await s.delete(o),{stale:d,expiresAt:u}}catch{return{}}}async writeCacheApi(e,t,n,r){try{let i=new Request(t,{method:`GET`,headers:{[na]:n}});await(await caches.open(e)).put(i,r)}catch{}}};async function ma(e,t,n){return pa.execute(e,t,n)}function ha(e){let t=new WeakSet;try{return JSON.stringify(e,(e,n)=>typeof n!=`object`||!n?n:t.has(n)?`[Circular]`:(t.add(n),n))??null}catch{return null}}function ga(e){let t=[e?.data?.message,e?.error?.message,e?.message];for(let e of t)if(typeof e==`string`&&e)return e;return null}function _a(e,t){let n=ga(e);if(n)return n;let r=ha(e);if(r&&r!==`{}`)return r;let i=e.constructor?.name;return i?`[${i}]`:t}function va(e,t){return typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`?`${e}`:typeof e==`symbol`?e.description?`Symbol(${e.description})`:`Symbol`:typeof e==`function`?e.name?`[Function ${e.name}]`:`[Function]`:t}function ya(e,t=`Unknown error`){return e instanceof Error?e.message||t:typeof e==`string`?e||t:e==null?t:typeof e==`object`?_a(e,t):va(e,t)}function ba(e){return ya(e,``)}function xa(e){let t=e;return typeof DOMException<`u`&&t instanceof DOMException&&t.name===`AbortError`||t instanceof Error&&t.name===`AbortError`||t?.message===`AbortError`}function Sa(e=`Aborted`){try{return new DOMException(e,`AbortError`)}catch{let t=Error(e);return t.name=`AbortError`,t}}var Ca=new AbortController().signal;function wa(e){let t=e.throwIfAborted;if(typeof t==`function`)try{t.call(e);return}catch(t){throw e.aborted||xa(t)?Sa():t instanceof Error?t:Error(String(t))}if(e.aborted)throw Sa()}function Ta(e,t){if(!(Number.isFinite(e)&&e>0))return{signal:t??Ca,cleanup:()=>{}};let n=new AbortController,r,i=()=>{r!==void 0&&(clearTimeout(r),r=void 0),n.abort(t?.reason)};return t&&(t.addEventListener(`abort`,i,{once:!0}),t.aborted&&i()),n.signal.aborted||(r=setTimeout(()=>{n.abort(Sa(`Timeout`)),r=void 0},e)),{signal:n.signal,cleanup:()=>{r!==void 0&&(clearTimeout(r),r=void 0),t?.removeEventListener(`abort`,i)}}}var Ea=d(c(((e,t)=>{(function(n,r){typeof e==`object`&&typeof t==`object`?t.exports=r():typeof define==`function`&&define.amd?define([],r):typeof e==`object`?e.bowser=r():n.bowser=r()})(e,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){typeof Symbol<`u`&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),Object.defineProperty(e,`__esModule`,{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t||4&t&&typeof e==`object`&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,`default`,{enumerable:!0,value:e}),2&t&&typeof e!=`string`)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,`a`,t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=``,n(n.s=90)}({17:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r=n(18);t.default=function(){function e(){}return e.getFirstMatch=function(e,t){var n=t.match(e);return n&&n.length>0&&n[1]||``},e.getSecondMatch=function(e,t){var n=t.match(e);return n&&n.length>1&&n[2]||``},e.matchAndReturnConst=function(e,t,n){if(e.test(t))return n},e.getWindowsVersionName=function(e){switch(e){case`NT`:return`NT`;case`XP`:return`XP`;case`NT 5.0`:return`2000`;case`NT 5.1`:return`XP`;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}},e.getMacOSVersionName=function(e){var t=e.split(`.`).splice(0,2).map((function(e){return parseInt(e,10)||0}));t.push(0);var n=t[0],r=t[1];if(n===10)switch(r){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}switch(n){case 11:return`Big Sur`;case 12:return`Monterey`;case 13:return`Ventura`;case 14:return`Sonoma`;case 15:return`Sequoia`;default:return}},e.getAndroidVersionName=function(e){var t=e.split(`.`).splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),!(t[0]===1&&t[1]<5))return t[0]===1&&t[1]<6?`Cupcake`:t[0]===1&&t[1]>=6?`Donut`:t[0]===2&&t[1]<2?`Eclair`:t[0]===2&&t[1]===2?`Froyo`:t[0]===2&&t[1]>2?`Gingerbread`:t[0]===3?`Honeycomb`:t[0]===4&&t[1]<1?`Ice Cream Sandwich`:t[0]===4&&t[1]<4?`Jelly Bean`:t[0]===4&&t[1]>=4?`KitKat`:t[0]===5?`Lollipop`:t[0]===6?`Marshmallow`:t[0]===7?`Nougat`:t[0]===8?`Oreo`:t[0]===9?`Pie`:void 0},e.getVersionPrecision=function(e){return e.split(`.`).length},e.compareVersions=function(t,n,r){r===void 0&&(r=!1);var i=e.getVersionPrecision(t),a=e.getVersionPrecision(n),o=Math.max(i,a),s=0,c=e.map([t,n],(function(t){var n=o-e.getVersionPrecision(t),r=t+Array(n+1).join(`.0`);return e.map(r.split(`.`),(function(e){return Array(20-e.length).join(`0`)+e})).reverse()}));for(r&&(s=o-Math.min(i,a)),--o;o>=s;){if(c[0][o]>c[1][o])return 1;if(c[0][o]===c[1][o]){if(o===s)return 0;--o}else if(c[0][o]1?i-1:0),o=1;o0){var o=Object.keys(n),c=s.default.find(o,(function(e){return t.isOS(e)}));if(c){var l=this.satisfies(n[c]);if(l!==void 0)return l}var u=s.default.find(o,(function(e){return t.isPlatform(e)}));if(u){var d=this.satisfies(n[u]);if(d!==void 0)return d}}if(a>0){var f=Object.keys(i),p=s.default.find(f,(function(e){return t.isBrowser(e,!0)}));if(p!==void 0)return this.compareVersion(i[p])}},t.isBrowser=function(e,t){t===void 0&&(t=!1);var n=this.getBrowserName().toLowerCase(),r=e.toLowerCase(),i=s.default.getBrowserTypeByAlias(r);return t&&i&&(r=i.toLowerCase()),r===n},t.compareVersion=function(e){var t=[0],n=e,r=!1,i=this.getBrowserVersion();if(typeof i==`string`)return e[0]===`>`||e[0]===`<`?(n=e.substr(1),e[1]===`=`?(r=!0,n=e.substr(2)):t=[],e[0]===`>`?t.push(1):t.push(-1)):e[0]===`=`?n=e.substr(1):e[0]===`~`&&(r=!0,n=e.substr(1)),t.indexOf(s.default.compareVersions(i,n,r))>-1},t.isOS=function(e){return this.getOSName(!0)===String(e).toLowerCase()},t.isPlatform=function(e){return this.getPlatformType(!0)===String(e).toLowerCase()},t.isEngine=function(e){return this.getEngineName(!0)===String(e).toLowerCase()},t.is=function(e,t){return t===void 0&&(t=!1),this.isBrowser(e,t)||this.isOS(e)||this.isPlatform(e)},t.some=function(e){var t=this;return e===void 0&&(e=[]),e.some((function(e){return t.is(e)}))},e}(),e.exports=t.default},92:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=/version\/(\d+(\.?_?\d+)+)/i;t.default=[{test:[/gptbot/i],describe:function(e){var t={name:`GPTBot`},n=i.default.getFirstMatch(/gptbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/chatgpt-user/i],describe:function(e){var t={name:`ChatGPT-User`},n=i.default.getFirstMatch(/chatgpt-user\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/oai-searchbot/i],describe:function(e){var t={name:`OAI-SearchBot`},n=i.default.getFirstMatch(/oai-searchbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/claudebot/i,/claude-web/i,/claude-user/i,/claude-searchbot/i],describe:function(e){var t={name:`ClaudeBot`},n=i.default.getFirstMatch(/(?:claudebot|claude-web|claude-user|claude-searchbot)\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/omgilibot/i,/webzio-extended/i],describe:function(e){var t={name:`Omgilibot`},n=i.default.getFirstMatch(/(?:omgilibot|webzio-extended)\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/diffbot/i],describe:function(e){var t={name:`Diffbot`},n=i.default.getFirstMatch(/diffbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/perplexitybot/i],describe:function(e){var t={name:`PerplexityBot`},n=i.default.getFirstMatch(/perplexitybot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/perplexity-user/i],describe:function(e){var t={name:`Perplexity-User`},n=i.default.getFirstMatch(/perplexity-user\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/youbot/i],describe:function(e){var t={name:`YouBot`},n=i.default.getFirstMatch(/youbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-webindexer/i],describe:function(e){var t={name:`Meta-WebIndexer`},n=i.default.getFirstMatch(/meta-webindexer\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-externalads/i],describe:function(e){var t={name:`Meta-ExternalAds`},n=i.default.getFirstMatch(/meta-externalads\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-externalagent/i],describe:function(e){var t={name:`Meta-ExternalAgent`},n=i.default.getFirstMatch(/meta-externalagent\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-externalfetcher/i],describe:function(e){var t={name:`Meta-ExternalFetcher`},n=i.default.getFirstMatch(/meta-externalfetcher\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/googlebot/i],describe:function(e){var t={name:`Googlebot`},n=i.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/linespider/i],describe:function(e){var t={name:`Linespider`},n=i.default.getFirstMatch(/(?:linespider)(?:-[-\w]+)?[\s/](\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/amazonbot/i],describe:function(e){var t={name:`AmazonBot`},n=i.default.getFirstMatch(/amazonbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/bingbot/i],describe:function(e){var t={name:`BingCrawler`},n=i.default.getFirstMatch(/bingbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/baiduspider/i],describe:function(e){var t={name:`BaiduSpider`},n=i.default.getFirstMatch(/baiduspider\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/duckduckbot/i],describe:function(e){var t={name:`DuckDuckBot`},n=i.default.getFirstMatch(/duckduckbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/ia_archiver/i],describe:function(e){var t={name:`InternetArchiveCrawler`},n=i.default.getFirstMatch(/ia_archiver\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/facebookexternalhit/i,/facebookcatalog/i],describe:function(){return{name:`FacebookExternalHit`}}},{test:[/slackbot/i,/slack-imgProxy/i],describe:function(e){var t={name:`SlackBot`},n=i.default.getFirstMatch(/(?:slackbot|slack-imgproxy)(?:-[-\w]+)?[\s/](\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/yahoo!?[\s/]*slurp/i],describe:function(){return{name:`YahooSlurp`}}},{test:[/yandexbot/i,/yandexmobilebot/i],describe:function(){return{name:`YandexBot`}}},{test:[/pingdom/i],describe:function(){return{name:`PingdomBot`}}},{test:[/opera/i],describe:function(e){var t={name:`Opera`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/opr\/|opios/i],describe:function(e){var t={name:`Opera`},n=i.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/SamsungBrowser/i],describe:function(e){var t={name:`Samsung Internet for Android`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/Whale/i],describe:function(e){var t={name:`NAVER Whale Browser`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/PaleMoon/i],describe:function(e){var t={name:`Pale Moon`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:PaleMoon)[\s/](\d+(?:\.\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/MZBrowser/i],describe:function(e){var t={name:`MZ Browser`},n=i.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/focus/i],describe:function(e){var t={name:`Focus`},n=i.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/swing/i],describe:function(e){var t={name:`Swing`},n=i.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/coast/i],describe:function(e){var t={name:`Opera Coast`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(e){var t={name:`Opera Touch`},n=i.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/yabrowser/i],describe:function(e){var t={name:`Yandex Browser`},n=i.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/ucbrowser/i],describe:function(e){var t={name:`UC Browser`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/Maxthon|mxios/i],describe:function(e){var t={name:`Maxthon`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/epiphany/i],describe:function(e){var t={name:`Epiphany`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/puffin/i],describe:function(e){var t={name:`Puffin`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/sleipnir/i],describe:function(e){var t={name:`Sleipnir`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/k-meleon/i],describe:function(e){var t={name:`K-Meleon`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/micromessenger/i],describe:function(e){var t={name:`WeChat`},n=i.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/qqbrowser/i],describe:function(e){var t={name:/qqbrowserlite/i.test(e)?`QQ Browser Lite`:`QQ Browser`},n=i.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/msie|trident/i],describe:function(e){var t={name:`Internet Explorer`},n=i.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/\sedg\//i],describe:function(e){var t={name:`Microsoft Edge`},n=i.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/edg([ea]|ios)/i],describe:function(e){var t={name:`Microsoft Edge`},n=i.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/vivaldi/i],describe:function(e){var t={name:`Vivaldi`},n=i.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/seamonkey/i],describe:function(e){var t={name:`SeaMonkey`},n=i.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/sailfish/i],describe:function(e){var t={name:`Sailfish`},n=i.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,e);return n&&(t.version=n),t}},{test:[/silk/i],describe:function(e){var t={name:`Amazon Silk`},n=i.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/phantom/i],describe:function(e){var t={name:`PhantomJS`},n=i.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/slimerjs/i],describe:function(e){var t={name:`SlimerJS`},n=i.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t={name:`BlackBerry`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t={name:`WebOS Browser`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/bada/i],describe:function(e){var t={name:`Bada`},n=i.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/tizen/i],describe:function(e){var t={name:`Tizen`},n=i.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/qupzilla/i],describe:function(e){var t={name:`QupZilla`},n=i.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/librewolf/i],describe:function(e){var t={name:`LibreWolf`},n=i.default.getFirstMatch(/(?:librewolf)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/firefox|iceweasel|fxios/i],describe:function(e){var t={name:`Firefox`},n=i.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/electron/i],describe:function(e){var t={name:`Electron`},n=i.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/sogoumobilebrowser/i,/metasr/i,/se 2\.[x]/i],describe:function(e){var t={name:`Sogou Browser`},n=i.default.getFirstMatch(/(?:sogoumobilebrowser)[\s/](\d+(\.?_?\d+)+)/i,e),r=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,e),a=i.default.getFirstMatch(/se ([\d.]+)x/i,e),o=n||r||a;return o&&(t.version=o),t}},{test:[/MiuiBrowser/i],describe:function(e){var t={name:`Miui`},n=i.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){return!!e.hasBrand(`DuckDuckGo`)||e.test(/\sDdg\/[\d.]+$/i)},describe:function(e,t){var n={name:`DuckDuckGo`};if(t){var r=t.getBrandVersion(`DuckDuckGo`);if(r)return n.version=r,n}var a=i.default.getFirstMatch(/\sDdg\/([\d.]+)$/i,e);return a&&(n.version=a),n}},{test:function(e){return e.hasBrand(`Brave`)},describe:function(e,t){var n={name:`Brave`};if(t){var r=t.getBrandVersion(`Brave`);if(r)return n.version=r,n}return n}},{test:[/chromium/i],describe:function(e){var t={name:`Chromium`},n=i.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/chrome|crios|crmo/i],describe:function(e){var t={name:`Chrome`},n=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/GSA/i],describe:function(e){var t={name:`Google Search`},n=i.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){var t=!e.test(/like android/i),n=e.test(/android/i);return t&&n},describe:function(e){var t={name:`Android Browser`},n=i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/playstation 4/i],describe:function(e){var t={name:`PlayStation 4`},n=i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/safari|applewebkit/i],describe:function(e){var t={name:`Safari`},n=i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/.*/i],describe:function(e){var t=e.search(`\\(`)===-1?/^(.*)\/(.*) /:/^(.*)\/(.*)[ \t]\((.*)/;return{name:i.default.getFirstMatch(t,e),version:i.default.getSecondMatch(t,e)}}}],e.exports=t.default},93:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=n(18);t.default=[{test:[/Roku\/DVP/],describe:function(e){var t=i.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,e);return{name:a.OS_MAP.Roku,version:t}}},{test:[/windows phone/i],describe:function(e){var t=i.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.WindowsPhone,version:t}}},{test:[/windows /i],describe:function(e){var t=i.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,e),n=i.default.getWindowsVersionName(t);return{name:a.OS_MAP.Windows,version:t,versionName:n}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(e){var t={name:a.OS_MAP.iOS},n=i.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,e);return n&&(t.version=n),t}},{test:[/macintosh/i],describe:function(e){var t=i.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,e).replace(/[_\s]/g,`.`),n=i.default.getMacOSVersionName(t),r={name:a.OS_MAP.MacOS,version:t};return n&&(r.versionName=n),r}},{test:[/(ipod|iphone|ipad)/i],describe:function(e){var t=i.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,e).replace(/[_\s]/g,`.`);return{name:a.OS_MAP.iOS,version:t}}},{test:[/OpenHarmony/i],describe:function(e){var t=i.default.getFirstMatch(/OpenHarmony\s+(\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.HarmonyOS,version:t}}},{test:function(e){var t=!e.test(/like android/i),n=e.test(/android/i);return t&&n},describe:function(e){var t=i.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,e),n=i.default.getAndroidVersionName(t),r={name:a.OS_MAP.Android,version:t};return n&&(r.versionName=n),r}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t=i.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,e),n={name:a.OS_MAP.WebOS};return t&&t.length&&(n.version=t),n}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t=i.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,e)||i.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,e)||i.default.getFirstMatch(/\bbb(\d+)/i,e);return{name:a.OS_MAP.BlackBerry,version:t}}},{test:[/bada/i],describe:function(e){var t=i.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.Bada,version:t}}},{test:[/tizen/i],describe:function(e){var t=i.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.Tizen,version:t}}},{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(e){var t=i.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.PlayStation4,version:t}}}],e.exports=t.default},94:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=n(18);t.default=[{test:[/googlebot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Google`}}},{test:[/linespider/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Line`}}},{test:[/amazonbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Amazon`}}},{test:[/gptbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`OpenAI`}}},{test:[/chatgpt-user/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`OpenAI`}}},{test:[/oai-searchbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`OpenAI`}}},{test:[/baiduspider/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Baidu`}}},{test:[/bingbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Bing`}}},{test:[/duckduckbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`DuckDuckGo`}}},{test:[/claudebot/i,/claude-web/i,/claude-user/i,/claude-searchbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Anthropic`}}},{test:[/omgilibot/i,/webzio-extended/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Webz.io`}}},{test:[/diffbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Diffbot`}}},{test:[/perplexitybot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Perplexity AI`}}},{test:[/perplexity-user/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Perplexity AI`}}},{test:[/youbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`You.com`}}},{test:[/ia_archiver/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Internet Archive`}}},{test:[/meta-webindexer/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/meta-externalads/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/meta-externalagent/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/meta-externalfetcher/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/facebookexternalhit/i,/facebookcatalog/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/slackbot/i,/slack-imgProxy/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Slack`}}},{test:[/yahoo/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Yahoo`}}},{test:[/yandexbot/i,/yandexmobilebot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Yandex`}}},{test:[/pingdom/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Pingdom`}}},{test:[/huawei/i],describe:function(e){var t=i.default.getFirstMatch(/(can-l01)/i,e)&&`Nova`,n={type:a.PLATFORMS_MAP.mobile,vendor:`Huawei`};return t&&(n.model=t),n}},{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(e){var t=e.test(/ipod|iphone/i),n=e.test(/like (ipod|iphone)/i);return t&&!n},describe:function(e){var t=i.default.getFirstMatch(/(ipod|iphone)/i,e);return{type:a.PLATFORMS_MAP.mobile,vendor:`Apple`,model:t}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:`Nexus`}}},{test:[/Nokia/i],describe:function(e){var t=i.default.getFirstMatch(/Nokia\s+([0-9]+(\.[0-9]+)?)/i,e),n={type:a.PLATFORMS_MAP.mobile,vendor:`Nokia`};return t&&(n.model=t),n}},{test:[/[^-]mobi/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(e){return e.getBrowserName(!0)===`blackberry`},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:`BlackBerry`}}},{test:function(e){return e.getBrowserName(!0)===`bada`},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(e){return e.getBrowserName()===`windows phone`},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:`Microsoft`}}},{test:function(e){var t=Number(String(e.getOSVersion()).split(`.`)[0]);return e.getOSName(!0)===`android`&&t>=3},describe:function(){return{type:a.PLATFORMS_MAP.tablet}}},{test:function(e){return e.getOSName(!0)===`android`},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:[/smart-?tv|smarttv/i],describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:[/netcast/i],describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:function(e){return e.getOSName(!0)===`macos`},describe:function(){return{type:a.PLATFORMS_MAP.desktop,vendor:`Apple`}}},{test:function(e){return e.getOSName(!0)===`windows`},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(e){return e.getOSName(!0)===`linux`},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(e){return e.getOSName(!0)===`playstation 4`},describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:function(e){return e.getOSName(!0)===`roku`},describe:function(){return{type:a.PLATFORMS_MAP.tv}}}],e.exports=t.default},95:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=n(18);t.default=[{test:function(e){return e.getBrowserName(!0)===`microsoft edge`},describe:function(e){if(/\sedg\//i.test(e))return{name:a.ENGINE_MAP.Blink};var t=i.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,e);return{name:a.ENGINE_MAP.EdgeHTML,version:t}}},{test:[/trident/i],describe:function(e){var t={name:a.ENGINE_MAP.Trident},n=i.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){return e.test(/presto/i)},describe:function(e){var t={name:a.ENGINE_MAP.Presto},n=i.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){var t=e.test(/gecko/i),n=e.test(/like gecko/i);return t&&!n},describe:function(e){var t={name:a.ENGINE_MAP.Gecko},n=i.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:a.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(e){var t={name:a.ENGINE_MAP.WebKit},n=i.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}}],e.exports=t.default}})}))}))(),1).default.getParser(globalThis.navigator.userAgent).getResult(),Da=`api.browser.yandex.ru`,Oa=`googlevideo.com`,ka=/^([\w-]+):\s*(.+)$/,Aa=/^[a-zA-Z][a-zA-Z\d+.-]*:/,ja=typeof GM_info>`u`?void 0:GM_info?.scriptHandler;function Ma(){let e=typeof GM_xmlhttpRequest>`u`?globalThis.GM_xmlhttpRequest:GM_xmlhttpRequest;return typeof e==`function`?e:void 0}function Na(){let e=typeof GM>`u`?globalThis.GM:GM,t=e?.xmlHttpRequest??e?.xmlhttpRequest;return typeof t==`function`?t.bind(e):void 0}function Pa(){return!!(Ma()||Na())}var Fa=!(typeof IS_EXTENSION<`u`&&IS_EXTENSION)&&(Ea.browser?.name===`Safari`||![`Tampermonkey`,`Violentmonkey`].includes(ja)),Ia=typeof GM<`u`||globalThis.GM!==void 0,La=Pa();function Ra(e){let t=e.trim();try{return new URL(t).hostname.toLowerCase()}catch{if(!Aa.test(t))try{return new URL(`https://${t}`).hostname.toLowerCase()}catch{}return}}function za(e,t){return e===t||e.endsWith(`.${t}`)}function Ba(e,t,n=!1){if(n)return!0;if(!e){let e=t.toLowerCase();return e.includes(Da)||e.includes(Oa)}return za(e,Da)||za(e,Oa)}function Va(e){return typeof e==`string`?e:e instanceof URL?e.href:e.url}function Ha(e,t){return t?t.toUpperCase():e instanceof Request?(e.method||`GET`).toUpperCase():`GET`}function Ua(e){return typeof e!=`string`||e.length===0?{}:e.split(/\r?\n/).reduce((e,t)=>{let n=ka.exec(t);if(!n)return e;let[,r,i]=n;return e[r]=i,e},{})}function Wa(e){let t=e;return typeof t?.error==`string`&&t.error.trim().length>0?t.error:typeof t?.statusText==`string`&&t.statusText.trim().length>0&&t.statusText!==`""`&&t.statusText!==`''`?t.statusText:ba(e)||`Unknown GM XHR error`}function Ga(e,t){let n=e.status,r=typeof e.statusText==`string`?e.statusText:``,i=e.response instanceof Blob?e.response:null,a=Ua(e.responseHeaders),o=new Response(i,{status:n,statusText:r,headers:a});return Object.defineProperty(o,`url`,{value:e.finalUrl??t}),o}async function Ka(e,t,n,r,i,a){return new Promise((o,s)=>{let c=!1,l,u=()=>{l&&r.signal?.removeEventListener(`abort`,l)},d=e=>{c||(c=!0,u(),s(e))},f=e({method:i,url:t,responseType:`blob`,data:r.body,timeout:n,headers:a,onload:e=>{if(!c){c=!0,u();try{let n=Ga(e,t);L.log(`[GM_fetch] GM_xmlhttpRequest completed`,{url:n.url,method:i,status:n.status,statusText:n.statusText}),o(n)}catch(n){L.warn(`[GM_fetch] GM_xmlhttpRequest response build failed`,{url:t,method:i,error:ba(n),rawStatus:e.status,rawStatusText:e.statusText}),s(n instanceof Error?n:Error(ba(n)))}}},ontimeout:()=>{L.warn(`[GM_fetch] GM_xmlhttpRequest timed out`,{url:t,method:i,timeout:n}),d(Error(`Timeout`))},onerror:e=>{let n=Wa(e);L.warn(`[GM_fetch] GM_xmlhttpRequest failed`,{url:t,method:i,error:n}),d(Error(n))},onabort:()=>{L.warn(`[GM_fetch] GM_xmlhttpRequest aborted`,{url:t,method:i}),d(Sa())}});if(l=()=>{try{f?.abort?.()}catch{}d(Sa())},r.signal&&(r.signal.addEventListener(`abort`,l,{once:!0}),r.signal.aborted)){l();return}})}async function qa(e,t,n,r,i,a){let o=e({method:i,url:t,responseType:`blob`,data:r.body,timeout:n,headers:a}),s;try{let e=new Promise((e,t)=>{r.signal&&(s=()=>{try{o.abort?.()}catch{}t(Sa())},r.signal.addEventListener(`abort`,s,{once:!0}),r.signal.aborted&&s())}),n=Ga(await Promise.race([o,e]),t);return L.log(`[GM_fetch] GM.xmlHttpRequest completed`,{url:n.url,method:i,status:n.status,statusText:n.statusText}),n}finally{s&&r.signal?.removeEventListener(`abort`,s)}}async function Ja(e,t,n){let r=Qi(n.headers),i=(n.method||`GET`).toUpperCase();L.log(`[GM_fetch] GM_xmlhttpRequest start`,{url:e,method:i,timeout:t,headerCount:Object.keys(r).length});let a=Ma();if(a){L.log(`[GM_fetch] attempting callback-style GM_xmlhttpRequest`);try{return await Ka(a,e,t,n,i,r)}catch(t){if(xa(t))throw t;L.warn(`[GM_fetch] callback-style GM_xmlhttpRequest failed`,{url:e,method:i,error:Wa(t)})}}let o=Na();if(o){L.log(`[GM_fetch] attempting promise-style GM.xmlHttpRequest`);try{return await qa(o,e,t,n,i,r)}catch(t){if(xa(t))throw t;L.warn(`[GM_fetch] promise-style GM.xmlHttpRequest failed`,{url:e,method:i,error:Wa(t)})}}throw L.warn(`[GM_fetch] none of the GM approaches worked`),Error(`All GM approaches failed`)}async function z(e,t={}){let{timeout:n=15e3,forceGmXhr:r=!1,responseCache:i,...a}=t,o=Va(e),s=Ra(o),c=Ha(e,a.method),l=Ba(s,o,r);L.log(`[GM_fetch] request`,{url:o,method:c,host:s??`unknown`,timeout:n,transport:l?`GM_xmlhttpRequest`:`fetch`,forced:r,responseCache:i?{ttlMs:i.ttlMs,key:i.key??null,useMemory:i.useMemory??!0,useCacheApi:i.useCacheApi??!0,dedupe:i.dedupe??!0}:null});let u=async()=>{if(l){L.log(`[GM_fetch] using GM_xmlhttpRequest transport`,{url:o,method:c,host:s??`unknown`,reason:r?`forced`:`host-policy`});try{return await Ja(o,n,a)}catch(t){if(xa(t)||r||Ba(s,o))throw t;L.warn(`[GM_fetch] all GM approaches failed, falling back to native fetch`,{url:o,method:c,host:s??`unknown`,error:ba(t)||`Unknown error`});let{signal:i,cleanup:l}=Ta(n,a.signal);try{return await fetch(e,{...a,signal:i})}finally{l()}}}let{signal:t,cleanup:i}=Ta(n,a.signal);try{return await fetch(e,{...a,signal:t})}catch(e){if(t.aborted||xa(e))throw e;return L.warn(`[GM_fetch] fetch failed, retrying via GM_xmlhttpRequest`,{url:o,method:c,host:s??`unknown`,error:ba(e)||`Unknown error`}),await Ja(o,n,a)}finally{i()}};return i?await ma({url:o,method:c,body:a.body},i,u):await u()}var Ya=Object.entries({numToBool:[[`autoTranslate`],[`dontTranslateYourLang`,`enabledDontTranslateLanguages`],[`autoSetVolumeYandexStyle`,`enabledAutoVolume`],[`showVideoSlider`],[`syncVolume`],[`downloadWithName`],[`sendNotifyOnComplete`],[`highlightWords`],[`onlyBypassMediaCSP`],[`newAudioPlayer`],[`showPiPButton`],[`translateAPIErrors`],[`audioBooster`],[`useNewModel`,`useLivelyVoice`]],number:[[`autoVolume`]],array:[[`dontTranslateLanguage`,`dontTranslateLanguages`]],string:[[`hotkeyButton`,`translationHotkey`],[`locale-lang-override`,`localeLangOverride`],[`locale-lang`,`localeLang`]]}).flatMap(([e,t])=>t.map(([t,n])=>({category:e,oldKey:t,newKey:n??t,shouldDeleteOldKey:!!n}))),Xa=new Map(Ya.map(e=>[e.oldKey,e])),Za=Array.from(new Set(Ya.map(e=>e.oldKey)));function Qa(e){let t={};for(let n of e)t[n]=void 0;return t}function $a(e,t){switch(e){case`numToBool`:case`number`:return typeof t==`number`;case`array`:return Array.isArray(t);case`string`:return typeof t==`string`||t===null;default:return!1}}function eo(e,t){switch(e){case`string`:case`array`:case`number`:return t;default:return!!t}}function to(e,t){let n=eo(e.category,t);return e.oldKey===`autoVolume`&&typeof t==`number`&&t<1&&(n=Math.round(t*100)),n}function no(e,t){return Array.isArray(e)&&Array.isArray(t)?e.length===t.length&&e.every((e,n)=>Object.is(e,t[n])):Object.is(e,t)}function ro(e){if(e!==null)try{return JSON.parse(e)}catch{return}}async function io(e){if(e.compatVersion===`2025-05-09`)return e;let t=new Set([...Object.keys(e),...Za]),n=await B.getValues(Qa(t)),r={...e},i=[],a=[];for(let[e,t]of Object.entries(n)){if(t===void 0)continue;let o=Xa.get(e);if(!o||!$a(o.category,t))continue;let s=to(o,t);r[o.newKey]=s;let c=n[o.newKey];(o.shouldDeleteOldKey||!no(c,s))&&i.push(B.set(o.newKey,s)),o.shouldDeleteOldKey&&a.push(B.delete(o.oldKey))}return await Promise.all([...i,...a]),{...r,compatVersion:Ei}}var ao=class{support=null;localStorageListeners=new Map;shouldUseSyntheticListeners(e){return!e.promiseAddValueChangeListener&&!e.legacyAddValueChangeListener}getGMRuntime(){return typeof GM<`u`?GM:globalThis.GM}resolveSupport(){if(this.support)return this.support;let e=this.getGMRuntime(),t={legacyGet:typeof GM_getValue==`function`,legacySet:typeof GM_setValue==`function`,legacyDelete:typeof GM_deleteValue==`function`,legacyList:typeof GM_listValues==`function`,legacyAddValueChangeListener:typeof globalThis.GM_addValueChangeListener==`function`,legacyRemoveValueChangeListener:typeof globalThis.GM_removeValueChangeListener==`function`,promiseGet:Ia&&typeof e?.getValue==`function`,promiseGetValues:Ia&&typeof e?.getValues==`function`,promiseSet:Ia&&typeof e?.setValue==`function`,promiseDelete:Ia&&typeof e?.deleteValue==`function`,promiseList:Ia&&typeof e?.listValues==`function`,promiseAddValueChangeListener:Ia&&typeof e?.addValueChangeListener==`function`,promiseRemoveValueChangeListener:Ia&&typeof e?.removeValueChangeListener==`function`};return this.support=t,L.log(`[VOT Storage] GM Promises: ${t.promiseGet} | GM legacy: ${t.legacyGet}`),t}get isSupportOnlyLS(){let e=this.resolveSupport();return!e.legacyGet&&!e.legacySet&&!e.legacyDelete&&!e.legacyList&&!e.promiseGet&&!e.promiseGetValues&&!e.promiseSet&&!e.promiseDelete&&!e.promiseList}syncGetByName(e,t,n){if(n.legacyGet)return GM_getValue(e,t);let r=globalThis.localStorage.getItem(e);if(r===null)return t;try{return JSON.parse(r)}catch{return t}}async getRaw(e,t){let n=this.resolveSupport();return n.promiseGet&&GM.getValue?await GM.getValue(e,t):this.syncGetByName(e,t,n)}async get(e,t){return this.getRaw(e,t)}async getValues(e){let t=this.resolveSupport();if(t.promiseGetValues&&GM.getValues)return await GM.getValues(e);let n=Object.entries(e);if(t.promiseGet&&GM.getValue){let e=await Promise.all(n.map(async([e,t])=>[e,await GM.getValue(e,t)]));return Object.fromEntries(e)}return Object.fromEntries(n.map(([e,n])=>[e,this.syncGetByName(e,n,t)]))}syncSetByName(e,t,n){return n.legacySet?GM_setValue(e,t):globalThis.localStorage.setItem(e,JSON.stringify(t))}async setRaw(e,t){let n=this.resolveSupport(),r=e,i=this.shouldUseSyntheticListeners(n),a=i?await this.getRaw(e):void 0;if(n.promiseSet&&GM.setValue){await GM.setValue(e,t),i&&this.notifyLocalStorageListeners(r,a,t,!1);return}let o=this.syncSetByName(e,t,n);return this.notifyLocalStorageListeners(r,a,t,!1),o}async set(e,t){return this.setRaw(e,t)}syncDeleteByName(e,t){return t.legacyDelete?GM_deleteValue(e):globalThis.localStorage.removeItem(e)}async deleteRaw(e){let t=this.resolveSupport(),n=e,r=this.shouldUseSyntheticListeners(t),i=r?await this.getRaw(e):void 0;if(t.promiseDelete&&GM.deleteValue){await GM.deleteValue(e),r&&this.notifyLocalStorageListeners(n,i,void 0,!1);return}let a=this.syncDeleteByName(e,t);return this.notifyLocalStorageListeners(n,i,void 0,!1),a}async delete(e){return this.deleteRaw(e)}addValueChangeListener(e,t){let n=this.resolveSupport(),r=this.getGMRuntime();if(n.promiseAddValueChangeListener){let i=r?.addValueChangeListener,a=n.promiseRemoveValueChangeListener?r?.removeValueChangeListener:void 0;if(typeof i==`function`){let n=i(e,this.createTypedListener(t));return()=>{typeof a==`function`&&a(n)}}}if(n.legacyAddValueChangeListener){let r=globalThis.GM_addValueChangeListener,i=n.legacyRemoveValueChangeListener?globalThis.GM_removeValueChangeListener:void 0;if(typeof r==`function`){let n=r(e,this.createTypedListener(t));return()=>{typeof i==`function`&&i(n)}}}let i=this.getLocalStorageListeners(e),a=t;i.add(a);let o=t=>{t.storageArea!==globalThis.localStorage||t.key!==e||a(e,ro(t.oldValue),ro(t.newValue),!0)};return globalThis.addEventListener(`storage`,o),()=>{i.delete(a),i.size===0&&this.localStorageListeners.delete(e),globalThis.removeEventListener(`storage`,o)}}createTypedListener(e){return(t,n,r,i)=>{e(t,n,r,i)}}getLocalStorageListeners(e){let t=this.localStorageListeners.get(e);if(t)return t;let n=new Set;return this.localStorageListeners.set(e,n),n}notifyLocalStorageListeners(e,t,n,r){let i=this.localStorageListeners.get(e);if(!(!i||i.size===0))for(let a of i)a(e,t,n,r)}syncList(e){return e.legacyList?GM_listValues():Oi}async list(){let e=this.resolveSupport();return e.promiseList&&GM.listValues?await GM.listValues():this.syncList(e)}},oo=`__VOT_STORAGE_SINGLETON__`,B=(()=>{let e=globalThis,t=e[oo];if(t instanceof ao)return t;let n=new ao;return e[oo]=n,n})(),so=`vot-auth`,co=`account-updated`;function lo(){return{source:so,type:co}}function uo(e){if(!e||typeof e!=`object`)return!1;let t=e;return t.source===`vot-auth`&&t.type===`account-updated`}function fo(e=globalThis.opener){!e||typeof e.postMessage!=`function`||e.postMessage(lo(),`*`)}function po(){let e=globalThis._userData;if(!e||typeof e!=`object`)return null;let t=e;return typeof t.avatar_id!=`string`||typeof t.username!=`string`||t.avatar_id.length===0||t.username.length===0?null:{avatar_id:t.avatar_id,username:t.username}}async function mo(){let{access_token:e,expires_in:t}=Object.fromEntries(new URLSearchParams(globalThis.location.hash.slice(1)));if(!e||!t)throw Error(`[VOT] Invalid token response`);let n=Number.parseInt(t,10);if(Number.isNaN(n))throw TypeError(`[VOT] Invalid expires_in value`);await B.set(`account`,{token:e,expires:Date.now()+n*1e3,username:void 0,avatarId:void 0}),fo()}async function ho(){let e=po();if(!e)throw Error(`[VOT] Invalid user data`);let{avatar_id:t,username:n}=e,r=await B.get(`account`);if(!r)throw Error(`[VOT] No account data found`);await B.set(`account`,{...r,username:n,avatarId:t}),fo()}async function go(){if(globalThis.location.pathname===`/auth/callback`)return mo();if(globalThis.location.pathname===`/my/profile`)return ho()}var _o={recommended:`recommended`,translateVideo:`Translate video`,disableTranslate:`Turn off`,translationSettings:`Translation settings`,subtitlesSettings:`Subtitles settings`,subtitlesSmartLayout:`Smart subtitle layout`,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`,requestTranslationFailed:`Failed to request video translation`,audioNotReceived:`Audio link not received`,VOTFailedDownloadAudio:`Failed to download audio`,audioFormatNotSupported:`The audio format is not supported`,VOTAutoTranslate:`Translate on open`,VOTAutoSubtitles:`Subtitles on open`,VOTDontTranslateYourLang:`Don't 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`,VOTDisableFromYourLang:`You have disabled the translation of the video in your language`,VOTVideoIsTooLong:`Video is too long`,VOTNoVideoIDFound:`No video ID found`,VOTSubtitles:`Subtitles`,VOTSubtitlesDisabled:`Disabled`,VOTDefaultSubtitlesLanguage:`Default subtitle language`,VOTOriginalVideoLanguage:`Original video language`,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`},streamNoConnectionToServer:`There is no connection to the server`,searchField:`Search...`,VOTTranslateAPIErrors:`Translate errors from the API`,VOTDetectService:`Language detection service`,VOTProxyWorkerHost:`Enter the proxy worker address`,VOTM3u8ProxyHost:`Enter the address of the m3u8 proxy worker`,proxySettings:`Proxy Settings`,translationTakeApproximatelyMinute2:`The translation will take approximately {0} minutes`,VOTAudioBooster:`Extended translation volume increase`,VOTSubtitlesDesign:`Subtitles design`,VOTSubtitlesFont:`Subtitle font`,VOTSubtitlesFontSize:`Font size of subtitles`,VOTSubtitlesOpacity:`Transparency of the subtitle background`,VOTSubtitlesDownloadFormat:`The format for downloading subtitles`,VOTDownloadWithName:`Download files with the video name`,VOTUpdateLocaleFiles:`Update localization files`,VOTLocaleHash:`Locale hash`,VOTUpdatedAt:`Updated at`,VOTNeedWebAudioAPI:`To enable this, you must have a Web Audio API`,VOTMediaCSPEnabledOnSite:`Media CSP is enabled on this site`,VOTOnlyBypassMediaCSP:`Use it only for bypassing Media CSP`,VOTNewAudioPlayer:`Use the new audio player`,VOTUseNewModel:`Use an experimental variation of Yandex voices for some videos`,TranslationDelayed:`The translation is slightly delayed`,VOTTranslationCompletedNotify:`The translation on the {0} has been completed!`,VOTSendNotifyOnComplete:`Send a notification that the video has been translated`,VOTBugReport:`Report a bug`,VOTTranslateProxyDisabled:`Disabled`,VOTTranslateProxyEnabled:`Enabled`,VOTTranslateProxyEverything:`Proxy everything`,VOTTranslateProxyStatus:`Proxying mode`,VOTTranslatedBy:`Translated by {0}`,VOTStreamNotAvailable:`Translate stream isn't available`,VOTTranslationTextService:`Text translation service`,VOTNotAffectToVoice:`Doesn't affect the translation of text in voice over`,DontTranslateSelectedLanguages:`Don't translate from selected languages`,showVideoVolumeSlider:`Display the video volume slider`,hotkeysSettings:`Hotkeys settings`,None:`None`,VOTUseLivelyVoice:`Use lively voices. Speakers sound like native Russians.`,miscSettings:`Misc settings`,services:{yandexbrowser:`Yandex Browser`,msedge:`Microsoft Edge`,"rust-server":`Rust Server`},aboutExtension:`About extension`,appearance:`Appearance`,buttonPosition:`Button position in the player`,position:{left:`Left`,right:`Right`,top:`Top`,default:`Default`},secs:`secs`,autoHideButtonDelay:`Delay before hiding the translate button`,notFound:`not found`,minButtonPositionContainer:`The button position only changes in players larger than 600 pixels.`,VOTTranslateProxyStatusDefault:`Completely disabling proxying in your country may break the extension`,PressTheKeyCombination:`Press the key combination...`,VOTUseAudioDownload:`Use audio download`,VOTUseAudioDownloadWarning:`Disabling audio downloads may affect the functionality of the extension`,VOTAccountRequired:`You need to log in to use this feature`,VOTMyAccount:`My account`,VOTLogin:`Login`,VOTLogout:`Logout`,VOTRefresh:`Refresh`,VOTYandexToken:`Enter the Yandex OAuth Token`,VOTYandexTokenInfo:`You can manually set the account token in this field. Please note that we don't check its validity before sending a translate request`,VOTLoginViaToken:`Login via token`,smartDucking:`Adaptive volume`},vo=[`localePhrases`,`localeLang`,`localeHash`,`localeVersion`,`localeUpdatedAt`,`localeLangOverride`],yo=$i(_o),bo=`master`,xo=(()=>{let e=Array.isArray(`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`.split(`.`))?`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`.split(`.`):[`en`];return e.includes(`auto`)?e:[`auto`,...e]})();function So(e,t){return e||t||`unknown`}function Co(){return So(`1.11.5`,typeof GM_info<`u`?String(GM_info?.script?.version||``):``)}var V=new class{lang;locale;defaultLocale=yo;localesUrl=`${bi}/${bo}/src/localization/locales`;hashesUrl=`${bi}/${bo}/src/localization/hashes.json`;warnedMissingKeys=new Set;_langOverride=`auto`;constructor(){this.lang=this.getLang(),this.locale={}}async init(){let[e,t]=await Promise.all([B.get(`localeLangOverride`,`auto`),B.get(`localePhrases`,``)]);return this._langOverride=e,this.lang=this.getLang(),this.setLocaleFromJsonString(t),this}get langOverride(){return this._langOverride}getLang(){return this.langOverride===`auto`?Mi:this.langOverride}getAvailableLangs(){return[...xo]}async reset(){return await Promise.all(vo.map(e=>B.delete(e))),this}buildUrl(e,t=``,n=!1){return`${e}${t}${n?`?timestamp=${Zi()}`:``}`}async changeLang(e){return this.langOverride===e?!1:(await B.set(`localeLangOverride`,e),this._langOverride=e,this.lang=this.getLang(),await this.update(!0),!0)}async checkUpdates(e=!1){L.log(`Check locale updates...`);try{let t=Co();if(!e){let e=await B.get(`localeVersion`,``);if(t!==`unknown`&&e===t)return!1}let n=await z(this.buildUrl(this.hashesUrl,``,e));if(!n.ok)throw n.status;let r=await n.json();if(!r||typeof r!=`object`)throw Error(`Invalid locale hashes payload`);let i=r[this.lang];return typeof i!=`string`||!i||await B.get(`localeHash`,``)===i?!1:i}catch(e){return console.error(`[VOT] [localizationProvider] Failed to get locales hash:`,e),null}}async update(e=!1){let t=Co(),n=await B.get(`localeVersion`,``),r=await this.checkUpdates(e);if(r===null)return this;if(!r)return n!==t&&await B.set(`localeVersion`,t),this;let i=Zi();L.log(`Updating locale...`);try{let n=await z(this.buildUrl(this.localesUrl,`/${this.lang}.json`,e));if(!n.ok)throw n.status;let a=await n.text();this.setLocaleFromJsonString(a),await Promise.all([B.set(`localePhrases`,a),B.set(`localeHash`,r),B.set(`localeLang`,this.lang),B.set(`localeVersion`,t),B.set(`localeUpdatedAt`,i)])}catch(e){console.error(`[VOT] [localizationProvider] Failed to get locale:`,e),this.setLocaleFromJsonString(await B.get(`localePhrases`,``))}return this}setLocaleFromJsonString(e){let t=e.trim();if(!t)return this.locale={},this.warnedMissingKeys.clear(),this;try{let e=JSON.parse(t);if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`Locale payload should be a JSON object`);this.locale=$i(e)}catch(e){console.error(`[VOT] [localizationProvider]`,e),this.locale={}}return this.warnedMissingKeys.clear(),this}getFromLocale(e,t,n=`locale`){return e[t]??this.warnMissingKey(e,t,n)}warnMissingKey(e,t,n){let r=`${n}:${t}`;this.warnedMissingKeys.has(r)||(this.warnedMissingKeys.add(r),console.warn(`[VOT] [localizationProvider] locale`,e,`doesn't contain key`,t))}getDefault(e){return this.getFromLocale(this.defaultLocale,e,`default`)??e}get(e){return this.getFromLocale(this.locale,e)??this.getDefault(e)}getLangLabel(e){let t=`langs.${e}`;if(t in this.defaultLocale){let e=this.get(t);if(e)return e}return e.toUpperCase()}},wo=null;function To(){return wo??=V.init(),wo}var Eo=()=>globalThis.self!==globalThis.top,Do=!1,Oo=null;async function ko(e,t){if(!Do){if(Oo!==null){await Oo;return}Oo=(async()=>{if(t(`Activating runtime`,{reason:e}),globalThis.location.origin===`https://rust-server-531j.onrender.com`){await go(),Do=!0;return}await To(),Eo()||await V.update(),L.log(`Selected menu language: ${V.lang}`),Do=!0})();try{await Oo}finally{Oo=null}}}var Ao=new WeakSet;function jo(e){let{videoObserver:t,videosWrappers:n,ensureRuntimeActivated:r,getServicesCached:i,findContainer:a,createVideoHandler:o}=e;if(Ao.has(t))return;Ao.add(t);let s=new WeakSet,c=new WeakMap,l=new WeakMap,u=new WeakMap,d=e=>{let t=l.get(e);return t&&c.get(t)===e&&c.delete(t),l.delete(e),t??void 0},f=e=>{e&&u.delete(e)},p=async(e,t)=>{let r=n.get(e);if(r)try{await r.release()}catch(e){console.error(`[VOT] Failed to release videoHandler (${t})`,e)}finally{n.delete(e)}},m=e=>{for(let t of i()){let n=a(t,e);if(n)return{site:t,container:n}}return null},h=e=>{let t=String(e.host);return t===`peertube`||t===`directlink`?{...e,url:globalThis.location.origin}:e},g=async e=>{if(!e)return;let t=u.get(e);t&&(u.delete(e),!(!t.isConnected||n.has(t)||s.has(t))&&await _(t))},_=async e=>{if(!(n.has(e)||s.has(e))){s.add(e);try{try{await r(`video-detected`)}catch(e){console.error(`[VOT] Failed to activate runtime`,e);return}let t=m(e);if(!t)return;let{site:i,container:a}=t,s=c.get(a);if(s&&s!==e){if(s.isConnected){u.set(a,e);return}await p(s,`stale container`),d(s)}let _=o(e,a,h(i));n.set(e,_),l.set(e,a),c.set(a,e);try{if(await _.init(),n.get(e)!==_)return;try{await _.setCanPlay()}catch(e){console.error(`[VOT] Failed to get video data`,e)}}catch(t){if(n.get(e)===_){await p(e,`init failed`);let t=d(e);f(t),await g(t)}console.error(`[VOT] Failed to initialize videoHandler`,t)}}finally{s.delete(e)}}};t.onVideoAdded.addListener(_),t.onVideoRemoved.addListener(async e=>{let t=d(e);await p(e,`video removed`),s.delete(e),t&&u.get(t)===e&&f(t),await g(t)})}function Mo(e){return e.isIframe?e.href===`about:blank`||e.href.startsWith(`about:srcdoc`)||e.origin===`null`:!1}function No(e){return Mo(e)?`skip`:!e.isIframe&&e.origin===e.authOrigin?`auth-eager`:`lazy`}function Po(e){return e?typeof ShadowRoot<`u`&&e instanceof ShadowRoot?e.host:e.parentNode??null:null}function Fo(e=document){let t=e.activeElement;for(;t instanceof HTMLElement&&t.shadowRoot;){let e=t.shadowRoot.activeElement;if(!e)break;t=e}return t}function Io(e,t){let n=t;for(;n;){if(n===e)return!0;n=Po(n)}return!1}function Lo(e,t){return!e||!t?null:Bo(e,t,e instanceof Document?null:e)}function Ro(e,t,n){if(!n)return e.querySelector(t);let r=e.querySelectorAll(t);for(let e of r)if(Io(e,n))return e;return null}function zo(e){let t=e.getRootNode();if(t instanceof ShadowRoot)return t.host;if(t instanceof Document)return t;if(t!==e){let n=Po(t);if(n&&n!==e&&n instanceof Element)return n}return null}function Bo(e,t,n){return e?e instanceof Document?Ro(e,t,n):e.closest(t)||Bo(zo(e),t,n):null}function Vo(e,t){if(!t)return null;let n=Lo(e,t);return n instanceof HTMLElement&&n.isConnected&&Io(n,e)?n:null}function Ho(e,t){return t.host===`youtube`&&t.additionalData!==`mobile`?e.parentElement??e:e}function Uo(e){let t=Ho(e.container,e.site),n=e.fullscreenRoot??t;return{base:t,root:n,portalContainer:t,subtitlesMountContainer:n}}var H=class{listeners=new Set;get size(){return this.listeners.size}addListener(e){return this.listeners.add(e),this}removeListener(e){return this.listeners.delete(e),this}dispatch(...e){for(let t of this.listeners)try{t(...e)}catch(e){console.error(`[VOT]`,e)}}async dispatchAsync(...e){let t=[];for(let n of this.listeners)try{let r=n(...e);r&&typeof r.then==`function`&&t.push(Promise.resolve(r))}catch(e){console.error(`[VOT]`,e)}if(!t.length)return;let n=await Promise.allSettled(t);for(let e of n)e.status===`rejected`&&console.error(`[VOT]`,e.reason)}clear(){this.listeners.clear()}};function Wo(e,t,n,r){return JSON.stringify({downloadType:e,itag:t,minChunkSize:r,fileSize:n})}function Go(e){return e?.toLowerCase()??``}function Ko(e){let t=Go(e);return t.includes(`audio/`)&&!t.includes(`video/`)}function qo(e){let t=Go(e);return t.includes(`audio/mp4`)&&t.includes(`mp4a.`)}function Jo(e){let t=Go(e);return t.includes(`audio/webm`)&&t.includes(`opus`)}function Yo(e){if(!e)return`mp4a.40.2`;let t=/codecs="([^"]+)"/i.exec(e);if(!t?.[1])return`mp4a.40.2`;let n=t[1].split(`,`).map(e=>e.trim());return n.find(e=>e.toLowerCase().startsWith(`mp4a.`))??n[0]??`mp4a.40.2`}function Xo(e,t){let n=null,r=t===`max`?-1/0:1/0;for(let i of e){let e=i.bitrate??0;(t===`max`&&e>r||t===`min`&&eKo(e.mimeType));if(!n.length)throw Error(`No adaptive audio formats were found in player response`);let r=t===`bestefficiency`?`min`:`max`,i=t===`bestefficiency`?[n.filter(e=>Jo(e.mimeType)),n]:[n.filter(e=>qo(e.mimeType)),n.filter(e=>Jo(e.mimeType)),n];for(let e of i){if(!e.length)continue;let t=Xo(e,r);if(t)return t}throw Error(`No adaptive audio formats were found in player response`)}var Qo=/^[a-zA-Z0-9_-]{11}$/,$o=`https://www.youtube.com`,es=`1.60.19`,ts=[`ANDROID_VR`],ns={accept:`*/*`,origin:$o,referer:`${$o}/`},rs=256*1024;function is(e){return e?{signal:e}:{}}function as(e){if(e!==void 0&&e!==`ANDROID_VR`)throw Error(`Unsupported Innertube client: ${e}`);return{clientName:`ANDROID_VR`,clientVersion:es,hl:`en`,gl:`US`,androidSdkVersion:31,osName:`Android`,osVersion:`12`,platform:`MOBILE`}}function os(e){let t=e.trim();if(Qo.test(t))return t;let n;try{n=new URL(t)}catch{throw Error(`Cannot extract YouTube video id from: ${e}`)}let r=n.hostname.toLowerCase();if(r===`youtu.be`||r.endsWith(`.youtu.be`))return ss(n.pathname.split(`/`).find(Boolean),e);let i=n.searchParams.get(`v`);if(i&&Qo.test(i))return i;let a=cs(n.pathname.split(`/`).filter(Boolean));if(a)return a;throw Error(`Cannot extract YouTube video id from: ${e}`)}function ss(e,t){if(e&&Qo.test(e))return e;throw Error(`Cannot extract YouTube video id from: ${t}`)}function cs(e){for(let t of[`shorts`,`embed`]){let n=e.indexOf(t);if(n===-1)continue;let r=e[n+1];if(r&&Qo.test(r))return r}return null}function ls(e){return e.replaceAll(`\\u0026`,`&`).replaceAll(`\\/`,`/`)}function us(e){let t=e.videoId??e.videoUrl;if(!t)throw Error(`Either videoId or videoUrl is required`);return os(t)}function ds(e,t){for(let n of t){let t=n.exec(e)?.[1];if(t)return t}}async function fs(e){return new Uint8Array(await e.arrayBuffer())}function ps(e=16){let t=`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_`,n=``;if(typeof crypto<`u`&&typeof crypto.getRandomValues==`function`){let r=new Uint8Array(e);crypto.getRandomValues(r);for(let e of r)n+=t[e%64]??`a`;return n}for(let r=0;ri)return!1;let a=gs(e.headers.get(`content-range`));return a?a.start===n&&a.end===n+t.byteLength-1:e.status===206?t.byteLength===i:e.status===200?n===0&&t.byteLength===i:!1}function ys(e,t){let n=e.headers.get(`content-range`)??`none`,r=e.headers.get(`content-length`)??`none`;return`status=${e.status}; bytes=${t.byteLength}; content-range=${n}; content-length=${r}`}function bs(e){let t=e?.toLowerCase()??``;return t.includes(`audio/webm`)?`audio/webm`:t.includes(`audio/mp4`)?`audio/mp4`:`audio/aac`}function xs(e){let t=e?[e,...ts]:[...ts],n=new Set;return t.filter(e=>n.has(e)?!1:(n.add(e),!0))}var Ss=class{fetchFn;constructor(e={}){this.fetchFn=e.fetchImplementation??fetch}async fetchRangeChunk(e,t,n,r){let i=`bytes=${t}-${n}`,a=await this.fetchFn(e,{headers:{...ns,range:i},...is(r)});if(!a.ok)throw Error(`Failed to download stream chunk: ${a.status}`);let o=await fs(a);if(!vs(a,o,t,n))throw Error(`Received unexpected stream chunk payload: ${ys(a,o)}`);return o}async downloadStreamByRanges(e,t,n){let r=await this.resolveStreamContentLength(e,t,n,!0),i=new Uint8Array(r),a=0;for(let t=0;ti.byteLength)throw Error(`Downloaded stream chunk exceeds probed stream content length`);i.set(s,a),a+=s.byteLength}return a===i.byteLength?i:i.slice(0,a)}async downloadAudioToChunkStream(e,t){if(t.chunkSize<=0)throw RangeError(`Audio downloader. ytAudio. chunkSize must be > 0`);return this.withResolvedPlayableAudioFormat(e,e.audioQuality??`best`,`Chunk mode requires an adaptive audio stream format`,`Unable to resolve streamable format for chunk mode`,async({resolved:e,signal:n})=>{let r=await this.resolveStreamContentLength(e.streamUrl,e.chosenFormat.contentLength,n,!0),i=Math.max(1,Math.ceil(r/t.chunkSize));return{videoId:e.videoId,fileSize:r,itag:e.chosenFormat.itag??0,mediaPartsLength:i,getMediaBuffers:async function*(){for(let a=0;a{let r=await this.downloadStreamByRanges(e.streamUrl,e.chosenFormat.contentLength,n),i=this.getExtractionHints(e.chosenFormat);return await t.write(r),{videoId:e.videoId,bytesWritten:r.byteLength,mimeType:bs(e.chosenFormat.mimeType),codec:i.codec,sampleRate:i.sampleRate,channels:i.channels}})}async withResolvedPlayableAudioFormat(e,t,n,r,i){let a=us(e),{signal:o}=e,s=await this.fetchWatchContext(a,o),c=xs(e.client),l=[];for(let e of c)try{let r=await this.resolvePlayableFormatForClient({videoId:a,watchContext:s,client:e,quality:t,signal:o});if(!Ko(r.chosenFormat.mimeType))throw Error(n);return await i({resolved:r,signal:o})}catch(t){let n=t instanceof Error?t.message:String(t);l.push(`${e}: ${n}`)}throw Error(`${r}. Attempts: ${l.join(` | `)}`)}async resolvePlayableFormatForClient({videoId:e,watchContext:t,client:n,quality:r,signal:i}){let a=((await this.fetchPlayerResponse(e,t,n,i)).streamingData?.adaptiveFormats??[]).filter(e=>!!e.url);if(!a.length)throw Error(`Player response did not contain direct adaptive audio stream URLs`);let o=Zo(a,r);return{videoId:e,chosenFormat:o,streamUrl:this.resolveFormatUrl(o)}}async resolveStreamContentLength(e,t,n,r=!1){let i=ms(t);if(i!==null&&!r)return i;let a;try{a=await this.fetchFn(e,{headers:{...ns,range:`bytes=0-0`},...is(n)})}catch(e){if(i!==null)return i;let t=e instanceof Error?e.message:String(e);throw Error(`Failed to probe stream content length: ${t}`)}if(!a.ok){if(i!==null)return i;throw Error(`Failed to probe stream content length: ${a.status}`)}let o=hs(a.headers.get(`content-range`)),s=ms(a.headers.get(`x-goog-stored-content-length`)),c=ms(a.headers.get(`content-length`));if(typeof a.body?.cancel==`function`)try{await a.body.cancel()}catch{}return o??s??i??c??(()=>{throw Error(`Failed to resolve stream content length`)})()}getExtractionHints(e){let t=Yo(e.mimeType),n=Number.parseInt(e.audioSampleRate??``,10);return{codec:t,sampleRate:Number.isFinite(n)&&n>0?n:44100,channels:e.audioChannels&&e.audioChannels>0?e.audioChannels:2}}resolveFormatUrl(e){if(!e.url)throw Error(`Selected format does not contain a direct stream URL`);let t=new URL(e.url);return t.searchParams.set(`cpn`,ps()),t.toString()}async fetchWatchContext(e,t){let n=`${$o}/watch?v=${encodeURIComponent(e)}&hl=en`,r=await this.fetchFn(n,{headers:ns,...is(t)});if(!r.ok)throw Error(`Failed to load watch page: ${r.status}`);let i=await r.text(),a=ds(i,[/"INNERTUBE_API_KEY":"([^"]+)"/,/["']INNERTUBE_API_KEY["']\s*:\s*"([^"]+)"/]),o=ds(i,[/"INNERTUBE_CLIENT_VERSION":"([^"]+)"/,/["']INNERTUBE_CLIENT_VERSION["']\s*:\s*"([^"]+)"/]),s=ds(i,[/"STS":(\d+)/,/["']STS["']\s*:\s*(\d+)/]),c=ds(i,[/"VISITOR_DATA":"([^"]+)"/,/"visitorData":"([^"]+)"/,/["'](?:VISITOR_DATA|visitorData)["']\s*:\s*"([^"]+)"/]);if(!a||!o)throw Error(`Failed to extract required player context from watch page`);let l=s?Number.parseInt(s,10):void 0,u={apiKey:a,clientVersion:o};return typeof l==`number`&&Number.isFinite(l)&&(u.signatureTimestamp=l),c&&(u.visitorData=ls(c)),u}async fetchPlayerResponse(e,t,n,r){let i=as(n);t.visitorData&&(i.visitorData=t.visitorData);let a={context:{client:i},videoId:e,contentCheckOk:!0,racyCheckOk:!0};t.signatureTimestamp&&(a.playbackContext={contentPlaybackContext:{signatureTimestamp:t.signatureTimestamp}});let o=`${$o}/youtubei/v1/player?key=${encodeURIComponent(t.apiKey)}`,s=await this.fetchFn(o,{method:`POST`,headers:{...ns,"content-type":`application/json`,...t.visitorData?{"x-goog-visitor-id":t.visitorData}:{}},body:JSON.stringify(a),...is(r)});if(!s.ok)throw Error(`Player API request failed with status ${s.status}`);let c=await s.json(),l=!!c.streamingData?.formats?.length,u=!!c.streamingData?.adaptiveFormats?.length;if(!l&&!u)throw Error(`Player response did not contain streaming formats`);return c}},Cs=`bestefficiency`,ws=3e4;function Ts(e){if(e<=0)throw RangeError(`Audio downloader. ytAudio. chunkSize must be > 0`)}function Es({signal:e,timeoutMs:t}){return async(n,r={})=>await z(n,{...r,signal:r.signal??e,forceGmXhr:!0,timeout:t})}async function Ds({videoId:e,signal:t},n={}){let r=n.chunkSize??f.minChunkSize;Ts(r);let i=Es({signal:t,timeoutMs:n.fetchTimeoutMs??ws}),a=n.createDownloader?.(i)??new Ss({fetchImplementation:i});try{let n=await a.downloadAudioToChunkStream({videoId:e,audioQuality:Cs,signal:t},{chunkSize:r});return{fileId:Wo(Kt.WEB_API_STEAL_SIG_AND_N,n.itag,String(n.fileSize),r),mediaPartsLength:n.mediaPartsLength,getMediaBuffers:n.getMediaBuffers}}catch(e){console.warn(`[VOT] ytAudio streaming mode failed, falling back to buffered mode`,e)}let o=(await a.downloadAudioToUint8Array({videoId:e,audioQuality:Cs,signal:t})).bytes;if(!o||o.byteLength===0)throw Error(`Audio downloader. ytAudio. Empty audio`);let s=Math.max(1,Math.ceil(o.byteLength/r));return{fileId:Wo(Kt.WEB_API_STEAL_SIG_AND_N,0,String(o.byteLength),r),mediaPartsLength:s,async*getMediaBuffers(){for(let e=0;e=Ps&&(n+=1),n>=60)return t(`translationTakeMoreThanHour`);if(n<=1)return t(`translationTakeAboutMinute`);let r=String(n);return n!==11&&n%10==1?t(`translationTakeApproximatelyMinute2`).replace(`{0}`,r):![12,13,14].includes(n)&&[2,3,4].includes(n%10)?t(`translationTakeApproximatelyMinute`).replace(`{0}`,r):t(`translationTakeApproximatelyMinutes`).replace(`{0}`,r)}var U=class extends Error{name=`VOTLocalizedError`;unlocalizedMessage;localizedMessage;constructor(e){super(V.getDefault(e)),this.unlocalizedMessage=e,this.localizedMessage=V.get(e)}};function Is(e){return e??null}async function Ls(e,t){let n=await e.translateVideoImpl(t.videoData,t.requestLang,t.responseLang,Is(t.translationHelp),!t.useAudioDownload,t.signal);return n?.url?{url:n.url,usedLivelyVoice:!!n.usedLivelyVoice}:null}function Rs(e){return{videoId:e.videoId,from:e.requestLang,to:e.responseLang,url:e.downloadTranslationUrl??e.fallbackUrl,useLivelyVoice:e.usedLivelyVoice}}async function zs(e){return!(e.isActionStale(e.actionContext)||(await e.updateTranslation(e.url,e.actionContext),e.isActionStale(e.actionContext)))}async function Bs(e){let t=await Ls(e.requester,{videoData:e.request.videoData,requestLang:e.request.requestLang,responseLang:e.request.responseLang,translationHelp:e.request.translationHelp,useAudioDownload:e.request.useAudioDownload,signal:e.request.signal});return!t||!await zs({url:t.url,actionContext:e.actionContext,isActionStale:e.isActionStale,updateTranslation:e.updateTranslation})||e.isActionStale(e.actionContext)?null:t}function Vs(e){e.setTranslation(e.cacheKey,Rs({videoId:e.videoId,requestLang:e.requestLang,responseLang:e.responseLang,fallbackUrl:e.fallbackUrl,downloadTranslationUrl:e.downloadTranslationUrl,usedLivelyVoice:e.usedLivelyVoice}))}function Hs(e){return e.aborted||!e.translateApiErrorsEnabled||!e.hadAsyncWait?e.hadAsyncWait:(e.notify({videoId:e.videoId,message:e.error}),!1)}function Us(e){if(!e||typeof e!=`object`)return null;let t=e,n=t.data&&typeof t.data==`object`?t.data:void 0;return{name:t.name,message:t.message,data:n}}function Ws(e){let t=Us(e)?.data?.message;return typeof t==`string`&&t.length>0?t:void 0}function Gs(e){let t=Us(e);if(!t||t.name!==`VOTJSError`)return e;let n=typeof t.message==`string`?t.message:``,r=typeof t.data?.message==`string`&&t.data.message.length>0;return n===`Yandex couldn't translate video`&&!r||n===`Failed to request video translation`?new U(`requestTranslationFailed`):n===`Audio link wasn't received`||n===`Audio link wasn't received from VOT response`?new U(`audioNotReceived`):e}function Ks(e){return{status:e.status,translated:e.translated,remainingTime:e.remainingTime,translationId:e.translationId}}var qs=class{videoHandler;audioDownloader;downloading;downloadWaiters=new Set;requestedFailAudio=new Set;constructor(e){this.videoHandler=e,this.audioDownloader=new Ns,this.downloading=!1,this.audioDownloader.addEventListener(`downloadedAudio`,this.onDownloadedAudio).addEventListener(`downloadedPartialAudio`,this.onDownloadedPartialAudio).addEventListener(`downloadAudioError`,this.onDownloadAudioError)}onDownloadedAudio=async(e,t)=>{if(L.log(`downloadedAudio`,t),!this.downloading){L.log(`skip downloadedAudio`);return}let{videoId:n,fileId:r,audioData:i}=t,a=this.getCanonicalUrl(n);try{await this.videoHandler.votClient.requestVtransAudio(a,e,{audioFile:i,fileId:r})}catch(e){L.error(`Failed to upload downloaded audio`,e),this.finishDownloadFailure(Error(`Audio downloader failed while uploading full audio`));return}this.finishDownloadSuccess()};onDownloadedPartialAudio=async(e,t)=>{if(L.log(`downloadedPartialAudio`,t),!this.downloading){L.log(`skip downloadedPartialAudio`);return}let{audioData:n,fileId:r,videoId:i,amount:a,version:o,index:s}=t,c=this.getCanonicalUrl(i);try{await this.videoHandler.votClient.requestVtransAudio(c,e,{audioFile:n,chunkId:s},{audioPartsLength:a,fileId:r,version:o})}catch(e){L.error(`Failed to upload downloaded audio chunk`,e),this.finishDownloadFailure(Error(`Audio downloader failed while uploading chunk`));return}s===a-1&&this.finishDownloadSuccess()};onDownloadAudioError=async e=>{if(!this.downloading){L.log(`skip downloadAudioError`);return}L.log(`Failed to download audio ${e}`);let t=this.getCanonicalUrl(e);if(!(this.videoHandler.site.host===`youtube`&&this.videoHandler.data?.useAudioDownload)){this.finishDownloadFailure(new U(`VOTFailedDownloadAudio`));return}try{this.requestedFailAudio.has(t)?L.log(`fail-audio-js request already sent for this video`):(L.log(`Sending fail-audio-js request`),await this.videoHandler.votClient.requestVtransFailAudio(t),this.requestedFailAudio.add(t)),this.finishDownloadSuccess()}catch(e){L.error(`fail-audio-js request failed`,e),this.finishDownloadFailure(new U(`VOTFailedDownloadAudio`))}};finishDownloadSuccess(){this.downloading=!1,this.resolveDownloadWaiters()}finishDownloadFailure(e){this.downloading=!1,this.rejectDownloadWaiters(e)}getCanonicalUrl(e){return`https://youtu.be/${e}`}isLivelyVoiceUnavailableError(e){let t=ba(e);return!!t&&t.toLowerCase().includes(`обычная озвучка`)}scheduleRetry(e,t,n){return new Promise((r,i)=>{let a=null,o=()=>{a!==null&&clearTimeout(a),n.removeEventListener(`abort`,s)},s=()=>{o(),i(Sa())};if(n.addEventListener(`abort`,s,{once:!0}),n.aborted){s();return}a=setTimeout(async()=>{if(n.aborted){s();return}o();try{r(await e())}catch(e){i(e)}},t),a!==null&&(this.videoHandler.autoRetry=a)})}getVideoTranslationRetryDelayMs(e,t){return e>0?25e3:t<=600?6e4:75e3}async translateVideoImpl(e,t,n,r=null,i=!1,a=Ca,o={}){let{disableLivelyVoice:s=!1,retryAttempt:c=0}=o;clearTimeout(this.videoHandler.autoRetry),this.finishDownloadSuccess();let l=this.videoHandler.getRequestLangForTranslation(t,n);L.log(`[Translation] translateVideoImpl start`,{videoId:e.videoId,duration:e.duration,requestLang:t,requestLangForApi:l,responseLang:n,retryAttempt:c,disableLivelyVoice:s,shouldSendFailedAudio:i,translationHelpCount:r?.length??0}),L.log(e,`Translate video (requestLang: ${t}, requestLangForApi: ${l}, responseLang: ${n})`);let u=s;try{wa(a);let o=this.videoHandler.isLivelyVoiceAllowed(l,n),s=await this.requestTranslationWithLivelyFallback({videoData:e,requestLangForApi:l,responseLang:n,translationHelp:r,shouldSendFailedAudio:i,livelyDisabled:u,livelyVoiceAllowed:o});u=s.livelyDisabled;let d=s.useLivelyVoice,f=s.response;if(!f)throw Error(`Failed to get translation response`);if(L.log(`[Translation] translateVideoImpl response`,{videoId:e.videoId,useLivelyVoice:d,...Ks(f)}),wa(a),f.translated&&f.remainingTime<1)return L.log(`[Translation] translation finished`,{videoId:e.videoId,useLivelyVoice:d,...Ks(f)}),{...f,usedLivelyVoice:d};let p=f.message??V.get(`translationTakeFewMinutes`);if(L.log(`[Translation] translation still processing`,{videoId:e.videoId,useLivelyVoice:d,...Ks(f),message:p}),await this.videoHandler.updateTranslationErrorMsg(f.remainingTime>0?Fs(f.remainingTime,e=>V.get(e)):p,a),f.status===Gt.AUDIO_REQUESTED&&this.videoHandler.isYouTubeHosts())return this.videoHandler.hadAsyncWait=!0,L.log(`[Translation] audio download started`,{videoId:e.videoId,translationId:f.translationId}),this.downloading=!0,await this.audioDownloader.runAudioDownload(e.videoId,f.translationId,a),L.log(`[Translation] waiting for audio download completion`,{videoId:e.videoId,translationId:f.translationId,timeoutMs:15e3}),await this.waitForAudioDownloadCompletion(a,15e3),await this.translateVideoImpl(e,t,n,r,!0,a,{disableLivelyVoice:u,retryAttempt:c})}catch(t){if(xa(t))return L.log(`[Translation] translation aborted`,{videoId:e.videoId,retryAttempt:c}),null;let n=Gs(t);return L.error(`[Translation] translation failed`,{videoId:e.videoId,retryAttempt:c,error:t,mappedError:n}),await this.videoHandler.updateTranslationErrorMsg(Ws(n)??n,a),this.videoHandler.hadAsyncWait=Hs({aborted:!!this.videoHandler.actionsAbortController?.signal?.aborted,translateApiErrorsEnabled:!!this.videoHandler.data?.translateAPIErrors,hadAsyncWait:this.videoHandler.hadAsyncWait,videoId:e.videoId,error:t,notify:e=>this.videoHandler.notifier.translationFailed(e)}),null}this.videoHandler.hadAsyncWait=!0;let d=this.getVideoTranslationRetryDelayMs(c,e.duration);return L.log(`[Translation] scheduling translation retry`,{videoId:e.videoId,retryAttempt:c,retryDelayMs:d,duration:e.duration}),this.scheduleRetry(()=>this.translateVideoImpl(e,t,n,r,i,a,{disableLivelyVoice:u,retryAttempt:c+1}),d,a)}async requestTranslationWithLivelyFallback({videoData:e,requestLangForApi:t,responseLang:n,translationHelp:r,shouldSendFailedAudio:i,livelyDisabled:a,livelyVoiceAllowed:o}){let s=!a&&o&&!!this.videoHandler.data?.useLivelyVoice;for(L.log(`[Translation] requesting translation from VOT client`,{videoId:e.videoId,requestLangForApi:t,responseLang:n,shouldSendFailedAudio:i,livelyDisabled:a,livelyVoiceAllowed:o,useLivelyVoice:s,translationHelpCount:r?.length??0});;){try{L.log(`[Translation] votClient.translateVideo call`,{videoId:e.videoId,requestLangForApi:t,responseLang:n,useLivelyVoice:s,shouldSendFailedAudio:i,translationHelpCount:r?.length??0});let o=await this.videoHandler.votClient.translateVideo({videoData:e,requestLang:t,responseLang:n,translationHelp:r,extraOpts:{useLivelyVoice:s,videoTitle:this.videoHandler.videoData?.title},shouldSendFailedAudio:i});if(!s||!this.isLivelyVoiceUnavailableError(o))return L.log(`[Translation] votClient.translateVideo resolved`,{videoId:e.videoId,useLivelyVoice:s,...Ks(o)}),{response:o,useLivelyVoice:s,livelyDisabled:a};L.warn(`[Translation] lively voice unavailable in response`,{videoId:e.videoId,useLivelyVoice:s,...Ks(o)})}catch(t){if(!s||!this.isLivelyVoiceUnavailableError(t))throw t;L.warn(`[Translation] lively voice unavailable in error`,{videoId:e.videoId,useLivelyVoice:s,error:t})}a=!0,s=!1,L.log(`[Translation] retrying translation without lively voice`,{videoId:e.videoId,requestLangForApi:t,responseLang:n})}}waitForAudioDownloadCompletion(e,t){return this.downloading?new Promise((n,r)=>{let i,a=()=>{s(),r(Sa())},o=setTimeout(()=>{s(),n()},t),s=()=>{clearTimeout(o),e.removeEventListener(`abort`,a),this.downloadWaiters.delete(i)};i={resolve:()=>{s(),n()},reject:e=>{s(),r(e)}},this.downloadWaiters.add(i),e.addEventListener(`abort`,a,{once:!0}),e.aborted&&a()}):Promise.resolve()}resolveDownloadWaiters(){this.forEachDownloadWaiter(e=>e.resolve())}rejectDownloadWaiters(e){this.forEachDownloadWaiter(t=>t.reject(e))}forEachDownloadWaiter(e){if(!this.downloadWaiters.size)return;let t=Array.from(this.downloadWaiters);this.downloadWaiters.clear();for(let n of t)e(n)}},Js=class{state={status:`idle`};deps;constructor(e){this.deps=e}get currentState(){return this.state}setState(e){this.state=e,L.log(`[TranslationOrchestrator] state`,e)}reset(){this.setState({status:`idle`})}async runAutoTranslationIfEligible(){if(this.state.status===`idle`&&this.deps.isFirstPlay()&&this.deps.isAutoTranslateEnabled()&&this.deps.getVideoId()){if(this.deps.isMobileYouTubeMuted?.()){L.log(`[TranslationOrchestrator] Mobile YouTube video is muted, deferring auto-translate`),this.setState({status:`deferred`,reason:`muted`}),this.deps.setMuteWatcher?.(()=>{L.log(`[TranslationOrchestrator] Video unmuted, running deferred auto-translate`),this.setState({status:`idle`}),this.runAutoTranslationIfEligible()});return}this.setState({status:`pending`,reason:`auto`});try{await this.deps.scheduleAutoTranslate(),this.deps.setFirstPlay(!1),this.reset()}catch(e){throw this.setState({status:`error`,message:e}),e}}}};function Ys(e,t={}){let{requireVideoData:n=!1,clearVideoData:r=!1}=t;n&&!e.videoData||(r&&(e.videoData=void 0),e.stopTranslation(),e.resetSubtitlesWidget())}function Xs(e,t={}){let{hideMenu:n=!1}=t;e?.votButton?.container&&(e.votButton.container.hidden=!0),n&&e?.votMenu&&(e.votMenu.hidden=!0)}function Zs(e,t,n={}){let{requireVideoData:r,clearVideoData:i,hideMenu:a}=n;Ys(e,{requireVideoData:r,clearVideoData:i}),Xs(t,{hideMenu:a})}var Qs=class{host;lifecycleGeneration=0;lastSetCanPlaySourceKey=``;activeSetCanPlaySourceKey=``;setCanPlayRequested=!1;setCanPlayLoopPromise;constructor(e){this.host=e}isStale(e){return e!==this.lifecycleGeneration}resetActions(e){if(typeof this.host.resetActionsAbortController==`function`){this.host.resetActionsAbortController(e);return}this.host.actionsAbortController?.abort(e)}invalidateActiveSession(e){this.lifecycleGeneration!==0&&(this.lifecycleGeneration+=1,this.resetActions(`[VideoLifecycle] ${e}`),L.log(`[VideoLifecycle] cancelled active session (active: ${this.lifecycleGeneration})`,{reason:e}))}startSession(e){this.lifecycleGeneration+=1;let t=this.lifecycleGeneration;return this.resetActions(`[VideoLifecycle][session:${t}] ${e}`),L.log(`[VideoLifecycle][session:${t}] started`,{reason:e}),t}shouldAbortHandleSrcChanged(e,t){return this.isStale(e)?(L.log(`[VideoLifecycle][session:${e}] handleSrcChanged aborted at ${t} (active: ${this.lifecycleGeneration})`),!0):!1}showOverlayButton(e){e.votButton.container.hidden=!1,e.votButton.opacity=1,this.host.queueOverlayAutoHide?.()}teardown(){this.setCanPlayRequested=!1,this.invalidateActiveSession(`teardown`)}getCurrentSourceKey(){let e=this.host.video.srcObject?`1`:`0`;if(this.host.site.host===`youtube`){let t=globalThis.location.pathname;return`${`${globalThis.location.origin}${t}${globalThis.location.search}`}||${e}`}let t=this.host.video.currentSrc||this.host.video.src||``;return`${globalThis.location.href}||${t}||${e}`}resolveContainer(){let{site:e,video:t,container:n}=this.host;return e.selector?Vo(t,e.selector)||(n.isConnected&&Io(n,t)?n:t.parentElement??n):t.parentElement??n}async setCanPlay(){if(this.setCanPlayRequested=!0,this.setCanPlayLoopPromise!==void 0){let e=this.getCurrentSourceKey();return this.activeSetCanPlaySourceKey&&e!==this.activeSetCanPlaySourceKey?this.invalidateActiveSession(`setCanPlay source changed while previous trigger is running`):L.log(`[VideoLifecycle] setCanPlay deduplicated for same source`,{sourceKey:e}),await this.setCanPlayLoopPromise}let e=(async()=>{for(;this.setCanPlayRequested;)this.setCanPlayRequested=!1,await this.runSetCanPlayOnce()})();this.setCanPlayLoopPromise=e;try{await e}finally{this.setCanPlayLoopPromise===e&&(this.setCanPlayLoopPromise=void 0)}}async runSetCanPlayOnce(){let e=this.getCurrentSourceKey();if(this.host.videoData?.videoId&&e===this.lastSetCanPlaySourceKey){L.log(`[VideoLifecycle] setCanPlay deduplicated for same source`,{sourceKey:e});return}let t;try{t=await this.host.getVideoData()}catch(t){L.log(`[VideoLifecycle] getVideoData failed for source ${e}`,t),this.host.videoData=void 0,Xs(this.host.uiManager.votOverlayView,{hideMenu:!0});return}if(this.getCurrentSourceKey()!==e){L.log(`[VideoLifecycle] discarded stale getVideoData result after source change`,{sourceKey:e});return}this.host.videoData=t,this.activeSetCanPlaySourceKey=e;let n=this.startSession(`setCanPlay (source: ${e})`);L.log(`[VideoLifecycle][session:${n}] setCanPlay started`,{sourceKey:e});try{if(await this.handleSrcChanged(n,e),this.isStale(n)){L.log(`[VideoLifecycle][session:${n}] setCanPlay aborted after src change (active: ${this.lifecycleGeneration})`);return}let t=this.runAutoSubtitlesIfEnabled(n);if(await this.host.translationOrchestrator.runAutoTranslationIfEligible(),this.isStale(n)){L.log(`[VideoLifecycle][session:${n}] auto-translation result ignored (stale session)`);return}if(await t,this.isStale(n)){L.log(`[VideoLifecycle][session:${n}] auto-subtitles result ignored (stale session)`);return}L.log(`[VideoLifecycle][session:${n}] setCanPlay finished`)}finally{this.activeSetCanPlaySourceKey===e&&(this.activeSetCanPlaySourceKey=``)}}async runAutoSubtitlesIfEnabled(e){if(!(!this.host.data.autoSubtitles||!this.host.videoData?.videoId))try{await this.host.enableSubtitlesForCurrentLangPair()}catch(t){L.log(`[VideoLifecycle][session:${e}] auto-subtitles failed`,t)}}async handleSrcChanged(e,t){let n=typeof e==`number`?e:this.startSession(`manual handleSrcChanged`),r=typeof t==`string`&&t.length>0?t:this.getCurrentSourceKey();if(this.shouldAbortHandleSrcChanged(n,`before start`))return;L.log(`[VideoLifecycle][session:${n}] src changed`,{sourceKey:r}),this.host.translationOrchestrator.reset(),this.host.firstPlay=!0;let i=this.host.uiManager.votOverlayView;Zs(this.host,i,{requireVideoData:!0}),!this.host.video.src&&!this.host.video.currentSrc&&!this.host.video.srcObject&&Xs(i,{hideMenu:!0});let a=this.resolveContainer();if(a!==this.host.container&&(this.host.container=a),this.shouldAbortHandleSrcChanged(n,`before getVideoData`)||(this.showOverlayButton(i),this.shouldAbortHandleSrcChanged(n,`after getVideoData`)))return;if(!this.host.videoData?.videoId){L.log(`[VideoLifecycle][session:${n}] No videoId resolved, hiding overlay`),Xs(i,{hideMenu:!0});return}let o=this.host.getPreferredSubtitlesLanguage(this.host.videoData.detectedLanguage,this.host.videoData.responseLanguage);if(o){let e=this.host.getSubtitlesCacheKey(this.host.videoData.videoId,this.host.videoData.detectedLanguage,o),t=this.host.cacheManager.getSubtitles(e);this.host.subtitles=t??[],this.host.subtitlesCacheKey=t===void 0?null:e}else this.host.subtitles=[],this.host.subtitlesCacheKey=null;await this.host.updateSubtitlesLangSelect(),!this.shouldAbortHandleSrcChanged(n,`after subtitles update`)&&(this.host.translateToLang=this.host.data.responseLanguage??`ru`,this.host.setSelectMenuValues(this.host.videoData.detectedLanguage,this.host.videoData.responseLanguage),this.showOverlayButton(i),this.lastSetCanPlaySourceKey=r,L.log(`[VideoLifecycle][session:${n}] src handling finished`))}};function $s(e,t){let n=()=>e;return{get video(){return n().video},get site(){return n().site},get container(){return n().container},set container(e){n().container!==e&&(n().container=e,n().uiManager.updateMount(t(e)))},get firstPlay(){return n().firstPlay},set firstPlay(e){n().firstPlay=e},stopTranslation:()=>e.stopTranslation(),get uiManager(){return n().uiManager},getVideoData:()=>e.getVideoData(),cacheManager:{getSubtitles:e=>n().cacheManager.getSubtitles(e)},getSubtitlesCacheKey:(t,n,r)=>e.getSubtitlesCacheKey(t,n,r),getPreferredSubtitlesLanguage:(t,n)=>e.getPreferredSubtitlesLanguage(t,n),updateSubtitlesLangSelect:()=>e.updateSubtitlesLangSelect(),enableSubtitlesForCurrentLangPair:()=>e.enableSubtitlesForCurrentLangPair(),setSelectMenuValues:(t,n)=>e.setSelectMenuValues(t,n),get translateToLang(){return n().translateToLang},set translateToLang(e){n().translateToLang=e},get data(){return n().data??{}},get subtitles(){return n().subtitles},set subtitles(e){n().subtitles=e},get subtitlesCacheKey(){return n().subtitlesCacheKey},set subtitlesCacheKey(e){n().subtitlesCacheKey=e},get videoData(){return n().videoData},set videoData(e){n().videoData=e},get actionsAbortController(){return n().actionsAbortController},set actionsAbortController(e){n().actionsAbortController=e},resetActionsAbortController:t=>e.resetActionsAbortController(t),translationOrchestrator:e.translationOrchestrator,resetSubtitlesWidget:()=>e.resetSubtitlesWidget(),queueOverlayAutoHide:()=>e.overlayVisibility?.queueAutoHide()}}var ec=450,tc=new RegExp([String.raw`(?:https?:\/\/|www\.)\S+`,String.raw`#[^\s#]+`,String.raw`auto-generated\s+by\s+youtube`,String.raw`provided\s+to\s+youtube\s+by`,String.raw`released\s+on`,String.raw`\bpaypal\b`,String.raw`\b0x[a-f0-9]{40}\b`,String.raw`\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b`,String.raw`\b(?:bc1|tb1|bcrt1)[ac-hj-np-z02-9]{11,71}\b`,String.raw`\b(?:-1|0):[a-f0-9]{64}\b`].join(`|`),`giu`),nc=/[\p{N}\p{P}\p{S}]+/gu,rc=/\s+/g,ic=/\p{L}/u;function ac(e,t){return e.length<=t?e:e.slice(0,t).trimEnd()}function oc(e,t){let n=`${e??``} ${t??``}`.trim();if(!n)return``;let r=n.normalize(`NFKC`).replace(tc,` `).replace(nc,` `).replace(rc,` `).trim();return ic.test(r)?ac(r,ec):``}var sc=5e3,cc=2**53-1,lc=null,uc=0,dc=null,fc=0;async function pc(){let e=Date.now();if(lc&&e-uci){let t=Ac(e,`up`,r);return Math.min(a,t)}return Ac(e,`nearest`,r)}var Mc=new Set([`youtube`,`googledrive`]),Nc=Mc,Pc=new Set([`rutube`,`ok`]),Fc=new Set([`youtube`,`invidious`,`piped`]);function Ic(e){return Mc.has(e)}function Lc(e){return Nc.has(e)}function Rc(e){return Pc.has(e)}function zc(e){return Lc(e.host)&&e.additionalData!==`mobile`}function Bc(e){return Fc.has(e)}var Vc={rutube:`ru`,"ok.ru":`ru`,mail_ru:`ru`,weverse:`ko`,niconico:`ja`,youku:`zh`,bilibili:`zh`,weibo:`zh`,zdf:`de`},Hc=`.ytp-volume-panel [aria-valuenow]`,Uc=35,Wc=500,Gc=new Set(yn),Kc=new Map;function qc(e){let t=Kc.get(e);if(t)return t;let n={};for(Kc.set(e,n);Kc.size>Wc;){let e=Kc.keys().next().value;if(typeof e!=`string`)break;Kc.delete(e)}return n}function Jc(e){if(typeof e!=`string`)return;let t=e.toLowerCase().split(/[-_]/)[0];return Gc.has(t)?t:void 0}function Yc(e){return!!(e&&e!==`auto`)}function Xc(e,t){return oc(typeof e==`string`?e:``,typeof t==`string`?t:void 0)}function Zc(e){let t=Vc[e];if(t)return t;if(e===`vk`){let e=document.getElementsByTagName(`track`)?.[0]?.srclang;return Jc(e)}}function Qc(e){if(!Array.isArray(e)||e.length===0)return;let t=t=>{for(let n of e){if(!n||typeof n!=`object`)continue;let e=n;if(e.source!==`youtube`||typeof e.translatedFromLanguage==`string`||t&&e.isAutoGenerated===!0)continue;let r=Jc(e.language);if(Yc(r))return r}};return t(!0)??t(!1)}async function $c(e){if(e.isStream)return{detectedLanguage:`auto`};if(e.userOverrideLanguage)return{detectedLanguage:e.userOverrideLanguage};let t=Zc(e.host);if(Yc(t))return{detectedLanguage:t,cacheLanguage:t};let n=Jc(e.possibleLanguage);if(Yc(n))return{detectedLanguage:n,cacheLanguage:n};let r=e.host===`youtube`?Qc(e.subtitles):void 0;if(Yc(r))return{detectedLanguage:r,cacheLanguage:r};if(e.cachedDetectedLanguage)return{detectedLanguage:e.cachedDetectedLanguage};if(!e.allowTextLanguageDetection)return{detectedLanguage:`auto`};let i=Xc(e.title,e.description);if(!i||i.length0?i/a*100:i):null}var tl=class{videoHandler;constructor(e){this.videoHandler=e}setDetectedLanguageCache(e,t){qc(e).detectedLanguage=t}rememberUserLanguageSelection(e,t){let n=Jc(t);if(!Yc(n)){let t=Kc.get(e);t&&delete t.userLanguageOverride;return}let r=qc(e);r.userLanguageOverride=n,r.detectedLanguage=n}rememberDetectedLanguage(e,t){let n=Jc(t);Yc(n)&&(this.setDetectedLanguageCache(e,n),this.videoHandler.videoData?.videoId===e&&(this.videoHandler.videoData.detectedLanguage=n))}async detectLanguageSingleFlight(e,t){let n=qc(e),r=n.detectInFlight;if(r!==void 0)return r;let i=(async()=>{L.log(`Detecting language text: ${t}`);let e=Jc(await yc(t));return Yc(e)?e:void 0})();n.detectInFlight=i;try{return await i}finally{n.detectInFlight===i&&delete n.detectInFlight}}async ensureDetectedLanguageForTranslation(e){if(!e?.videoId||e.detectedLanguage!==`auto`)return;let t=qc(e.videoId),{detectedLanguage:n,cacheLanguage:r}=await $c({isStream:e.isStream,host:this.videoHandler.site.host,possibleLanguage:e.detectedLanguage,subtitles:e.subtitles,userOverrideLanguage:t.userLanguageOverride,cachedDetectedLanguage:t.detectedLanguage,title:e.title,description:e.description,allowTextLanguageDetection:!0,detectLanguage:async t=>await this.detectLanguageSingleFlight(e.videoId,t)});r&&this.setDetectedLanguageCache(e.videoId,r),!(!n||n===`auto`)&&this.videoHandler.setSelectMenuValues(n,this.videoHandler.translateToLang)}async getVideoData(){let{duration:e,url:t,videoId:n,host:r,title:i,translationHelp:a=null,localizedTitle:o,description:s,detectedLanguage:c,subtitles:l,isStream:u=!1}=await qr(this.videoHandler.site,{fetchFn:z,video:this.videoHandler.video,language:V.lang}),d=qc(n),{detectedLanguage:p,cacheLanguage:m}=await $c({isStream:u,host:this.videoHandler.site.host,possibleLanguage:c,subtitles:l,userOverrideLanguage:d.userLanguageOverride,cachedDetectedLanguage:d.detectedLanguage,title:i,description:s,allowTextLanguageDetection:!1,detectLanguage:async e=>await this.detectLanguageSingleFlight(n,e)});m&&this.setDetectedLanguageCache(n,m);let h={translationHelp:a,isStream:u,duration:e||this.videoHandler.video?.duration||f.defaultDuration,videoId:n,url:t,host:r,detectedLanguage:p,responseLanguage:this.videoHandler.translateToLang,subtitles:l,title:i,localizedTitle:o,description:s,downloadTitle:o??i??document.title??n};return d.lastLoggedDetectedLanguage!==p&&(console.log(`[VOT] Detected language:`,p),d.lastLoggedDetectedLanguage=p),h}async videoValidator(){let e=this.videoHandler.videoData,t=this.videoHandler.data;if(!e||!t)throw new U(`VOTNoVideoIDFound`);if(L.log(`VideoValidator videoData: `,this.videoHandler.videoData),this.videoHandler.data.enabledDontTranslateLanguages&&this.videoHandler.data.dontTranslateLanguages?.includes(this.videoHandler.videoData.detectedLanguage))throw new U(`VOTDisableFromYourLang`);if(this.videoHandler.videoData.isStream)throw new U(`VOTStreamNotAvailable`);if(this.videoHandler.videoData.duration>14400)throw new U(`VOTVideoIsTooLong`);return!0}getVideoVolume(){let e=this.videoHandler.video;if(e){if(Ic(this.videoHandler.site.host)){let e=el(Hc);if(e!=null)return Oc(e);let t=F.getVolume();if(typeof t==`number`&&Number.isFinite(t))return Ac(t)}return Ac(e.volume)}}setVideoVolume(e){let t=Ac(e);if(!Ic(this.videoHandler.site.host))return this.videoHandler.video.volume=t,this;try{let e=F.setVolume(t);if(typeof e==`boolean`&&e||typeof e==`number`&&Number.isFinite(e))return this}catch{}return this.videoHandler.video.volume=t,this}isMuted(){return Ic(this.videoHandler.site.host)?F.isMuted():this.videoHandler.video?.muted}syncVideoVolumeSlider(){let e=this.videoHandler.uiManager.votOverlayView;if(!e?.isInitialized())return this;let t=Ic(this.videoHandler.site.host)?el(Hc):null,n=this.isMuted()?0:t??Dc(this.getVideoVolume()??0);return e.videoVolumeSlider.value=n,this.videoHandler.onVideoVolumeSliderSynced?.(n),this}setSelectMenuValues(e,t){let n=this.videoHandler.videoData;if(!n)return this;let r=Jc(e)??`auto`,i=`${r}->${t}`,a=qc(n.videoId);a.lastLoggedLangPair!==i&&(console.log(`[VOT] Set translation from ${r} to ${t}`),a.lastLoggedLangPair=i),n.detectedLanguage=r,n.responseLanguage=t,this.videoHandler.translateFromLang=r,this.videoHandler.translateToLang=t;let o=this.videoHandler.uiManager.votOverlayView;return o?.isInitialized()?(o.languagePairSelect.fromSelect.selectTitle=V.getLangLabel(r),o.languagePairSelect.toSelect.selectTitle=V.getLangLabel(t),o.languagePairSelect.fromSelect.setSelectedValue(r),o.languagePairSelect.toSelect.setSelectedValue(t),this):this}},nl=globalThis,rl=e=>e,il=nl.trustedTypes,al=il?il.createPolicy(`lit-html`,{createHTML:e=>e}):void 0,ol=`$lit$`,sl=`lit$${Math.random().toFixed(9).slice(2)}$`,cl=`?`+sl,ll=`<${cl}>`,ul=document,dl=()=>ul.createComment(``),fl=e=>e===null||typeof e!=`object`&&typeof e!=`function`,pl=Array.isArray,ml=e=>pl(e)||typeof e?.[Symbol.iterator]==`function`,hl=`[ +\f\r]`,gl=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,_l=/-->/g,vl=/>/g,yl=RegExp(`>|${hl}(?:([^\\s"'>=/]+)(${hl}*=${hl}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,`g`),bl=/'/g,xl=/"/g,Sl=/^(?:script|style|textarea|title)$/i,Cl=e=>(t,...n)=>({_$litType$:e,strings:t,values:n}),wl=Cl(1),G=Cl(2),Tl=Symbol.for(`lit-noChange`),K=Symbol.for(`lit-nothing`),El=new WeakMap,Dl=ul.createTreeWalker(ul,129);function Ol(e,t){if(!pl(e)||!e.hasOwnProperty(`raw`))throw Error(`invalid template strings array`);return al===void 0?t:al.createHTML(t)}var kl=(e,t)=>{let n=e.length-1,r=[],i,a=t===2?``:t===3?``:``,o=gl;for(let t=0;t`?(o=i??gl,l=-1):c[1]===void 0?l=-2:(l=o.lastIndex-c[2].length,s=c[1],o=c[3]===void 0?yl:c[3]===`"`?xl:bl):o===xl||o===bl?o=yl:o===_l||o===vl?o=gl:(o=yl,i=void 0);let d=o===yl&&e[t+1].startsWith(`/>`)?` `:``;a+=o===gl?n+ll:l>=0?(r.push(s),n.slice(0,l)+ol+n.slice(l)+sl+d):n+sl+(l===-2?t:d)}return[Ol(e,a+(e[n]||``)+(t===2?``:t===3?``:``)),r]},Al=class e{constructor({strings:t,_$litType$:n},r){let i;this.parts=[];let a=0,o=0,s=t.length-1,c=this.parts,[l,u]=kl(t,n);if(this.el=e.createElement(l,r),Dl.currentNode=this.el.content,n===2||n===3){let e=this.el.content.firstChild;e.replaceWith(...e.childNodes)}for(;(i=Dl.nextNode())!==null&&c.length0){i.textContent=il?il.emptyScript:``;for(let n=0;n2||n[0]!==``||n[1]!==``?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=K}_$AI(e,t=this,n,r){let i=this.strings,a=!1;if(i===void 0)e=jl(this,e,t,0),a=!fl(e)||e!==this._$AH&&e!==Tl,a&&(this._$AH=e);else{let r=e,o,s;for(e=i[0],o=0;o{let r=n?.renderBefore??t,i=r._$litPart$;if(i===void 0){let e=n?.renderBefore??null;r._$litPart$=i=new Nl(t.insertBefore(dl(),e),e,void 0,n??{})}return i._$AI(e),i};function Bl(){if(globalThis.__votKeyboardNavInitialized)return;globalThis.__votKeyboardNavInitialized=!0;let e=document.documentElement,t=`vot-keyboard-nav`,n=()=>e.classList.add(t),r=()=>e.classList.remove(t);globalThis.addEventListener(`keydown`,e=>{e.key===`Tab`&&n()},!0);for(let e of[`pointerdown`,`mousedown`,`touchstart`])globalThis.addEventListener(e,r,{capture:!0,passive:!0})}Bl();var J={makeButtonLike(e,{ariaLabel:t}={}){e.setAttribute(`role`,`button`),e.hasAttribute(`tabindex`)||(e.tabIndex=0);let n=e.tabIndex,r=()=>{e.getAttribute(`disabled`)===`true`?(e.setAttribute(`aria-disabled`,`true`),e.tabIndex=-1):(e.removeAttribute(`aria-disabled`),e.tabIndex=n)};return r(),new MutationObserver(()=>r()).observe(e,{attributes:!0,attributeFilter:[`disabled`]}),t&&e.setAttribute(`aria-label`,t),e.addEventListener(`keydown`,t=>{e.getAttribute(`disabled`)===`true`||e.getAttribute(`aria-disabled`)===`true`||(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),e.click())}),e},createEl(e,t=[],n=null){let r=document.createElement(e);return t.length&&r.classList.add(...t),n!==null&&r.append(n),r},createHeader(e,t=4){return J.createEl(`vot-block`,[`vot-header`,`vot-header-level-${t}`],e)},createInformation(e,t){let n=J.createEl(`vot-block`,[`vot-info`]),r=J.createEl(`vot-block`);q(e,r);let i=J.createEl(`vot-block`);return q(t,i),n.append(r,i),{container:n,header:r,value:i}},createButton(e){let t=J.createEl(`vot-block`,[`vot-button`],e);return J.makeButtonLike(t)},createTextButton(e){let t=J.createEl(`vot-block`,[`vot-text-button`],e);return J.makeButtonLike(t)},createOutlinedButton(e){let t=J.createEl(`vot-block`,[`vot-outlined-button`],e);return J.makeButtonLike(t)},createIconButton(e,t={}){let n=J.createEl(`vot-block`,[`vot-icon-button`]);return q(e,n),J.makeButtonLike(n,t)},createInlineLoader(){return J.createEl(`vot-block`,[`vot-inline-loader`])},createPortal(e=!1){return J.createEl(`vot-block`,[`vot-portal${e?`-local`:``}`])},createSubtitleInfo(e,t,n){let r=J.createEl(`vot-block`,[`vot-subtitles-info`]);r.id=`vot-subtitles-info`;let i=J.createEl(`vot-block`,[`vot-subtitles-info-service`],V.get(`VOTTranslatedBy`).replace(`{0}`,n)),a=J.createEl(`vot-block`,[`vot-subtitles-info-header`],e),o=J.createEl(`vot-block`,[`vot-subtitles-info-context`],t);return r.append(i,a,o),{container:r,translatedWith:i,header:a,context:o}}},Vl=[`left`,`top`,`right`,`bottom`],Hl=[`hover`,`click`],Y=class e{showed=!1;target;anchor;content;position;preferredPosition;trigger;parentElement;layoutRoot;offsetX;offsetY;_hidden;autoLayout;pageWidth;pageHeight;globalOffsetX;globalOffsetY;renderOffsetX;renderOffsetY;maxWidth;backgroundColor;borderRadius;_bordered;container;onResizeObserver;intersectionObserver;scrollListening=!1;positionRafId=null;destroyFallbackTimerId;static DESTROY_FALLBACK_MS=700;tooltipId=typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`vot-tooltip-${Math.random().toString(36).slice(2)}`;prevAriaDescribedBy=null;constructor({target:t,anchor:n=void 0,content:r=``,position:i=`top`,trigger:a=`hover`,offset:o=4,maxWidth:s=void 0,hidden:c=!1,autoLayout:l=!0,backgroundColor:u=void 0,borderRadius:d=void 0,bordered:f=!0,parentElement:p=document.body,layoutRoot:m=document.documentElement}){if(!(t instanceof HTMLElement))throw TypeError(`target must be a valid HTMLElement`);this.target=t,this.anchor=n instanceof HTMLElement?n:t,this.content=r,typeof o==`number`?this.offsetY=this.offsetX=o:(this.offsetX=o.x,this.offsetY=o.y),this._hidden=c,this.autoLayout=l,this.trigger=e.validateTrigger(a)?a:`hover`,this.position=e.validatePos(i)?i:`top`,this.preferredPosition=this.position,this.parentElement=p,this.layoutRoot=m,this.borderRadius=d,this._bordered=f,this.maxWidth=s,this.backgroundColor=u,this.updatePageSize(),this.init()}static validatePos(e){return Vl.includes(e)}static validateTrigger(e){return Hl.includes(e)}setPosition(t){return this.preferredPosition=e.validatePos(t)?t:`top`,this.position=this.preferredPosition,this.schedulePositionUpdate(),this}setContent(e){return this.content=e,this.container?(this.container.replaceChildren(),typeof e==`string`?this.container.textContent=e:this.container.append(e),this.schedulePositionUpdate(),this):this}updateMount({parentElement:e,layoutRoot:t}){return e&&this.parentElement!==e&&(this.parentElement=e,this.container?.isConnected&&e.appendChild(this.container)),t&&this.layoutRoot!==t&&(this.layoutRoot=t),this.schedulePositionUpdate(),this}onResize=()=>{this.schedulePositionUpdate()};onClick=()=>{this.showed?this.destroy():this.create()};onTargetKeyDown=e=>{e.key!==`Escape`||!this.showed||this.destroy()};onScroll=()=>{this.schedulePositionUpdate()};onHoverPointerDown=e=>{e.pointerType!==`mouse`&&this.create()};onHoverPointerUp=e=>{e.pointerType!==`mouse`&&this.destroy()};onMouseEnter=()=>{this.create()};onMouseLeave=e=>{this.isInTooltipContext(e.relatedTarget)||this.destroy()};onTooltipMouseLeave=e=>{this.isInTooltipContext(e.relatedTarget)||this.destroy()};isInTooltipContext(e){return e instanceof Node?this.target.contains(e)||this.container?.contains(e):!1}updatePageSize(){if(this.layoutRoot===document.documentElement)this.globalOffsetX=0,this.globalOffsetY=0;else{let{left:e,top:t}=this.layoutRoot.getBoundingClientRect();this.globalOffsetX=e,this.globalOffsetY=t}let{left:e,top:t}=this.parentElement.getBoundingClientRect();return this.renderOffsetX=e,this.renderOffsetY=t,this.pageWidth=this.layoutRoot.clientWidth||document.documentElement.clientWidth,this.pageHeight=this.layoutRoot.clientHeight||document.documentElement.clientHeight,this}onIntersect=([e])=>{if(!e.isIntersecting)return this.destroy(!0)};init(){return this.onResizeObserver=new ResizeObserver(this.onResize),this.intersectionObserver=new IntersectionObserver(this.onIntersect),this.target.addEventListener(`keydown`,this.onTargetKeyDown),this.trigger===`click`?(this.target.addEventListener(`pointerdown`,this.onClick),this):(this.target.addEventListener(`mouseenter`,this.onMouseEnter),this.target.addEventListener(`mouseleave`,this.onMouseLeave),this.target.addEventListener(`focusin`,this.onMouseEnter),this.target.addEventListener(`focusout`,this.onMouseLeave),this.target.addEventListener(`pointerdown`,this.onHoverPointerDown),this.target.addEventListener(`pointerup`,this.onHoverPointerUp),this)}release(){return this.destroy(!0),this.detachScrollListener(),this.target.removeEventListener(`keydown`,this.onTargetKeyDown),this.trigger===`click`?(this.target.removeEventListener(`pointerdown`,this.onClick),this):(this.target.removeEventListener(`mouseenter`,this.onMouseEnter),this.target.removeEventListener(`mouseleave`,this.onMouseLeave),this.target.removeEventListener(`focusin`,this.onMouseEnter),this.target.removeEventListener(`focusout`,this.onMouseLeave),this.target.removeEventListener(`pointerdown`,this.onHoverPointerDown),this.target.removeEventListener(`pointerup`,this.onHoverPointerUp),this)}schedulePositionUpdate(){this.container&&this.positionRafId===null&&(this.positionRafId=requestAnimationFrame(()=>{this.positionRafId=null,this.updatePageSize(),this.updatePos()}))}cancelPositionUpdate(){this.positionRafId!==null&&(cancelAnimationFrame(this.positionRafId),this.positionRafId=null)}clearDestroyFallbackTimer(){this.destroyFallbackTimerId!==void 0&&(globalThis.clearTimeout(this.destroyFallbackTimerId),this.destroyFallbackTimerId=void 0)}create(){return this.destroy(!0),this.showed=!0,this.container=J.createEl(`vot-block`,[`vot-tooltip`],this.content),this.bordered&&this.container.classList.add(`vot-tooltip-bordered`),this.container.setAttribute(`role`,`tooltip`),this.container.id=this.tooltipId,this.container.dataset.trigger=this.trigger,this.container.dataset.position=this.position,this.parentElement.appendChild(this.container),this.schedulePositionUpdate(),this.backgroundColor!==void 0&&(this.container.style.backgroundColor=this.backgroundColor),this.borderRadius!==void 0&&(this.container.style.borderRadius=`${this.borderRadius}px`),this.hidden?this.container.hidden=!0:this.syncAriaDescribedBy(!0),this.container.style.opacity=`1`,this.trigger===`hover`&&this.container.addEventListener(`mouseleave`,this.onTooltipMouseLeave),this.attachScrollListener(),this.onResizeObserver?.observe(this.layoutRoot),this.anchor!==this.layoutRoot&&this.onResizeObserver?.observe(this.anchor),this.intersectionObserver?.observe(this.target),this}updatePos(){if(!this.container)return this;let{top:e,left:t}=this.calcPos(this.autoLayout,this.preferredPosition),n=Math.max(0,this.pageWidth-this.offsetX*2),r=R(this.maxWidth??n,0,n);return this.container.style.transform=`translate(${t}px, ${e}px)`,this.container.dataset.position=this.position,this.container.style.maxWidth=`${r}px`,this}calcPos(e=!0,t=this.preferredPosition){if(!this.container)return{top:0,left:0};let{left:n,right:r,top:i,bottom:a,width:o,height:s}=this.anchor.getBoundingClientRect(),{width:c,height:l}=this.container.getBoundingClientRect(),u=R(c,0,this.pageWidth),d=R(l,0,this.pageHeight),f={left:n-this.globalOffsetX,right:r-this.globalOffsetX,top:i-this.globalOffsetY,bottom:a-this.globalOffsetY,anchorWidth:o,anchorHeight:s},p={width:u,height:d},m=this.resolveTooltipPosition(f,p,t,e),h=this.getTooltipCoordinates(f,p,m);return this.position=m,{top:h.top+this.globalOffsetY-this.renderOffsetY,left:h.left+this.globalOffsetX-this.renderOffsetX}}resolveTooltipPosition(e,t,n,r){if(!r)return n;switch(n){case`top`:return R(e.top-t.height-this.offsetY,0,this.pageHeight)+this.offsetYthis.pageWidth-this.offsetX?`left`:`right`;case`bottom`:return R(e.bottom+this.offsetY,0,this.pageHeight-t.height)+t.height>this.pageHeight-this.offsetY?`top`:`bottom`;case`left`:return Math.max(0,e.left-t.width-this.offsetX)+t.width>e.left-this.offsetX?`right`:`left`;default:return n}}getTooltipCoordinates(e,t,n){switch(n){case`top`:return{top:R(e.top-t.height-this.offsetY,0,this.pageHeight),left:R(e.left-t.width/2+e.anchorWidth/2,this.offsetX,this.pageWidth-t.width-this.offsetX)};case`right`:return{top:R(e.top+(e.anchorHeight-t.height)/2,this.offsetY,this.pageHeight-t.height-this.offsetY),left:R(e.right+this.offsetX,0,this.pageWidth-t.width)};case`bottom`:return{top:R(e.bottom+this.offsetY,0,this.pageHeight-t.height),left:R(e.left-t.width/2+e.anchorWidth/2,this.offsetX,this.pageWidth-t.width-this.offsetX)};case`left`:return{top:R(e.top+(e.anchorHeight-t.height)/2,this.offsetY,this.pageHeight-t.height-this.offsetY),left:Math.max(0,e.left-t.width-this.offsetX)};default:return{top:0,left:0}}}destroy(t=!1){if(!this.container)return this;let n=this.container;if(this.cancelPositionUpdate(),this.clearDestroyFallbackTimer(),this.showed=!1,this.syncAriaDescribedBy(!1),this.onResizeObserver?.disconnect(),this.intersectionObserver?.disconnect(),this.detachScrollListener(),t)return n.remove(),this.container=void 0,this;n.removeEventListener(`mouseleave`,this.onTooltipMouseLeave),n.style.pointerEvents=`none`,n.style.opacity=`0`;let r=()=>{this.clearDestroyFallbackTimer(),n?.remove(),this.container===n&&(this.container=void 0)};return n.addEventListener(`transitionend`,r,{once:!0}),n.addEventListener(`transitioncancel`,r,{once:!0}),this.destroyFallbackTimerId=globalThis.setTimeout(r,e.DESTROY_FALLBACK_MS),this}syncAriaDescribedBy(e){let t=this.target.getAttribute(`aria-describedby`);if(this.prevAriaDescribedBy??=t,!e){this.prevAriaDescribedBy===null?this.target.removeAttribute(`aria-describedby`):this.target.setAttribute(`aria-describedby`,this.prevAriaDescribedBy),this.prevAriaDescribedBy=null;return}let n=new Set((t??``).split(/\s+/).filter(Boolean));n.add(this.tooltipId),this.target.setAttribute(`aria-describedby`,Array.from(n).join(` `))}set bordered(e){this._bordered=e,this.container?.classList.toggle(`vot-tooltip-bordered`,e)}get bordered(){return this._bordered}set hidden(e){this._hidden=e,this.container&&(this.container.hidden=e),this.showed&&this.syncAriaDescribedBy(!e)}get hidden(){return this._hidden}attachScrollListener(){this.scrollListening||(this.scrollListening=!0,document.addEventListener(`scroll`,this.onScroll,{passive:!0,capture:!0}))}detachScrollListener(){this.scrollListening&&(this.scrollListening=!1,document.removeEventListener(`scroll`,this.onScroll,{capture:!0}))}},Ul=Gl(`.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));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:var(--vot-shadow-1);transition:box-shadow var(--vot-duration-medium) var(--vot-easing-standard);outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-4)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:none!important;font-weight:500!important}.vot-button:before,.vot-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-button:before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-button:hover:before{opacity:.08}.vot-button:active:after{opacity:.32;background-size:100% 100%;transition:background-size}.vot-button:hover,.vot-button:active{box-shadow:var(--vot-shadow-2)}.vot-button[disabled=true]{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .12);color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);box-shadow:none;cursor:initial}.vot-button[disabled=true]:before,.vot-button[disabled=true]:after{opacity:0}.vot-outlined-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-theme));background-color:#0000;outline:none;font-size:14px;line-height:34px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-4)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:solid 1px var(--vot-border-color)!important;margin:0!important;font-weight:500!important}.vot-outlined-button:before,.vot-outlined-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-outlined-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-outlined-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-outlined-button:hover:before{opacity:.04}.vot-outlined-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-outlined-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-outlined-button[disabled=true]:before,.vot-outlined-button[disabled=true]:after{opacity:0}.vot-text-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-theme));background-color:#0000;outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-2)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:none!important;margin:0!important;font-weight:500!important}.vot-text-button:before,.vot-text-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-text-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-text-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-text-button:hover:before{opacity:.04}.vot-text-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-text-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-text-button[disabled=true]:before,.vot-text-button[disabled=true]:after{opacity:0}.vot-icon-button{--vot-helper-onsurface:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;width:36px;min-width:36px;height:36px;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:#0000;outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:none!important;border-radius:50%!important;margin:0!important;padding:0!important;font-weight:500!important}.vot-icon-button:before,.vot-icon-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-icon-button:before{background-color:var(--vot-helper-onsurface);transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-icon-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-icon-button:hover:before{opacity:.04}.vot-icon-button:active:after{opacity:.32;background-size:100% 100%;transition:background-size}.vot-icon-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);fill:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-icon-button[disabled=true]:before,.vot-icon-button[disabled=true]:after{opacity:0}.vot-icon-button svg{fill:inherit;stroke:inherit;width:24px;height:36px}.vot-hotkey{justify-content:flex-start;align-items:center;gap:var(--vot-space-3,12px);flex-wrap:wrap;display:flex}.vot-hotkey-label{word-break:break-word;max-width:80%}.vot-hotkey-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;background-color:#0000;outline:none;width:fit-content;min-width:32px;height:fit-content;font-size:15px;line-height:1.5;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-2)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border:solid 1px var(--vot-border-color)!important;margin:0!important;font-weight:400!important}.vot-hotkey-button:before,.vot-hotkey-button:after{content:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-hotkey-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-hotkey-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-hotkey-button:hover:before{opacity:.04}.vot-hotkey-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-hotkey-button[data-status=active]{color:rgb(var(--vot-helper-theme))}.vot-hotkey-button[data-status=active]:before{opacity:.04}.vot-hotkey-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-hotkey-button[disabled=true]:before,.vot-hotkey-button[disabled=true]:after{opacity:0}.vot-textfield{display:inline-block;--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), .38)!important;--vot-helper-safari2:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;--vot-helper-safari3:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;text-align:start!important;padding-top:6px!important;font-size:16px!important;line-height:1.5!important;position:relative!important}.vot-textfield>:is(input,textarea){box-sizing:border-box!important;border-style:solid!important;border-width:1px!important;border-color:transparent var(--vot-helper-safari2) var(--vot-helper-safari2)!important;width:100%!important;height:inherit!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;-webkit-text-fill-color:currentColor!important;font-family:inherit!important;font-size:inherit!important;line-height:inherit!important;caret-color:var(--vot-helper-theme)!important;background-color:#0000!important;border-radius:4px!important;margin:0!important;padding:15px 13px!important;transition:border .2s,box-shadow .2s!important;box-shadow:inset 1px 0 #0000,inset -1px 0 #0000,inset 0 -1px #0000!important}.vot-textfield>:is(input,textarea):not(:focus):not(:is(.vot-show-placeholder,.vot-show-placeholer))::placeholder{color:#0000!important}.vot-textfield>:is(input,textarea):not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2)!important}.vot-textfield>:is(input,textarea)+span{font-family:inherit;width:100%!important;max-height:100%!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;cursor:text!important;pointer-events:none!important;font-size:75%!important;line-height:15px!important;transition:color .2s,font-size .2s,line-height .2s!important;display:flex!important;position:absolute!important;top:0!important;left:0!important}.vot-textfield>:is(input,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;box-sizing:border-box!important;border-top:solid 1px var(--vot-helper-safari2)!important;pointer-events:none!important;min-width:10px!important;height:8px!important;margin-top:6px!important;transition:border .2s,box-shadow .2s!important;display:block!important;box-shadow:inset 0 1px #0000!important}.vot-textfield>input+span:before,.vot-textfield>textarea+span:before{border-left:1px solid #0000!important;border-radius:4px 0!important;margin-right:4px!important}.vot-textfield>input+span:after,.vot-textfield>textarea+span:after{border-right:1px solid #0000!important;border-radius:0 4px!important;flex-grow:1!important;margin-left:4px!important}.vot-textfield>input:is(.vot-show-placeholder,.vot-show-placeholer)+span:before,.vot-textfield>textarea:is(.vot-show-placeholder,.vot-show-placeholer)+span:before{margin-right:0!important}.vot-textfield>input:is(.vot-show-placeholder,.vot-show-placeholer)+span:after,.vot-textfield>textarea:is(.vot-show-placeholder,.vot-show-placeholer)+span:after{margin-left:0!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:#0000!important}.vot-textfield:hover>input:not(:disabled),.vot-textfield:hover>textarea:not(:disabled){border-color:transparent var(--vot-helper-safari3) var(--vot-helper-safari3)!important}.vot-textfield:hover>input:not(:disabled)+span:before,.vot-textfield:hover>input:not(:disabled)+span:after,.vot-textfield:hover>textarea:not(:disabled)+span:before,.vot-textfield:hover>textarea:not(:disabled)+span:after{border-top-color:var(--vot-helper-safari3)!important}.vot-textfield:hover>input:not(:disabled):not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:disabled):not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3)!important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:transparent 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:transparent var(--vot-helper-safari1) var(--vot-helper-safari1)!important;color:rgba(var(--vot-onsurface-rgb,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,.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:#0000!important}@media not all and (resolution>=.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-checkbox-label-offset:30px;--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;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);text-align:start;font-size:16px;line-height:1.5;display:inline-block;position:relative;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;text-transform:none!important}.vot-checkbox-sub{padding-left:var(--vot-checkbox-label-offset)!important}.vot-checkbox>input{appearance:none;z-index:10000;box-sizing:border-box;opacity:1;cursor:pointer;background:0 0;outline:none;width:18px;height:18px;transition:border-color .2s,background-color .2s;display:block;position:absolute;border:2px solid!important;border-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;border-radius:2px!important;margin:3px 1px!important;padding:0!important}.vot-checkbox>input+span{box-sizing:border-box;width:inherit;cursor:pointer;font-family:inherit;display:inline-block;position:relative;padding-left:var(--vot-checkbox-label-offset)!important;font-weight:400!important}.vot-checkbox>input+span:before{content:"";background-color:rgb(var(--vot-onsurface-rgb,0, 0, 0));opacity:0;pointer-events:none;width:40px;height:40px;transition:opacity .3s,transform .2s;display:block;position:absolute;top:-8px;left:-10px;transform:scale(1);border-radius:50%!important}.vot-checkbox>input+span:after{content:"";z-index:10000;pointer-events:none;width:10px;height:5px;transition:border-color .2s;display:block;position:absolute;top:3px;left:1px;transform:translate(3px,4px)rotate(-45deg);box-sizing:content-box!important;border:0 solid #0000!important;border-width:0 0 2px 2px!important}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{background-color:rgb(var(--vot-helper-theme));border-color:rgb(var(--vot-helper-theme))!important}.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))!important}.vot-checkbox>input:hover{box-shadow:none!important}.vot-checkbox>input:indeterminate+span:after{transform:translate(4px,3px);border-left-width:0!important}.vot-checkbox:hover>input+span:before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input:not(:disabled){border-color:rgb(var(--vot-helper-theme))!important}.vot-checkbox:active>input:checked{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6);border-color:#0000!important}.vot-checkbox:active>input+span:before{opacity:1;transition:transform,opacity;transform:scale(0)}.vot-checkbox>input:disabled{cursor:initial;border-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);border-color:#0000!important}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial}.vot-checkbox>input:disabled+span:before{opacity:0;transform:scale(0)}html.vot-keyboard-nav .vot-checkbox>input:focus-visible{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav .vot-checkbox>input:focus{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}}.vot-slider{flex-direction:column;gap:6px;display:flex;width:100%!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", BlinkMacSystemFont, system-ui, -apple-system)!important;text-align:start!important;font-size:16px!important;line-height:1.5!important}.vot-slider>span{order:1;margin:0!important;display:block!important}.vot-slider .vot-slider-label{flex-wrap:wrap;align-items:baseline;gap:6px;width:100%;display:inline-flex}.vot-slider-label-value{font-variant-numeric:tabular-nums;margin-left:0!important;font-weight:500!important}.vot-slider .vot-slider-label-text{min-width:0}.vot-slider>input{order:2;appearance:none!important;cursor:pointer!important;background-color:#0000!important;border:none!important;width:100%!important;height:32px!important;margin:0!important;padding:0!important;display:block!important;position:relative!important;top:0!important}.vot-slider>input:hover{box-shadow:none!important}.vot-slider>input:before{content:""!important;width:calc(100% * var(--vot-progress,0))!important;background:rgb(var(--vot-primary-rgb,33, 150, 243))!important;height:2px!important;display:block!important;position:absolute!important;top:calc(50% - 1px)!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), .38)!important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-slider>input:disabled::-webkit-slider-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)!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)!important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important}.vot-slider>input:focus{outline:none!important}.vot-slider>input::-webkit-slider-runnable-track{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important;border-radius:1px!important;width:100%!important;height:2px!important;margin:15px 0!important}.vot-slider>input::-moz-range-track{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important;border-radius:1px!important;width:100%!important;height:2px!important;margin:15px 0!important}.vot-slider>input::-webkit-slider-thumb{appearance:none!important;background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;width:2px!important;height:2px!important;box-shadow:none!important;border:none!important;border-radius:50%!important;transition:box-shadow .2s!important;transform:scale(6)!important}.vot-slider>input::-moz-range-thumb{appearance:none!important;background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;width:2px!important;height:2px!important;box-shadow:none!important;border:none!important;border-radius:50%!important;transition:box-shadow .2s!important;transform:scale(6)!important}.vot-slider>input::-webkit-slider-thumb{-webkit-appearance:none!important;margin:0!important}.vot-slider>input::-moz-range-progress{background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;border-radius:1px!important;height:2px!important}.vot-slider>input:focus:not(:focus-visible)::-webkit-slider-thumb{box-shadow:none!important}.vot-slider>input:focus:not(:focus-visible)::-moz-range-thumb{box-shadow:none!important}html.vot-keyboard-nav .vot-slider>input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}html.vot-keyboard-nav .vot-slider>input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav .vot-slider>input:focus::-webkit-slider-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}html.vot-keyboard-nav .vot-slider>input:focus::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}}.vot-select{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);--vot-helper-safari1:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6);--vot-helper-safari2:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme);justify-content:space-between;align-items:center;font-size:14px;line-height:1.5;display:flex;font-weight:400!important}.vot-select-outer{cursor:pointer;justify-content:space-between;align-items:center;width:120px;max-width:120px;display:flex;border:1px solid var(--vot-helper-safari1)!important;border-radius:4px!important;padding:0 5px!important;transition:border .2s!important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2)!important}.vot-select-outer[disabled=true]{opacity:.5;cursor:default}.vot-select-outer[disabled=true]:hover{border-color:var(--vot-helper-safari1)!important}.vot-select-title{text-overflow:ellipsis;white-space:nowrap;font-family:inherit;overflow:hidden}.vot-select-arrow-icon{justify-content:center;align-items:center;width:20px;height:32px;display:flex}.vot-select-arrow-icon svg{fill:inherit;stroke:inherit}.vot-select-content-list{flex-direction:column;display:flex}.vot-select-content-list .vot-select-content-item{cursor:pointer;border-radius:8px!important;padding:5px 10px!important}.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), .2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .1)!important}.vot-select-content-list .vot-select-content-item[inert]{cursor:default;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;line-height:1.5;font-weight:700!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{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;-webkit-user-select:text;user-select:text;font-size:16px;line-height:1.5;display:flex}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), .5);flex:1;margin-left:8px!important}.vot-details{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif);text-align:start;cursor:pointer;transition:background var(--vot-duration-medium) var(--vot-easing-standard);justify-content:space-between;align-items:center;font-size:16px;line-height:1.5;display:flex;border-radius:.5em!important;margin:-.5em!important;padding:.5em!important}.vot-details-arrow-icon{width:20px;height:32px;fill:rgba(var(--vot-helper-onsurface-rgb), .87);justify-content:center;align-items:center;display:flex;transform:scale(1.25)rotate(-90deg)}.vot-details:hover{background:rgba(var(--vot-onsurface-rgb,0, 0, 0), .06)}.vot-settings-section{border:1px solid var(--vot-border-color);border-radius:var(--vot-radius-l);padding:var(--vot-space-2);background:rgba(var(--vot-helper-onsurface-rgb), .03);flex-direction:column;display:flex}.vot-settings-section>*{margin:0!important}.vot-settings-section>*+*{margin-top:var(--vot-space-2)!important}.vot-settings-section-header{border-radius:var(--vot-radius-m);margin:0!important;padding:.45em .5em!important}.vot-settings-section-header .vot-details-arrow-icon{transition:transform var(--vot-duration-medium) var(--vot-easing-standard)}.vot-settings-section-header[data-open=true] .vot-details-arrow-icon{transform:scale(1.25)rotate(0)}.vot-settings-section-content{--vot-settings-control-width:200px;--vot-settings-row-gap:var(--vot-space-2);padding:0 var(--vot-space-1) var(--vot-space-1);flex-direction:column;display:flex}.vot-settings-section-content>*{margin:0!important}.vot-settings-section-content>*+*{margin-top:var(--vot-settings-row-gap)!important}.vot-settings-section-content>.vot-checkbox,.vot-settings-section-content>.vot-hotkey,.vot-settings-section-content>.vot-textfield,.vot-settings-section-content>.vot-select,.vot-settings-section-content>.vot-slider{padding:var(--vot-space-1);box-sizing:border-box;width:100%!important}.vot-settings-section-content>.vot-textfield{gap:var(--vot-space-1);flex-direction:column;padding-top:0!important;display:flex!important}.vot-settings-section-content>.vot-textfield>span{order:0;width:auto!important;max-height:none!important;color:rgba(var(--vot-helper-onsurface-rgb), .72)!important;cursor:default!important;pointer-events:none!important;font-size:13px!important;line-height:1.2!important;display:block!important;position:static!important}.vot-settings-section-content>.vot-textfield>span:before,.vot-settings-section-content>.vot-textfield>span:after{content:none!important;display:none!important}.vot-settings-section-content>.vot-textfield>input,.vot-settings-section-content>.vot-textfield>textarea{transition:border-color var(--vot-duration-fast) var(--vot-easing-standard), background-color var(--vot-duration-fast) var(--vot-easing-standard);order:1;width:100%!important;height:36px!important;padding:0 var(--vot-space-3)!important;border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-s)!important;background:rgba(var(--vot-helper-onsurface-rgb), .04)!important;color:rgba(var(--vot-helper-onsurface-rgb), .9)!important;-webkit-text-fill-color:currentColor!important;box-shadow:none!important}.vot-settings-section-content>.vot-textfield>textarea{resize:vertical;height:auto!important;min-height:84px!important;padding:var(--vot-space-2) var(--vot-space-3)!important}.vot-settings-section-content>.vot-textfield>input::placeholder,.vot-settings-section-content>.vot-textfield>textarea::placeholder{color:rgba(var(--vot-helper-onsurface-rgb), .55)!important}.vot-settings-section-content>.vot-textfield:hover>input,.vot-settings-section-content>.vot-textfield:hover>textarea{border-color:var(--vot-border-color-hover)!important}.vot-settings-section-content>.vot-textfield>input:not(:focus):placeholder-shown,.vot-settings-section-content>.vot-textfield>textarea:not(:focus):placeholder-shown{border-color:var(--vot-border-color)!important}.vot-settings-section-content>.vot-textfield>input:focus,.vot-settings-section-content>.vot-textfield>textarea:focus{border-color:rgba(var(--vot-primary-rgb), .7)!important}.vot-lang-select{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);color:var(--vot-helper-theme);fill:var(--vot-helper-theme);justify-content:space-between;align-items:center;display:flex}.vot-lang-select-icon{justify-content:center;align-items:center;width:32px;height:32px;display:flex}.vot-lang-select-icon svg{fill:inherit;stroke:inherit}.vot-segmented-button{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);-webkit-user-select:none;user-select:none;background:rgb(var(--vot-surface-rgb,255, 255, 255));max-width:100vw;height:36px;color:var(--vot-helper-theme);fill:var(--vot-helper-theme);cursor:default;transition:opacity var(--vot-duration-slow) var(--vot-easing-standard);z-index:2147483647;align-items:center;font-size:16px;line-height:1.5;display:flex;position:absolute;top:5rem;left:50%;overflow:hidden;transform:translate(-50%);opacity:1!important;pointer-events:auto!important;touch-action:none!important;border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-s)!important;box-shadow:var(--vot-shadow-1)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important}.vot-segmented-button.vot-segmented-button--hidden{opacity:0!important;pointer-events:none!important}.vot-segmented-button *{box-sizing:border-box!important}.vot-segmented-button .vot-separator{background:rgba(var(--vot-helper-theme-rgb), .1);width:1px;height:50%}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{height:100%;color:inherit;transition:background-color var(--vot-duration-fast) var(--vot-easing-standard);-webkit-tap-highlight-color:transparent;background-color:#0000;outline:none;justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden;padding:0 var(--vot-space-2)!important;border:none!important}.vot-segmented-button .vot-segment:focus,.vot-segmented-button .vot-segment-only-icon:focus{box-shadow:inset 0 0 0 2px var(--vot-focus-ring-color);outline:none}.vot-segmented-button .vot-segment:focus:not(:focus-visible),.vot-segmented-button .vot-segment-only-icon:focus:not(:focus-visible){box-shadow:none}.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:"";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-segmented-button .vot-segment:before,.vot-segmented-button .vot-segment-only-icon:before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-segmented-button .vot-segment:after,.vot-segmented-button .vot-segment-only-icon:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.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}.vot-segmented-button .vot-segment-only-icon{min-width:36px;padding:0!important}.vot-segmented-button .vot-segment-label{white-space:nowrap;color:inherit;margin-left:var(--vot-space-2)!important;font-weight:400!important}.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[data-loading=true] #vot-loading-icon{display:block!important}.vot-segmented-button[data-loading=true] #vot-translate-icon{display:none!important}.vot-segmented-button[data-direction=column]{flex-direction:column;height:fit-content}.vot-segmented-button[data-direction=column] .vot-segment-label{display:none}.vot-segmented-button[data-direction=column]>.vot-segment-only-icon,.vot-segmented-button[data-direction=column]>.vot-segment{padding:8px!important}.vot-segmented-button[data-direction=column] .vot-separator{width:50%;height:1px}.vot-segmented-button[data-position=left]{top:12.5vh;left:50px}.vot-segmented-button[data-position=right]{top:12.5vh;left:auto;right:0}.vot-segmented-button svg{width:24px;fill:inherit;stroke:inherit}.vot-tooltip{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);--vot-helper-ondialog:rgb(var(--vot-ondialog-rgb,37, 38, 40));--vot-helper-border:rgb(var(--vot-tooltip-border,69, 69, 69));-webkit-user-select:none;user-select:none;background:rgb(var(--vot-surface-rgb,255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);cursor:default;z-index:2147483647;opacity:0;align-items:center;width:max-content;max-width:calc(100vw - 10px);height:max-content;font-size:14px;line-height:1.5;transition:opacity .5s;display:flex;position:absolute;inset:0;overflow:hidden;box-shadow:0 1px 3px #0000001f;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;border-radius:4px!important;padding:4px 8px!important}.vot-tooltip[data-trigger=click]{-webkit-user-select:text;user-select:text}.vot-tooltip.vot-tooltip-bordered{border:1px solid var(--vot-helper-border)}.vot-tooltip *{box-sizing:border-box!important;font-family:inherit!important}.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), .87);--vot-settings-control-width:clamp(120px, 45%, 200px);-webkit-user-select:none;user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);cursor:default;z-index:2147483646;visibility:visible;opacity:1;transform-origin:top;width:fit-content;min-width:320px;max-width:min(90vw,560px);transition:opacity var(--vot-duration-medium) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);font-size:16px;line-height:1.5;position:absolute;top:calc(5rem + 48px);left:50%;overflow:hidden;transform:translate(-50%)scale(1);border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-m)!important;box-shadow:var(--vot-shadow-2)!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important}.vot-menu *{box-sizing:border-box!important}.vot-menu[hidden]{pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%,-4px)scale(.98);display:block!important}.vot-menu-content-wrapper{min-width:320px;min-height:100px;max-height:calc(var(--vot-container-height,75vh) - (5rem + 32px + 16px) * 2);flex-direction:column;display:flex;overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:center;min-height:31px;display:flex;padding-inline-end:var(--vot-space-2)!important}.vot-menu-header-container:empty{padding:0 0 16px!important}.vot-menu-header-container>.vot-icon-button{margin-inline-end:var(--vot-space-1)!important;margin-top:var(--vot-space-1)!important}.vot-menu-title-container{font-size:inherit;text-align:start;outline:0;flex:1;display:flex;font-weight:inherit!important;margin:0!important}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding:var(--vot-space-4)!important;font-weight:500!important}.vot-menu-body-container{box-sizing:border-box;gap:var(--vot-space-2);overscroll-behavior:contain;flex-direction:column;min-height:1.375rem;display:flex;overflow:auto;padding:0 var(--vot-space-4)!important;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), .1) var(--vot-helper-surface)!important}.vot-menu-body-container::-webkit-scrollbar{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-menu-body-container::-webkit-scrollbar-track{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-menu-body-container::-webkit-scrollbar-thumb{border-radius:1ex;background:rgba(var(--vot-helper-onsurface-rgb), .1)!important;border:5px solid var(--vot-helper-surface)!important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border-width:3px!important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface)!important}.vot-menu-footer-container{flex-shrink:0;justify-content:flex-end;display:flex;padding:var(--vot-space-4)!important}.vot-menu-footer-container:empty{padding:var(--vot-space-4) 0 0 0!important}.vot-menu .vot-select--labeled>.vot-select-outer{margin-left:auto}.vot-menu[data-position=left]{transform-origin:0;top:12.5vh;left:240px}.vot-menu[data-position=right]{transform-origin:100%;top:12.5vh;left:auto;right:-80px}.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), .87);--vot-dialog-viewport-margin:16px;--vot-dialog-max-height:75vh;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width,512px), 100%);border:1px solid var(--vot-border-color);border-radius:var(--vot-radius-l);background-color:var(--vot-helper-surface);height:fit-content;color:var(--vot-helper-onsurface);box-shadow:var(--vot-shadow-2);-webkit-user-select:none;user-select:none;visibility:visible;opacity:1;transform-origin:50%;transition:opacity var(--vot-duration-medium) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);font-size:16px;line-height:1.5;display:block;position:fixed;inset-block:0;inset-inline:0;overflow:auto hidden;transform:scale(1);font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;margin:auto!important;padding:0!important}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transition:opacity var(--vot-duration-fast) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);transform:translateY(-4px)scale(.98)}.vot-dialog[data-vertical-align=top]{inset-block-start:var(--vot-dialog-viewport-margin);inset-block-end:auto;margin:0 auto!important}.vot-dialog-container{visibility:visible;z-index:2147483647;position:absolute}.vot-dialog-container[hidden]{pointer-events:none;visibility:hidden;display:block!important}.vot-dialog-container *{box-sizing:border-box!important}.vot-dialog-backdrop{opacity:1;background-color:#0009;transition:opacity .3s;position:fixed;inset:0}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog-content-wrapper{max-height:var(--vot-dialog-max-height,75vh);flex-direction:column;display:flex;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;min-height:31px;display:flex}.vot-dialog-header-container:empty{padding:0 0 20px}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:var(--vot-space-1)!important;margin-top:var(--vot-space-1)!important}.vot-dialog-title-container{font-size:inherit;outline:0;flex:1;display:flex;font-weight:inherit!important;margin:0!important}.vot-dialog-title{flex:1;font-size:115.385%;line-height:1;padding:var(--vot-space-5) var(--vot-space-5) var(--vot-space-4)!important;font-weight:700!important}.vot-dialog-body-container{box-sizing:border-box;gap:var(--vot-space-4);overscroll-behavior:contain;flex-direction:column;min-height:1.375rem;display:flex;overflow:auto;padding:0 var(--vot-space-5)!important;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), .1) var(--vot-helper-surface)!important}.vot-dialog-body-container::-webkit-scrollbar{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-dialog-body-container::-webkit-scrollbar-track{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-dialog-body-container::-webkit-scrollbar-thumb{border-radius:1ex;background:rgba(var(--vot-helper-onsurface-rgb), .1)!important;border:5px solid var(--vot-helper-surface)!important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border-width:3px!important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface)!important}.vot-dialog-footer-container{justify-content:flex-end;gap:var(--vot-space-2);flex-wrap:wrap;flex-shrink:0;display:flex;padding:var(--vot-space-4)!important}.vot-dialog-footer-container:empty{padding:var(--vot-space-5) 0 0 0!important}@media (width<=480px){.vot-dialog-footer-container{flex-direction:column;align-items:stretch}.vot-dialog-footer-container>:is(.vot-button,.vot-outlined-button,.vot-text-button){white-space:normal;text-overflow:clip;text-align:center;justify-content:center;align-items:center;width:100%;height:auto;min-height:36px;padding:8px 16px;line-height:1.2;display:flex;overflow:visible}}.vot-inline-loader{aspect-ratio:5;--vot-loader-bg:no-repeat radial-gradient(farthest-side, rgba(var(--vot-onsurface-rgb,0, 0, 0), .38) 94%, transparent);background:var(--vot-loader-bg), var(--vot-loader-bg), var(--vot-loader-bg), var(--vot-loader-bg);background-size:20% 100%;height:8px;animation:.75s infinite alternate dotsSlide,1.5s infinite alternate dotsFlip}.vot-loader-progress{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));fill:none;stroke:rgb(var(--vot-helper-theme));stroke-width:2px;stroke-linecap:round;transform-origin:50%;transform:rotate(-90deg)}@keyframes dotsSlide{0%,10%{background-position:0 0,0 0,0 0,0 0}33%{background-position:0 0,33.3333% 0,33.3333% 0,33.3333% 0}66%{background-position:0 0,33.3333% 0,66.6667% 0,66.6667% 0}90%,to{background-position:0 0,33.3333% 0,66.6667% 0,100% 0}}@keyframes dotsFlip{0%,49.99%{transform:scale(1)}50%,to{transform:scale(-1)}}.vot-label{font-family:inherit;font-size:16px;line-height:1.5;display:block}.vot-label-text{display:inline}.vot-label-icon{vertical-align:text-bottom;cursor:help;justify-content:center;align-items:center;width:20px;height:20px;margin-left:4px;display:inline-flex}.vot-label-icon>svg{width:20px;height:20px;display:block}.vot-account{justify-content:space-between;align-items:center;gap:1rem;display:flex}.vot-account-container,.vot-account-wrapper,.vot-account-buttons{align-items:center;gap:1rem;display:flex}.vot-account-avatar{min-width:36px;max-width:36px;min-height:36px;max-height:36px;overflow:hidden}.vot-account-avatar-img{object-fit:cover;border-radius:50%;width:36px;height:36px}@property --vot-subtitles-opacity{syntax:"";inherits:true;initial-value:.8}@property --vot-subtitles-scale-compensation{syntax:"";inherits:true;initial-value:1}.vot-subtitles{--vot-subtitles-background:rgba(var(--vot-surface-rgb,46, 47, 52), var(--vot-subtitles-opacity,.8));--vot-subtitles-effective-max-width:var(--vot-subtitles-max-width,var(--vot-subtitles-smart-max-width,70vw));max-width:var(--vot-subtitles-effective-max-width);max-inline-size:var(--vot-subtitles-effective-max-width);background:var(--vot-subtitles-background,#2e2f34cc);width:max-content;inline-size:max-content;color:var(--vot-subtitles-color,#e3e3e3);pointer-events:all;touch-action:none;font-size:calc(var(--vot-subtitles-font-size,clamp(18px, var(--vot-subtitles-smart-font-preferred,2.2vw), 50px)) * var(--vot-subtitles-scale-compensation,1));-webkit-text-stroke:var(--vot-subtitles-text-stroke-width,clamp(1px, .08em, 2px)) var(--vot-subtitles-text-stroke-color,#000000eb);paint-order:stroke fill;text-shadow:var(--vot-subtitles-text-shadow,0 1px 2px #00000073, 0 2px 8px #00000040);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-synthesis:none;position:relative;--vot-subtitles-font-family:var(--vot-subtitles-font-family-custom,var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif))!important;font-family:var(--vot-subtitles-font-family)!important;font-style:normal!important;font-weight:var(--vot-subtitles-font-weight,500)!important;text-transform:none!important;letter-spacing:normal!important;border-radius:.5em!important;padding:.5em .75em!important;line-height:1.25!important}.vot-subtitles,.vot-subtitles *{-webkit-text-stroke:inherit;paint-order:inherit;font-family:var(--vot-subtitles-font-family)!important}.vot-subtitles{box-sizing:border-box;-webkit-user-select:none;user-select:none;contain:layout paint;isolation:isolate;text-align:center;text-wrap:balance;white-space:normal;overflow-wrap:anywhere;unicode-bidi:plaintext;margin:0 auto;display:block}.vot-subtitles-widget{--vot-subtitles-anchor-width:100vw;--vot-subtitles-anchor-height:100vh;--vot-subtitles-effective-max-width:var(--vot-subtitles-max-width,var(--vot-subtitles-smart-max-width,70vw));--vot-subtitles-smart-target-width:48ch;--vot-subtitles-smart-min-width-ratio:.62;--vot-subtitles-smart-max-width-ratio:.78;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0333);--vot-subtitles-smart-max-width:clamp(calc(var(--vot-subtitles-anchor-width) * var(--vot-subtitles-smart-min-width-ratio)), var(--vot-subtitles-smart-target-width), calc(var(--vot-subtitles-anchor-width) * var(--vot-subtitles-smart-max-width-ratio)));box-sizing:border-box;z-index:2147483647;--vot-subtitles-fallback-bottom-inset:calc(env(safe-area-inset-bottom,0px) + clamp(56px, 10vh, 220px) + 10px);left:50%;top:calc(100% - var(--vot-subtitles-fallback-bottom-inset));width:max-content;inline-size:max-content;max-width:var(--vot-subtitles-effective-max-width);max-inline-size:var(--vot-subtitles-effective-max-width);pointer-events:none;will-change:left, top, transform;max-height:100%;display:block;position:absolute;transform:translate(-50%,-100%)}.vot-subtitles-info{flex-direction:column;gap:2px;max-width:100%;display:flex;padding:6px!important}.vot-subtitles-info-service,.vot-subtitles-info-header,.vot-subtitles-info-context{overflow-wrap:anywhere;word-break:break-word;white-space:normal!important}.vot-subtitles-info-service{color:var(--vot-subtitles-context-color,#86919b);margin-bottom:8px!important;font-size:10px!important;line-height:1!important}.vot-subtitles-info-header{color:var(--vot-subtitles-header-color,#fff);margin-bottom:6px!important;font-size:20px!important;font-weight:500!important;line-height:1!important}.vot-subtitles-info-context{color:var(--vot-subtitles-context-color,#86919b);font-size:12px!important;line-height:1.2!important}.vot-subtitles span[data-vot-highlight-index].passed{color:var(--vot-subtitles-passed-color,#2196f3)}.vot-subtitles span[data-vot-token="1"]{cursor:pointer;white-space:normal;overflow-wrap:inherit;word-break:normal;position:relative;font-size:inherit!important;font-family:inherit!important;font-style:inherit!important;font-weight:inherit!important;line-height:inherit!important;text-transform:inherit!important;text-decoration:none!important}.vot-subtitles span[data-vot-token="1"]:before{content:"";z-index:-1;position:absolute;inset:2px -2px;border-radius:4px!important}.vot-subtitles span[data-vot-token="1"]:hover:before{background:var(--vot-subtitles-hover-color,#ffffff8c)}.vot-subtitles span[data-vot-token="1"].selected:before{background:var(--vot-subtitles-passed-color,#2196f3)}.vot-subtitles span[data-vot-style-italic="1"]{font-style:italic!important}.vot-subtitles span[data-vot-style-bold="1"]{font-weight:700!important}.vot-subtitles span[data-vot-style-underline="1"]{text-decoration:underline!important}.vot-subtitles span[data-vot-style-color="1"]{color:var(--vot-subtitles-inline-color)!important}.vot-subtitles-layer{pointer-events:none;z-index:2147483647;contain:layout paint;width:100vw!important;height:100vh!important;position:fixed!important;inset:0!important}.vot-subtitles-guides{pointer-events:none;z-index:2147483646;position:absolute;inset:0}.vot-subtitles-guide{background:rgba(var(--vot-primary-rgb,33, 150, 243), .7);box-shadow:0 0 0 1px rgba(var(--vot-primary-rgb,33, 150, 243), .12);opacity:0;transition:opacity .12s linear;position:absolute}.vot-subtitles-guide[data-visible=true]{opacity:1}.vot-subtitles-guide--vertical{width:2px;transform:translate(-50%)}.vot-subtitles-guide--horizontal{height:2px;transform:translateY(-50%)}@media (aspect-ratio<=1){.vot-subtitles-widget{--vot-subtitles-smart-target-width:28ch;--vot-subtitles-smart-min-width-ratio:.8;--vot-subtitles-smart-max-width-ratio:.92;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0296)}}@media (aspect-ratio>=1) and (aspect-ratio<=7/5){.vot-subtitles-widget{--vot-subtitles-smart-target-width:32ch;--vot-subtitles-smart-min-width-ratio:.55;--vot-subtitles-smart-max-width-ratio:.9;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0333)}}@media (width<=900px) and (pointer:coarse){.vot-subtitles-widget{--vot-subtitles-fallback-bottom-inset:env(safe-area-inset-bottom,0px)}}@media (prefers-contrast:more){.vot-subtitles{--vot-subtitles-background:rgba(var(--vot-surface-rgb,46, 47, 52), .92);--vot-subtitles-text-stroke-width:max(2px, .1em);--vot-subtitles-text-shadow:0 2px 10px #0000008c}}:is(:fullscreen .vot-subtitles-widget,:fullscreen .vot-subtitles-widget){--vot-subtitles-smart-max-width-ratio:.8}:is(:fullscreen .vot-subtitles,:fullscreen .vot-subtitles){font-size:calc(var(--vot-subtitles-font-size,clamp(18px, var(--vot-subtitles-smart-font-preferred,2vw), 50px)) * var(--vot-subtitles-fullscreen-scale,1) * .95 * var(--vot-subtitles-scale-compensation,1))}#vot-subtitles-info.vot-subtitles-info *{-webkit-user-select:text!important;user-select:text!important}:root{--vot-font-family:"Roboto", "Segoe UI", system-ui, sans-serif;--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-color:rgb(var(--vot-onsurface-rgb,227, 227, 227));--vot-subtitles-passed-color:rgb(var(--vot-primary-rgb,33, 150, 243));--vot-space-1:4px;--vot-space-2:8px;--vot-space-3:12px;--vot-space-4:16px;--vot-space-5:20px;--vot-space-6:24px;--vot-radius-xs:6px;--vot-radius-s:10px;--vot-radius-m:14px;--vot-radius-l:18px;--vot-border-color:rgba(var(--vot-onsurface-rgb,227, 227, 227), .14);--vot-border-color-hover:rgba(var(--vot-onsurface-rgb,227, 227, 227), .22);--vot-shadow-1:0 1px 2px #0000002e, 0 8px 24px #00000024;--vot-shadow-2:0 2px 4px #00000038, 0 12px 32px #00000038;--vot-duration-fast:.12s;--vot-duration-medium:.2s;--vot-duration-slow:.32s;--vot-easing-standard:cubic-bezier(.4, 0, .2, 1);--vot-focus-ring-color:rgba(var(--vot-primary-rgb,139, 180, 245), .9);--vot-focus-ring:0 0 0 2px var(--vot-focus-ring-color);--vot-focus-ring-offset:0 0 0 4px rgba(var(--vot-surface-rgb,32, 33, 36), .9)}vot-block,vot-block *{box-sizing:border-box;-webkit-tap-highlight-color:transparent}vot-block[hidden]:not(.vot-menu):not(.vot-dialog-container),vot-block [hidden]:not(.vot-menu):not(.vot-dialog-container){display:none!important}vot-block{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;display:block;--vot-font-family:"Roboto", "Segoe UI", system-ui, sans-serif!important;font-family:var(--vot-font-family,"Roboto", "Segoe UI", system-ui, sans-serif)!important;visibility:visible!important;font-weight:400!important}vot-block *{font-weight:inherit!important}.vot-portal-local,.vot-subtitles-widget{isolation:isolate}vot-block:focus,vot-block :focus{box-shadow:none!important;outline:none!important}html.vot-keyboard-nav vot-block:focus-visible,html.vot-keyboard-nav vot-block :focus-visible{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav vot-block:focus,html.vot-keyboard-nav vot-block :focus{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}}@media (prefers-reduced-motion:reduce){.vot-portal-local *,.vot-portal *,.vot-subtitles-widget *{scroll-behavior:auto!important;transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}.vot-portal{display:inline}.vot-portal-local{z-index:2147483647;position:fixed;top:0;left:0}.vot-overlay-root{pointer-events:none}.vot-overlay-root>.vot-segmented-button,.vot-overlay-root>.vot-menu{pointer-events:auto}`),Wl;function Gl(e){return e.replace(/:root\b/g,`:host`).replace(/html\.vot-keyboard-nav/g,`:host-context(.vot-keyboard-nav)`).replace(/:fullscreen(?=\s|,)/g,`:host-context(:fullscreen)`).replace(/:-webkit-full-screen(?=\s|,)/g,`:host-context(:-webkit-full-screen)`)}function Kl(e,t){if(t)for(let[n,r]of Object.entries(t))typeof r==`string`&&e.style.setProperty(n,r)}function ql(){if(Wl!==void 0)return Wl;if(!(typeof CSSStyleSheet<`u`&&typeof CSSStyleSheet.prototype.replaceSync==`function`))return Wl=null,Wl;let e=new CSSStyleSheet;return e.replaceSync(Ul),Wl=e,Wl}function Jl(e){let t=ql();if(t){e.adoptedStyleSheets.includes(t)||(e.adoptedStyleSheets=[...e.adoptedStyleSheets,t]);return}let n=document.createElement(`style`);n.textContent=Ul,e.append(n)}function Yl({parent:e,hostTag:t=`vot-shadow-host`,rootTag:n=`vot-block`,hostClasses:r=[],rootClasses:i=[],hostStyles:a,rootStyles:o,delegatesFocus:s=!1}){let c=document.createElement(t);r.length>0&&c.classList.add(...r),Kl(c,a);let l=c.attachShadow({mode:`open`,delegatesFocus:s});Jl(l);let u=document.createElement(n);return i.length>0&&u.classList.add(...i),Kl(u,o),l.append(u),e.append(c),{host:c,root:u,shadowRoot:l}}function Xl(e,t){e&&e.host.parentElement!==t&&t.append(e.host)}function Zl(e){e?.host.remove()}function Ql(e,t){return e>=t.startMs&&e{if(e.tokens.length)return e.tokens;let t=e.text.trim();return t?[{text:t,startMs:e.startMs,durationMs:e.durationMs,isWordLike:!!t}]:[]},eu=e=>(e.text||$l(e).map(e=>e.text).join(``)).replaceAll(/\s+/gu,` `).trim(),tu=(e,t)=>{let n=e.startMs+Math.max(0,e.durationMs),r=t.startMs+Math.max(0,t.durationMs);return e.startMs{let t=[];for(let n of e){let e=eu(n.line);e&&(t.some(t=>e===eu(t.line)&&t.line.speakerId===n.line.speakerId&&tu(t.line,n.line))||t.push(n))}return t},ru=(e,t)=>{let n=0,r=t.length-1,i=-1;for(;n<=r;){let a=n+r>>1;if(t[a].startMs<=e){i=a,n=a+1;continue}r=a-1}return i},iu=(e,t,n=1/0)=>{let r=ru(e,t);if(r<0)return[];let i=Number.isFinite(n)?Math.max(0,e-Math.max(0,n)):-1/0,a=[];for(let n=r;n>=0;--n){let r=t[n];if(r.startMs{let r=iu(e,t,n);if(!r.length)return null;let i=nu(r.map(e=>({index:e,line:t[e]})));if(!i.length)return null;if(i.length===1){let[e]=i;return{line:e.line,lineKey:`${e.index}`}}let a=[],o=[],s=[],c=[],l=1/0,u=0;for(let e of i){let t=$l(e.line);if(t.length){if(a.length>0){let t=Math.max(l,e.line.startMs);a.push({text:` +`,startMs:t,durationMs:0,isWordLike:!1})}a.push(...t),o.push(e.line.text||t.map(e=>e.text).join(``)),s.push(e.line.metadata?.rawText??e.line.text),c.push(`${e.index}`),l=Math.min(l,e.line.startMs),u=Math.max(u,e.line.startMs+Math.max(0,e.line.durationMs))}}return!a.length||!c.length?null:{line:{text:o.join(` +`),startMs:l,durationMs:Math.max(0,u-l),speakerId:i[0]?.line.speakerId??`0`,tokens:a,metadata:s.length?{rawText:s.join(` +`)}:void 0},lineKey:c.join(`,`)}},ou=[`srt`,`vtt`,`ass`,`json`],su=[`default-sans`,`arial`,`helvetica`,`roboto`,`verdana`,`open-sans`,`poppins`,`lato`,`montserrat`,`barlow`],cu={"default-sans":`"Roboto", "Segoe UI", system-ui, sans-serif`,arial:`Arial, "Helvetica Neue", Helvetica, sans-serif`,helvetica:`"Helvetica Neue", Helvetica, Arial, sans-serif`,roboto:`"Roboto", "Segoe UI", system-ui, sans-serif`,verdana:`Verdana, Geneva, sans-serif`,"open-sans":`"Open Sans", "Segoe UI", system-ui, sans-serif`,poppins:`"Poppins", "Segoe UI", system-ui, sans-serif`,lato:`"Lato", "Segoe UI", system-ui, sans-serif`,montserrat:`"Montserrat", "Segoe UI", system-ui, sans-serif`,barlow:`"Barlow", "Segoe UI", system-ui, sans-serif`},lu=new Set(ou);function uu(e){return typeof e==`string`&&lu.has(e)}function du(e){return typeof e==`object`&&!!e}function fu(e){if(!du(e))return null;let t=e.format;return typeof e.source!=`string`||typeof e.language!=`string`||typeof e.url!=`string`||!uu(t)?null:{source:e.source,format:t,language:e.language,url:e.url,translatedFromLanguage:typeof e.translatedFromLanguage==`string`?e.translatedFromLanguage:void 0,isAutoGenerated:typeof e.isAutoGenerated==`boolean`?e.isAutoGenerated:void 0}}function pu(e){return su.includes(e)}var mu=`google:`,hu=`https://fonts.googleapis.com/css2`,gu=`https://fonts.google.com/metadata/fonts`,_u={roboto:`Roboto`,"open-sans":`Open Sans`,poppins:`Poppins`,lato:`Lato`,montserrat:`Montserrat`,barlow:`Barlow`},vu=new Set,yu=new Map,bu=null;function xu(e){return`${mu}${e}`}function Su(e){if(e.startsWith(mu)){let t=e.slice(7).trim();return t.length>0?t:null}return _u[e]??null}function Cu(e){if(pu(e))return cu[e];let t=Su(e);return t?`"${t}", "Segoe UI", system-ui, sans-serif`:cu[`default-sans`]}function wu(e){let t=Su(e);return t?`${hu}?family=${t.trim().replaceAll(/\s+/g,`+`)}&display=swap`:null}function Tu(e,t){let n=`vot-google-font-${e}`;if(document.getElementById(n))return;let r=globalThis.GM_addStyle,i=typeof r==`function`?r(t):document.createElement(`style`);i instanceof HTMLElement&&(i.id=n,i.textContent||=t,i.parentElement||(document.head||document.documentElement).appendChild(i))}async function Eu(e,t={}){if(vu.has(e))return;let n=yu.get(e);if(n!==void 0){await n;return}let r=wu(e);if(!r){vu.add(e);return}let i=Su(e),a=(async()=>{try{let n=await z(r,{timeout:1e4,forceGmXhr:t.forceGmXhr??!0,headers:{Accept:`text/css,*/*;q=0.1`}});if(!n.ok)throw Error(`Google Fonts CSS request failed with ${n.status}`);let a=await n.text();if(!a.trim())throw Error(`Google Fonts CSS response is empty`);Tu(e,a),vu.add(e),document.fonts&&i&&await document.fonts.load(`500 20px "${i}"`),t.onLoaded?.()}catch(t){L.log(`Failed to load Google Font for subtitles`,{fontFamily:e,error:t})}finally{yu.delete(e)}})();yu.set(e,a),await a}async function Du(){return bu===null&&(bu=(async()=>{let e=await z(gu,{timeout:15e3,forceGmXhr:La});if(!e.ok)throw Error(`Google Fonts metadata request failed with ${e.status}`);let t=(await e.text()).replace(/^\)\]\}'\n?/,``),n=JSON.parse(t).familyMetadataList?.map(e=>e.family?.trim()??``).filter(e=>e.length>0);return Array.from(new Set(n)).sort((e,t)=>e.localeCompare(t))})().catch(e=>(bu=null,L.log(`Failed to load Google Fonts catalog`,e),[]))),await bu}var Ou=class{container;constructor({container:e}){this.container=e}updateContainer(e){this.container=e}getWidgetParentElement(){return this.container}getLayoutRootElement(){return this.container}syncWidgetContainer(e){getComputedStyle(this.container).position===`static`&&(this.container.style.position=`relative`),e&&e.parentElement!==this.container&&this.container.appendChild(e)}release(){}},ku=/^[a-z]+$/iu,Au=/^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/iu,ju=/^(?:rgb|rgba|hsl|hsla)\(\s*[0-9.,%\s/+-]+\)$/iu,Mu=/^[a-z0-9_-]+$/iu,Nu=e=>{if(!e?.length)return;let t=Array.from(new Set(e.map(e=>e.trim()).filter(e=>e&&Mu.test(e)))).sort((e,t)=>e.localeCompare(t));return t.length?t:void 0},Pu=e=>{let t=e.trim();if(t){if(Au.test(t)||ku.test(t))return t.toLowerCase();if(ju.test(t))return t}},Fu=e=>{if(!e)return;let t={};e.italic&&(t.italic=!0),e.bold&&(t.bold=!0),e.underline&&(t.underline=!0);let n=typeof e.color==`string`?Pu(e.color):void 0;n&&(t.color=n);let r=Nu(e.classes);return r&&(t.classes=r),Object.keys(t).length?t:void 0},Iu=e=>{if(!e||typeof e!=`object`)return;let t=e;return Fu({italic:t.italic===!0,bold:t.bold===!0,underline:t.underline===!0,color:typeof t.color==`string`?t.color:void 0,classes:Array.isArray(t.classes)?t.classes.filter(e=>typeof e==`string`):void 0})},Lu=(e,t)=>{let n=Fu(e),r=Fu(t),i=n?.classes??[],a=r?.classes??[];return!!n?.italic==!!r?.italic&&!!n?.bold==!!r?.bold&&!!n?.underline==!!r?.underline&&(n?.color??``)===(r?.color??``)&&i.length===a.length&&i.every((e,t)=>e===a[t])},Ru=e=>{let t=Fu(e);return t?.color?`--vot-subtitles-inline-color:${t.color};`:``};function zu(e,t,n){return Math.max(t,Math.min(e,n))}function Bu(e,t,n,r,i){let a=n-e,o=r-t;return a*a+o*o>=i*i}function Vu({elementHeight:e,boxHeight:t,bottomInset:n}){let r=Math.max(0,e||0),i=Math.max(r,t-n);return{minAnchorY:r,baselineAnchorY:i,travelPx:Math.max(0,i-r)}}function Hu({anchorY:e,elementHeight:t,boxHeight:n,bottomInset:r}){let{minAnchorY:i,baselineAnchorY:a,travelPx:o}=Vu({elementHeight:t,boxHeight:n,bottomInset:r});return{offsetFromBaselinePx:zu(e,i,a)-a,travelPx:o}}function Uu({state:e,elementHeight:t,boxHeight:n,bottomInset:r}){let{minAnchorY:i,baselineAnchorY:a,travelPx:o}=Vu({elementHeight:t,boxHeight:n,bottomInset:r});if(!e||o<=0)return a;let s=Math.max(0,e.travelPx||0),c=Math.max(0,-(e.offsetFromBaselinePx||0));if(s<=0||c<=0)return a;let l=c/s*o;return zu(a-Math.min(o>=s?c:o,l),i,a)}function Wu({anchorX:e,anchorY:t,elementWidth:n,elementHeight:r,boxWidth:i,boxHeight:a,bottomInset:o}){let s=e,c=t,l=Math.max(0,a-o),u=r||0;if(n){let e=s-n/2,t=i-n;e=t>=0?zu(e,0,t):t/2,s=e+n/2}return c=zu(c,u,l),{anchorX:s,anchorY:c}}function Gu({current:e,candidates:t,thresholdPx:n}){let r=e,i=1/0;for(let n of t){let t=Math.abs(n-e);tn?{snapped:!1,value:e}:{snapped:!0,value:r}}var Ku=/^[\p{P}\p{S}]+/u,qu=/[\p{P}\p{S}]+$/u,Ju=/^[\p{P}\p{S}]+$/u,Yu=/\s+|[\p{P}\p{S}]+|[^\s\p{P}\p{S}]+/gu,Xu=(e,t,n,r={})=>{e.push({kind:`text`,text:t,style:n,highlightIndex:r.highlightIndex}),r.withBreak&&e.push({kind:`break`})},Zu=(e,t,n)=>{let r=t;for(;r<=n&&!e[r]?.isWordLike&&!e[r]?.text.trim();)r+=1;return r},Qu=(e,t,n)=>{for(let r=t;r<=n;r+=1){let t=e[r]?.text??``;if(!(!e[r]?.isWordLike||!t.trim())&&t.trimStart().replace(Ku,``).replace(qu,``))return!0}return!1},$u=(e,t,n,r,i,a)=>{let o=t[n],s=/^\s+/u.exec(o.text)?.[0]??``,c=o.text.slice(s.length);s&&Xu(e,s,o.style);let l=Ku.exec(c)?.[0]??``,u=c.slice(l.length),d=qu.exec(u)?.[0]??``,f=d?u.slice(0,u.length-d.length):u;return f?(l&&Xu(e,l,o.style,{highlightIndex:a}),e.push({kind:`word`,text:f,style:o.style,highlightIndex:a}),d&&Xu(e,d,o.style,{highlightIndex:a}),i?.has(n)?(e.push({kind:`break`}),{consumedWord:!0,nextTokenIndex:Zu(t,n+1,r)}):{consumedWord:!0,nextTokenIndex:n+1}):(c&&Xu(e,c,o.style),i?.has(n)?(e.push({kind:`break`}),{consumedWord:!1,nextTokenIndex:Zu(t,n+1,r)}):{consumedWord:!1,nextTokenIndex:n+1})},ed=(e,t,n,r,i,a,o,s,c)=>{let l=s??(Qu(n,t+1,r)?c:void 0),u=a.match(Yu)??[a];for(let t of u)Xu(e,t,i.style,{highlightIndex:Ju.test(t)?l:void 0});return o?(e.push({kind:`break`}),Zu(n,t+1,r)):t+1};function td(e,t,n){let r=[],i=0,a=null;for(let o=0;o<=t;){let s=e[o],c=s?.text??``;if(!c){o+=1;continue}if(c===` +`){r.push({kind:`break`}),o+=1;continue}if(s.isWordLike){let s=$u(r,e,o,t,n,i);o=s.nextTokenIndex,s.consumedWord&&(a=i,i+=1);continue}let l=!!n?.has(o);o=ed(r,o,e,t,s,c,l,a,i)}return r}var nd=(e,t,n)=>Math.min(n,Math.max(t,e)),rd=e=>Math.round(e),id=e=>e<.8?{widthRatio:.9,charsPerLine:27,fontHeightRatio:.03}:e<1.1?{widthRatio:.84,charsPerLine:31,fontHeightRatio:.031}:e<1.5?{widthRatio:.76,charsPerLine:36,fontHeightRatio:.033}:e<1.95?{widthRatio:.72,charsPerLine:40,fontHeightRatio:.034}:{widthRatio:.68,charsPerLine:44,fontHeightRatio:.035},ad=e=>e>=1920?{extraChars:4,widthScale:1.04}:e>=1440?{extraChars:3,widthScale:1.03}:e>=960?{extraChars:2,widthScale:1.02}:e>=640?{extraChars:1,widthScale:1.01}:{extraChars:0,widthScale:1},od=e=>Math.max(7,e*.56);function sd(e,t=null){let n=Number.isFinite(e.w)?Math.max(0,e.w):0,r=Number.isFinite(e.h)?Math.max(0,e.h):0;if(n<=0||r<=0)return{fontSizePx:t?.fontSizePx??20,maxWidthPx:t?.maxWidthPx??null};let{widthRatio:i,charsPerLine:a,fontHeightRatio:o}=id(n/r),{extraChars:s,widthScale:c}=ad(n),l=nd(r*o,16,42),u=t?.fontSizePx??l,d=od(u),f=n*Math.min(.92,i),p=n*nd(i*c,.66,.92);return{fontSizePx:u,maxWidthPx:rd(nd(nd(a+s,25,48)*d,f,p))}}var cd=/[.!?…:;][)"'\]»”]*\s*$/u,ld=/[,،、][)"'\]»”]*\s*$/u,ud=/^\s*[\p{Pe}\p{Pf},.;:!?%‰…]/u,dd=/\s*[\p{Ps}\p{Pi}¿¡([{«“"'`-]\s*$/u,fd=e=>e.replaceAll(/\s+/gu,` `).trim(),pd=e=>cd.test(e)?`strong`:ld.test(e)?`soft`:`neutral`,md=e=>ud.test(e),hd=e=>dd.test(e),gd=e=>!!(e?.isWordLike&&e.text.trim()),_d=e=>e&&Number.isFinite(e.startMs)?e.startMs:0,vd=e=>e?_d(e)+Math.max(0,e.durationMs):0,yd=(e,t,n)=>{for(let r=t;r{for(let r=n-1;r>=t;--r){let t=e[r];if(gd(t))return vd(t)}return vd(e[n-1])},xd=(e,t)=>{let n=e[t],r=_d(n);return{text:` +`,tokenIndex:t,breakAfterTokenIndex:t,startToken:t,endToken:t+1,charLength:0,startMs:r,endMs:r,boundary:`strong`,forcesLineBreak:!0}},Sd=(e,t)=>{let n=t;for(;n>0&&e[n-1]?.text!==` +`&&!gd(e[n-1]);)--n;let r=t+1;for(;re.text).join(``);return{text:i,tokenIndex:t,breakAfterTokenIndex:r-1,startToken:n,endToken:r,charLength:fd(i).length,startMs:yd(e,n,r),endMs:bd(e,n,r),boundary:pd(i),forcesLineBreak:!1}};function Cd(e){let t=[],n=[],r=0;for(;re.text).join(``);t.push({text:r,tokenIndex:0,breakAfterTokenIndex:e.length-1,startToken:0,endToken:e.length,charLength:fd(r).length,startMs:yd(e,0,e.length),endMs:bd(e,0,e.length),boundary:pd(r),forcesLineBreak:!1}),n.push(fd(r))}return{slices:t,key:n.join(`|`)}}function wd(e,t){return e.map(e=>({...e,width:e.forcesLineBreak?0:t(e.text)}))}var Td=(e,t)=>t<=0?0:vd(e[t-1]),Ed=(e,t,n,r)=>{if(r<=n)return;let i=yd(t,n,r),a=Td(t,r);e.push({startToken:n,endToken:r,startMs:i,endMs:Math.max(i,a)})};function Dd(e,t,n,r){if(!t.length||!e.length)return[];let i=Math.max(1,n),a=Math.max(1,r),o=[],s=t[0].startToken,c=0,l=0,u=1,d=s;for(let n of t){if(n.forcesLineBreak){if(u+=1,l=0,d=n.endToken,u>2){let t=Math.max(n.startToken,n.tokenIndex);Ed(o,e,s,t),s=t,c=0,d=s}continue}let t=c+n.charLength;if((l===0||l+n.width<=i)&&t<=a){l+=n.width,c=t,d=n.endToken;continue}if(u===1){u=2,l=n.width,c=t,d=n.endToken;continue}let r=Math.max(n.startToken,n.tokenIndex);Ed(o,e,s,r),s=r,c=n.charLength,l=n.width,u=1,d=n.endToken}if(Ed(o,e,s,d),!o.length)return[{startToken:0,endToken:e.length,startMs:yd(e,0,e.length),endMs:bd(e,0,e.length)}];for(let e=0;et.startMs&&(t.endMs=n.startMs)}let f=o.at(-1);return f&&(f.endMs=Math.max(f.endMs,bd(e,f.startToken,f.endToken))),o.filter(e=>e.endToken>e.startToken)}var Od=(e,t,n,r)=>n<=t?0:r(e.slice(t,n).map(e=>e.text).join(``)),kd=(e,t)=>{let n=t;for(;n+1{let r=null,i=1/0;for(let a=0;a=e.length-1)continue;let l=c+1,u=l,d=Od(e,0,l,t),f=Od(e,u,e.length,t),p=e.slice(0,l).map(e=>e.text).join(``),m=e.slice(u).map(e=>e.text).join(``),h=Math.max(0,d-n)*12+Math.max(0,f-n)*12+Math.abs(f-d)*.4+(md(m)?260:0)+(hd(p)?70:0);h{let c=Math.max(0,e-o)*12+Math.max(0,t-o)*12,l=Math.abs(t/Math.max(e,1)-1.08)*120,u=i<2?80:0,d=a<2?80:0,f=md(r)?260:0,p=hd(n)?70:0,m=s===`strong`?-28:s===`soft`?-14:0;return c+l+u+d+f+p+m};function Md(e,t,n){if(!e.length||e.reduce((e,t)=>e+Number(t.text===` +`),0)>0)return{breakAfterTokenIndices:[]};let{slices:r}=Cd(e),i=r.filter(e=>!e.forcesLineBreak);if(!i.length||Od(e,0,e.length,t)<=n)return{breakAfterTokenIndices:[]};let a=null,o=1/0;for(let r=0;re.text).join(``),secondText:e.slice(d).map(e=>e.text).join(``),firstWordCount:r+1,secondWordCount:i.length-(r+1),maxWidthPx:n,boundary:s.boundary});fthis.onPointerDown(e),this.onPointerUpBound=e=>this.onPointerUp(e),this.onPointerMoveBound=e=>this.onPointerMove(e),this.onPlaybackStateChangeBound=()=>this.handlePlaybackStateChange(),this.onVisualViewportChangeBound=()=>this.scheduleReposition(),this.checkerUnsubscribe=this.intervalIdleChecker.subscribe(()=>{this.onCheckerTick()}),this.bindEvents()}updateMount({container:e}){let t=this.container!==e;if(this.container=e,this.fullscreenLayerController.updateContainer(e),this.syncWidgetMount(),t){let e=this.getTokenTooltipParentElement();this.tokenTooltip?.updateMount({parentElement:e,layoutRoot:this.tooltipMount?.host})}this.subtitles&&(this.insetCacheReady=!1,this.lastAppliedLeftPct=null,this.lastAppliedTopPct=null,this.updateContainerRect(),this.requestUpdate())}resetTranslationContext(e=!1){this.strTranslatedTokens=``,e&&this.releaseTooltip()}resetSegmentationMemo(){this.tokenProcessingMemo=null,this.tokenPrecomputeMemo=null,this.lineMeasureMemo=null,this.lastSegmentIndex=0}resetWrapMemo(){this.setBreakAfterTokenIndices([]),this.lastWrapKey=null}resetRenderMemo(){this.lastRenderKey=null}computeAnchorBoxLayout(e){let t={left:0,top:0,w:e.w,h:e.h},n=this.video;if(!n)return t;let r=n.getBoundingClientRect();if(!(r.width>0&&r.height>0))return t;let i=e.rect;if(!(r.right>i.left&&r.lefti.top&&r.top0&&o>0))return t;let s=(r.left-i.left)/e.scaleX,c=(r.top-i.top)/e.scaleY,l=e.w-a,u=e.h-o;return{left:l>=0?zu(s,0,l):(e.w-a)/2,top:u>=0?zu(c,0,u):(e.h-o)/2,w:a,h:o}}readSmartCssMetrics(){let e=this.subtitlesBlock;if(!e)return null;let t=getComputedStyle(e),n=Number.parseFloat(t.fontSize),r=Number.parseFloat(t.maxWidth);if(!Number.isFinite(n)||!Number.isFinite(r)||n<=0||r<=0)return null;this.subtitleMaxWidthPx=r;let i=Number.parseFloat(t.paddingLeft)||0,a=Number.parseFloat(t.paddingRight)||0,o=Math.max(0,r-i-a);return o<=0?null:{fontSizePx:n,maxWidthPx:o}}ensureSmartLayout(e){if(!this.smartLayoutEnabled)return null;let t=this.readSmartCssMetrics(),n=t?.fontSizePx??this.smartFontSizePx,r=sd(e,t),i=r.maxWidthPx??this.smartMaxWidthPx,a=`${Math.round(n)}|${Math.round(i)}|${Math.round(r.maxWidthPx??0)}`,o=Math.abs(n-this.smartFontSizePx)>.5,s=Math.abs(i-this.smartMaxWidthPx)>.5;return a!==this.lastSmartLayoutKey&&(this.lastSmartLayoutKey=a,this.smartFontSizePx=n,this.smartMaxWidthPx=i,this.resetRenderMemo()),this.setSubtitlesContainerVar(`--vot-subtitles-max-width`,r.maxWidthPx&&r.maxWidthPx>0?`${r.maxWidthPx}px`:null),(o||s)&&this.lastWrapTokens&&(this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute()),r}scheduleReposition(){this.abortController.signal.aborted||this.subtitles&&(this.repositionPending=!0,this.intervalIdleChecker.markActivity(`subtitles-reposition`),this.intervalIdleChecker.requestImmediateTick())}setSubtitlesContainerVar(e,t){let n=this.subtitlesContainer;if(n){if(t===null){n.style.removeProperty(e);return}n.style.setProperty(e,t)}}applyOpacityStyle(){this.setSubtitlesContainerVar(`--vot-subtitles-opacity`,this.opacity)}applyManualFontSizeStyle(){if(!this.smartLayoutEnabled&&this.fontSizeOverridden){this.setSubtitlesContainerVar(`--vot-subtitles-font-size`,`${this.fontSize}px`);return}this.setSubtitlesContainerVar(`--vot-subtitles-font-size`,null)}applyFontFamilyStyle(){let e=this.fontFamily;this.setSubtitlesContainerVar(`--vot-subtitles-font-family-custom`,Cu(e)),Eu(e,{forceGmXhr:!0,onLoaded:()=>{this.fontFamily===e&&(this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute(),this.scheduleReposition())}})}syncVisualStyleVars(){this.applyOpacityStyle(),this.applyManualFontSizeStyle(),this.applyFontFamilyStyle()}ensureGuidesLayer(){if(this.guidesLayer)return this.guidesLayer;let e=document.createElement(`vot-block`);e.classList.add(`vot-subtitles-guides`);let t=document.createElement(`vot-block`);t.classList.add(`vot-subtitles-guide`,`vot-subtitles-guide--vertical`);let n=document.createElement(`vot-block`);return n.classList.add(`vot-subtitles-guide`,`vot-subtitles-guide--horizontal`),e.append(t,n),this.guidesLayer=e,this.verticalGuide=t,this.horizontalGuide=n,this.hideSnapGuides(),e}hideSnapGuides(){this.verticalGuide?.removeAttribute(`data-visible`),this.horizontalGuide?.removeAttribute(`data-visible`)}updateSnapGuides(e,t){let{showVerticalCenter:n=!1,showHorizontalCenter:r=!1}=t;this.ensureGuidesLayer().isConnected||this.syncGuideLayerMount(),this.verticalGuide&&(this.verticalGuide.style.left=`${e.left+e.w/2}px`,this.verticalGuide.style.top=`${e.top}px`,this.verticalGuide.style.height=`${e.h}px`,n?this.verticalGuide.dataset.visible=`true`:delete this.verticalGuide.dataset.visible),this.horizontalGuide&&(this.horizontalGuide.style.left=`${e.left}px`,this.horizontalGuide.style.top=`${e.top+e.h/2}px`,this.horizontalGuide.style.width=`${e.w}px`,r?this.horizontalGuide.dataset.visible=`true`:delete this.horizontalGuide.dataset.visible)}syncGuideLayerMount(){let e=this.ensureGuidesLayer();e.parentElement!==this.container&&this.container.appendChild(e)}syncWidgetMount(){this.fullscreenLayerController.syncWidgetContainer(null),this.subtitlesContainer&&this.subtitlesContainer.parentElement!==this.container&&this.container.appendChild(this.subtitlesContainer),this.tooltipMount&&Xl(this.tooltipMount,this.container),this.syncGuideLayerMount()}ensureTooltipMount(){return this.tooltipMount?Xl(this.tooltipMount,this.container):this.tooltipMount=Yl({parent:this.container,rootClasses:[`vot-portal-local`],hostStyles:{position:`absolute`,inset:`0`,display:`block`,"pointer-events":`none`},rootStyles:{position:`relative`,display:`block`,width:`100%`,height:`100%`,"pointer-events":`none`}}),this.tooltipMount}getTokenTooltipParentElement(){return this.ensureTooltipMount().root}createSubtitlesContainer(){if(this.subtitlesContainer)return this.subtitlesContainer;let e=document.createElement(`vot-block`);return e.classList.add(`vot-subtitles-widget`),this.subtitlesContainer=e,this.syncWidgetMount(),e.addEventListener(`pointerdown`,this.onPointerDownBound,{signal:this.abortController.signal,passive:!1,capture:!0}),this.syncVisualStyleVars(),this.insetCacheReady=!1,this.updateContainerRect(),e}bindEvents(){let{signal:e}=this.abortController,t={signal:e};this.video?.addEventListener(`play`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`pause`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`seeking`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`seeked`,this.onPlaybackStateChangeBound,t),this.video?.addEventListener(`ended`,this.onPlaybackStateChangeBound,t),this.resizeObserver=new ResizeObserver(()=>this.onResize()),this.resizeObserver.observe(this.container),this.video&&this.resizeObserver.observe(this.video),globalThis.visualViewport?.addEventListener(`resize`,this.onVisualViewportChangeBound,t),globalThis.visualViewport?.addEventListener(`scroll`,this.onVisualViewportChangeBound,t)}getUpdateMinIntervalMs(){return this.highlightWords?this.updateMinIntervalHighlightMs:this.updateMinIntervalMs}requestUpdate(e,t=performance.now()){if(this.abortController.signal.aborted||!this.subtitles)return;typeof e==`number`&&Number.isFinite(e)?this.lastPlaybackTimeMs=Math.max(0,e):this.video&&(this.lastPlaybackTimeMs=Math.max(0,this.video.currentTime*1e3));let n=this.getUpdateMinIntervalMs();t-this.lastUpdateRequestTs{if(this.videoFrameRequestId=null,this.abortController.signal.aborted)return;let n=this.video;if(!n||n.paused||n.ended||!this.subtitles)return;let r=typeof t.mediaTime==`number`&&Number.isFinite(t.mediaTime)?t.mediaTime*1e3:void 0;this.requestUpdate(r,e),this.startVideoFrameLoop()};onCheckerTick(){this.abortController.signal.aborted||(this.repositionPending&&(this.repositionPending=!1,this.updateContainerRect(),this.updatePending=!0),this.wrapPending&&(this.wrapPending=!1,this.recomputeWrapNow()),this.positionRefreshPending&&(this.positionRefreshPending=!1,this.applySubtitlePosition()),this.updatePending&&(this.updatePending=!1,this.update()))}attachDragDocumentListeners(){this.dragDocListenersAttached||(this.dragDocListenersAttached=!0,document.addEventListener(`pointermove`,this.onPointerMoveBound,{passive:!1,capture:!0}),document.addEventListener(`pointerup`,this.onPointerUpBound,!0),document.addEventListener(`pointercancel`,this.onPointerUpBound,!0))}detachDragDocumentListeners(){this.dragDocListenersAttached&&(this.dragDocListenersAttached=!1,document.removeEventListener(`pointermove`,this.onPointerMoveBound,!0),document.removeEventListener(`pointerup`,this.onPointerUpBound,!0),document.removeEventListener(`pointercancel`,this.onPointerUpBound,!0))}onResize(){this.syncWidgetMount(),this.scheduleReposition()}updateContainerRect(){let e=this.getLayoutSize();if(!e.w||!e.h)return;let t=this.computeAnchorBoxLayout(e);!t.w||!t.h||(this.refreshBottomInsetNow(e,t),this.applySubtitlePositionWithLayout(e,t))}getLayoutSize(){let e=this.fullscreenLayerController.getLayoutRootElement(),t=e.getBoundingClientRect(),n=e.clientWidth||t.width,r=e.clientHeight||t.height;return{w:n,h:r,rect:t,scaleX:t.width&&n?t.width/n:1,scaleY:t.height&&r?t.height/r:1}}ensureSafeAreaProbe(){if(this.safeAreaProbeEl)return;let e=document.createElement(`div`);e.style.position=`fixed`,e.style.left=`0`,e.style.right=`0`,e.style.bottom=`0`,e.style.height=`env(safe-area-inset-bottom, 0px)`,e.style.pointerEvents=`none`,e.style.opacity=`0`,e.style.zIndex=`-1`,document.documentElement.appendChild(e),this.safeAreaProbeEl=e}getSafeAreaBottomInsetPx(){return this.ensureSafeAreaProbe(),this.safeAreaProbeEl&&this.safeAreaProbeEl.offsetHeight||0}refreshInsetCache(){let e=this.fullscreenLayerController.getLayoutRootElement();this.safeAreaBottomInsetCachedPx=this.getSafeAreaBottomInsetPx(),this.containerPaddingBottomCachedPx=Number.parseFloat(getComputedStyle(e).paddingBottom||`0`)||0,this.insetCacheReady=!0}isMobileViewport(){return typeof globalThis.matchMedia==`function`?globalThis.matchMedia(`(max-width: 900px) and (pointer: coarse)`).matches:!1}getBottomInsetPreset(){let e=document,t=e.fullscreenElement??e.webkitFullscreenElement;if(!(t instanceof Element))return this.bottomInsetByMode.normal;let{container:n,video:r}=this;return t===n||t.contains(n)||n.contains(t)||r&&(t===r||t.contains(r)||r.contains(t))?this.bottomInsetByMode.fullscreen:this.bottomInsetByMode.normal}computeReservedBottomInsetPx(e,t=this.getBottomInsetPreset()){return zu(e*t.ratio,t.minPx,t.maxPx)}refreshBottomInsetNow(e,t){this.refreshInsetCache();let n=t?.h??this.computeAnchorBoxLayout(e??this.getLayoutSize()).h;if(!n){this.bottomInsetCachedPx=0;return}let r=this.getBottomInsetPreset();this.bottomInsetCachedPx=this.computeReservedBottomInsetPx(n,r)}getBottomInsetPx(e,t){this.insetCacheReady||this.refreshInsetCache();let n=this.getBottomInsetPreset(),r=this.safeAreaBottomInsetCachedPx,i=this.containerPaddingBottomCachedPx;if(this.isMobileViewport())return Math.max(i,r);let a=t?.h??this.computeAnchorBoxLayout(e??this.getLayoutSize()).h,o=a?this.computeReservedBottomInsetPx(a,n):n.minPx,s=Math.max(this.bottomInsetCachedPx,o);return Math.max(i,r,s)+n.gapPx}onPointerDown(e){let t=this.subtitlesContainer;if(!t)return;let n=e.target;if(!(n instanceof Node)||!t.contains(n)||!e.isPrimary||e.pointerType===`mouse`&&e.button!==0)return;e.stopPropagation();let r=this.getLayoutSize(),{rect:i,w:a,h:o,scaleX:s,scaleY:c}=r;if(!a||!o)return;let l=this.computeAnchorBoxLayout(r);if(!l.w||!l.h)return;this.lastPositionRefreshTs=performance.now();let u=t.getBoundingClientRect(),d=(e.clientX-i.left)/s-l.left,f=(e.clientY-i.top)/c-l.top,p=(u.left-i.left+u.width/2)/s-l.left,m=(u.top-i.top+u.height)/c-l.top;this.dragging.pointerId=e.pointerId,this.dragging.candidate=!0,this.dragging.active=!1,this.dragging.moved=!1,this.dragging.startClientX=e.clientX,this.dragging.startClientY=e.clientY,this.dragging.offset.x=p-d,this.dragging.offset.y=m-f,this.hideSnapGuides(),this.attachDragDocumentListeners()}onPointerUp(e){this.dragging.pointerId!==null&&e.pointerId===this.dragging.pointerId&&(this.dragging.moved&&(this.suppressTokenClicksUntil=performance.now()+450),this.dragging.pointerId=null,this.dragging.candidate=!1,this.dragging.active=!1,this.dragging.moved=!1,this.hideSnapGuides(),this.detachDragDocumentListeners())}onPointerMove(e){if(!this.dragging.candidate||this.dragging.pointerId===null||e.pointerId!==this.dragging.pointerId)return;if(this.dragging.active)this.dragging.moved=!0;else{if(!Bu(this.dragging.startClientX,this.dragging.startClientY,e.clientX,e.clientY,this.dragStartThresholdPx))return;this.dragging.active=!0,this.dragging.moved=!0,this.suppressTokenClicksUntil=performance.now()+450,this.releaseTooltip();try{this.subtitlesContainer?.setPointerCapture(e.pointerId)}catch{}}e.preventDefault(),e.stopPropagation();let t=this.getLayoutSize(),{rect:n,w:r,h:i,scaleX:a,scaleY:o}=t;if(!r||!i)return;let s=this.computeAnchorBoxLayout(t);if(!s.w||!s.h)return;let c=(e.clientX-n.left)/a-s.left,l=(e.clientY-n.top)/o-s.top,u=c+this.dragging.offset.x,d=l+this.dragging.offset.y,f=this.subtitlesContainer?.offsetWidth??0,p=this.subtitlesContainer?.offsetHeight??0,m=this.getBottomInsetPx(t,s),h=Gu({current:u,candidates:[s.w/2],thresholdPx:this.snapThresholdPx});h.snapped&&(u=h.value);let g=s.h/2+p/2,_=Gu({current:d,candidates:[g],thresholdPx:this.snapThresholdPx});_.snapped&&(d=_.value),{anchorX:u,anchorY:d}=Wu({anchorX:u,anchorY:d,elementWidth:f,elementHeight:p,boxWidth:s.w,boxHeight:s.h,bottomInset:m}),this.positionPreset=`custom`,this.customVerticalAnchorState=Hu({anchorY:d,elementHeight:p,boxHeight:s.h,bottomInset:m}),this.position.left=u/s.w*100,this.position.top=d/s.h*100,this.updateSnapGuides(s,{showVerticalCenter:h.snapped,showHorizontalCenter:_.snapped}),this.applySubtitlePositionWithLayout(t,s)}applySubtitlePosition(){if(!this.subtitlesContainer)return;let e=this.getLayoutSize();if(!e.w||!e.h)return;let t=this.computeAnchorBoxLayout(e);!t.w||!t.h||this.applySubtitlePositionWithLayout(e,t)}applySubtitlePositionWithLayout(e,t){let n=this.subtitlesContainer;if(!n)return;this.applyScaleCompensation(n,e),this.syncAnchorDimensions(n,t),this.smartLayoutEnabled&&this.ensureSmartLayout(t);let r=n.offsetWidth,i=n.offsetHeight,a=this.getBottomInsetPx(e,t),o=this.resolveCurrentAnchorPosition(t,r,i,a),s=this.clampContainerPosition(t,o.anchorX,o.anchorY,r,i,a),c=s.anchorX,l=s.anchorY,u=t.left+c,d=t.top+l,f=u/e.w*100,p=d/e.h*100;this.updateContainerPosition(n,f,p),this.tokenTooltip?.updatePos()}applyScaleCompensation(e,t){let n=Math.min(t.scaleX||1,t.scaleY||1),r=n>0&&n<.999?Math.min(1/n,3):1;if(Math.abs(r-1)<.001){e.style.removeProperty(`--vot-subtitles-scale-compensation`);return}e.style.setProperty(`--vot-subtitles-scale-compensation`,r.toFixed(3))}syncAnchorDimensions(e,t){let n=Math.max(1,Math.round(t.w)),r=Math.max(1,Math.round(t.h));(n!==this.smartAnchorWidthPx||r!==this.smartAnchorHeightPx)&&(this.smartAnchorWidthPx=n,this.smartAnchorHeightPx=r,e.style.setProperty(`--vot-subtitles-anchor-width`,`${n}px`),e.style.setProperty(`--vot-subtitles-anchor-height`,`${r}px`),this.lastWrapTokens&&(this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute()))}resolveCurrentAnchorPosition(e,t,n,r){let i=this.position.left/100*e.w,a=this.position.top/100*e.h;if(this.positionPreset===`custom`)return a=Uu({state:this.customVerticalAnchorState,elementHeight:n,boxHeight:e.h,bottomInset:r}),{anchorX:i,anchorY:a};let o=this.resolvePresetAnchorPosition({preset:this.positionPreset,anchorBox:e,elementWidth:t,elementHeight:n,bottomInset:r});return i=o.anchorX,a=o.anchorY,e.w>0&&(this.position.left=i/e.w*100),e.h>0&&(this.position.top=a/e.h*100),{anchorX:i,anchorY:a}}clampContainerPosition(e,t,n,r,i,a){let o=t-r/2,s=n-i,c=e.w-r,l=e.h-a-i;return o=c>=0?zu(o,0,c):c/2,s=l>=0?zu(s,0,l):0,{anchorX:o+r/2,anchorY:s+i}}updateContainerPosition(e,t,n){(this.lastAppliedLeftPct===null||Math.abs(t-this.lastAppliedLeftPct)>=.01)&&(e.style.left=`${t}%`,this.lastAppliedLeftPct=t),(this.lastAppliedTopPct===null||Math.abs(n-this.lastAppliedTopPct)>=.01)&&(e.style.top=`${n}%`,this.lastAppliedTopPct=n)}resolvePresetAnchorPosition({preset:e,anchorBox:t,elementWidth:n,elementHeight:r,bottomInset:i}){let a=t.w/2,o=t.h-i;switch(e){case`top-center`:o=r;break;case`center`:o=t.h/2+r/2;break;case`bottom-left`:a=n/2;break;case`bottom-right`:a=t.w-n/2;break;case`bottom-center`:case`custom`:break}return Wu({anchorX:a,anchorY:o,elementWidth:n,elementHeight:r,boxWidth:t.w,boxHeight:t.h,bottomInset:i})}applyPositionAfterContentRender(){let e=this.getLayoutSize();if(e.w&&e.h){let t=this.computeAnchorBoxLayout(e);if(t.w&&t.h){this.refreshBottomInsetNow(e,t),this.applySubtitlePositionWithLayout(e,t);return}this.refreshBottomInsetNow(e),this.applySubtitlePosition();return}this.refreshBottomInsetNow(),this.applySubtitlePosition()}trimEdgeWhitespaceTokens(e){if(!e.length)return e;let t=0,n=e.length;for(;tt&&!e[n-1]?.text.trim();)--n;return t===0&&n===e.length?e:t>=n?[]:e.slice(t,n)}selectTokensByMaxLength(e,t){if(!e.length)return e;let n=0,r=0,i=!1,a=0,o=e.length,s=!1,c=!1,l=(n,r)=>{if(r<=n||(s||=(a=n,o=r,!0),c))return;let i=e[n],l=e[r-1];if(!i||!l)return;let u=(rthis.maxLength&&t>n){i=!0,l(n,t),n=t,r=a.text.length;continue}r=e}return i?(l(n,e.length),this.trimEdgeWhitespaceTokens(e.slice(a,o))):this.trimEdgeWhitespaceTokens(e)}buildTokenPrecomputeInput(e){let t=this.tokenPrecomputeMemo;if(t?.tokens===e)return t.value;let{slices:n,key:r}=Cd(e),i={wordSlices:n,normalizedWordsKey:r};return this.tokenPrecomputeMemo={tokens:e,value:i},i}getTokenLayoutInputs(e){let t=this.subtitlesBlock;if(t){let n=getComputedStyle(t),r=`${n.fontStyle} ${n.fontVariant} ${n.fontWeight} ${n.fontSize} ${n.fontFamily}`;e.font=r;let i=Number.parseFloat(n.maxWidth),a=Number.parseFloat(n.paddingLeft)||0,o=Number.parseFloat(n.paddingRight)||0,s=Number.isFinite(i)?i:this.subtitleMaxWidthPx||globalThis.innerWidth*.8;return Number.isFinite(s)&&s>0&&(this.subtitleMaxWidthPx=s),{fontKey:r,maxWidthPx:Math.max(0,s-a-o)}}let n=Number.parseFloat(getComputedStyle(document.documentElement).fontSize)||16,r=Math.min(n*52,this.subtitleMaxWidthPx||globalThis.innerWidth*.8),i=this.fontSizeOverridden?this.fontSize:Math.min(24,Math.max(14,globalThis.innerWidth*.016)),a=`normal normal 500 ${i}px ${Cu(this.fontFamily)}`;return e.font=a,{fontKey:a,maxWidthPx:Math.max(0,r-i)}}getActiveLineKey(e){return this.lastActiveLineKey===null?`${e[0]?.startMs??0}:${e[0]?.durationMs??0}:${e.length}`:this.lastActiveLineKey}getLineMeasureMemo(e,t){let{wordSlices:n,normalizedWordsKey:r}=this.buildTokenPrecomputeInput(e);if(!n.length)return null;let i=this.getMeasureContext();if(!i)return null;let{fontKey:a,maxWidthPx:o}=this.getTokenLayoutInputs(i);if(!Number.isFinite(o)||o<24)return null;let s=`${t}|${a}|${Math.round(o)}|${r}`;if(this.lineMeasureMemo?.key===s)return this.lineMeasureMemo;let c={key:s,metrics:wd(n,e=>i.measureText(e).width),maxWidthPx:o};return this.lineMeasureMemo=c,c}buildTokenProcessingMemo(e,t){let n=this.getLineMeasureMemo(e,t);if(!n)return null;let r=`${n.key}|${this.maxLength}`;if(this.tokenProcessingMemo?.key===r)return this.tokenProcessingMemo;let i=Id(n.maxWidthPx),a={key:r,segmentRanges:Dd(e,n.metrics,i,this.maxLength)};return this.tokenProcessingMemo=a,this.lastSegmentIndex=0,a}selectSegmentIndexFromRanges(e,t){if(!e.length)return-1;let n=this.lastSegmentIndex;for(n>=e.length&&(n=0);n=e[n].endMs;)n+=1;for(;n>0&&t=e[n].startMs&&tt>=e.startMs&&t=0?r:t{if(performance.now()i[e];return r.length=i.length,r}renderTokens(e){return td(e,e.length-1,this.breakAfterTokenIndexSet).map(e=>this.renderPlanPart(e))}renderStyledSpan(e,t,n=!1,r){return!t&&!n&&r===void 0?e:wl`>>>>>> Stashed changes data-vot-token=${n?`1`:K} data-vot-highlight-index=${r??K} data-vot-style-italic=${t?.italic?`1`:`0`} data-vot-style-bold=${t?.bold?`1`:`0`} data-vot-style-underline=${t?.underline?`1`:`0`} data-vot-style-color=${t?.color?`1`:`0`} +<<<<<<< Updated upstream style=${Mu(t)} >${e}`}renderPlanPart(e){return e.kind===`break`?Tl`
`:this.renderStyledSpan(e.text,e.style,e.kind===`word`,e.highlightIndex)}updatePassedClasses(e){for(let t of this.renderedHighlightEls){let n=Number.parseInt(t.dataset.votHighlightIndex??``,10),r=Number.isInteger(n)&&n>=0&&nn.measureText(e).width,a);this.arraysEqual(s.breakAfterTokenIndices,this.breakAfterTokenIndices)||(this.setBreakAfterTokenIndices(s.breakAfterTokenIndices),this.resetRenderMemo(),this.update())}setContent(e,t=void 0){if(this.releaseTooltip(),this.subtitleLang=t,!e||!this.video){this.clearRenderedContent(),this.subtitles=null,this.maxActiveCueLookbackMs=0,this.lastPlaybackTimeMs=null,this.clearPendingSchedulerState(),this.stopVideoFrameLoop(),this.detachDragDocumentListeners();return}this.createSubtitlesContainer(),this.subtitles=e,this.maxActiveCueLookbackMs=e.subtitles.reduce((e,t)=>Math.max(e,Math.max(0,t.durationMs)),0),this.lastPlaybackTimeMs=Math.max(0,this.video.currentTime*1e3),this.lastActiveLineKey=null,this.syncVideoFrameLoop(),this.updateContainerRect(),this.update(),this.intervalIdleChecker.requestImmediateTick()}setMaxLength(e){typeof e==`number`&&e>0&&(this.maxLength=e,this.resetSegmentationMemo(),this.update(),this.scheduleReposition())}setHighlightWords(e){let t=this.highlightWords;this.highlightWords=!!e,t&&!this.highlightWords&&this.clearPassedClasses(),this.update()}setSmartLayout(e){let t=e!==!1;t!==this.smartLayoutEnabled&&(this.smartLayoutEnabled=t,this.subtitlesContainer?.style.removeProperty(`--vot-subtitles-max-width`),this.lastSmartLayoutKey=null,this.resetWrapMemo(),this.resetRenderMemo(),this.resetSegmentationMemo(),this.applyManualFontSizeStyle(),this.update(),this.scheduleWrapRecompute(),this.scheduleReposition())}setFontSize(e){this.fontSize=e,this.fontSizeOverridden=!0,this.smartLayoutEnabled||(this.applyManualFontSizeStyle(),this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute(),this.scheduleReposition())}setFontFamily(e){this.fontFamily=e,this.applyFontFamilyStyle(),this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute(),this.scheduleReposition()}setOpacity(e){let t=Number(e);this.opacity=((100-(Number.isFinite(t)?Nu(t,0,100):0))/100).toFixed(2),this.applyOpacityStyle()}stringifyTokens(e){let t=``;for(let n of e)t+=n.text;return t}resolveActiveLine(e,t){return $l(e,t,this.maxActiveCueLookbackMs)}clearInactiveLineState(){if(this.lastActiveLineKey=null,this.subtitlesBlock||this.lastRenderKey!==null||this.strTokens){this.clearRenderedContent({releaseTooltip:!0});return}this.releaseTooltip()}refreshSmartLayoutIfNeeded(){if(!this.smartLayoutEnabled)return;let e=performance.now();if(this.lastSmartLayoutKey!==null&&e-this.lastSmartLayoutCheckTs<=500)return;this.lastSmartLayoutCheckTs=e;let t=this.getLayoutSize();if(!t.w||!t.h)return;let n=this.computeAnchorBoxLayout(t);n.w&&n.h&&this.ensureSmartLayout(n)}getRenderState(e,t,n){let r=this.processTokens(e.tokens,n);this.lastWrapTokens=r;let i=this.stringifyTokens(r),a=i!==this.strTokens;a&&(this.releaseTooltip(),this.strTokens=i,this.resetTranslationContext(),this.resetWrapMemo());let o=`${t}:${i}`;return{tokens:r,tokensChanged:a,passedFlags:this.highlightWords?this.buildPassedState(r,n,o):null,renderKey:`${t}:${i}:${this.breakAfterTokenIndices.join(`,`)}`}}syncRenderedTokens(e){this.subtitlesContainer=this.subtitlesContainer??this.createSubtitlesContainer(),q(Tl`${e}
`}renderPlanPart(e){return e.kind===`break`?wl`
`:this.renderStyledSpan(e.text,e.style,e.kind===`word`,e.highlightIndex)}updatePassedClasses(e){for(let t of this.renderedHighlightEls){let n=Number.parseInt(t.dataset.votHighlightIndex??``,10),r=Number.isInteger(n)&&n>=0&&nn.measureText(e).width,a);this.arraysEqual(s.breakAfterTokenIndices,this.breakAfterTokenIndices)||(this.setBreakAfterTokenIndices(s.breakAfterTokenIndices),this.resetRenderMemo(),this.update())}setContent(e,t=void 0){if(this.releaseTooltip(),this.subtitleLang=t,!e||!this.video){this.clearRenderedContent(),this.subtitles=null,this.maxActiveCueLookbackMs=0,this.lastPlaybackTimeMs=null,this.clearPendingSchedulerState(),this.stopVideoFrameLoop(),this.detachDragDocumentListeners();return}this.createSubtitlesContainer(),this.subtitles=e,this.maxActiveCueLookbackMs=e.subtitles.reduce((e,t)=>Math.max(e,Math.max(0,t.durationMs)),0),this.lastPlaybackTimeMs=Math.max(0,this.video.currentTime*1e3),this.lastActiveLineKey=null,this.syncVideoFrameLoop(),this.updateContainerRect(),this.update(),this.intervalIdleChecker.requestImmediateTick()}setMaxLength(e){typeof e==`number`&&e>0&&(this.maxLength=e,this.resetSegmentationMemo(),this.update(),this.scheduleReposition())}setHighlightWords(e){let t=this.highlightWords;this.highlightWords=!!e,t&&!this.highlightWords&&this.clearPassedClasses(),this.update()}setSmartLayout(e){let t=e!==!1;t!==this.smartLayoutEnabled&&(this.smartLayoutEnabled=t,this.subtitlesContainer?.style.removeProperty(`--vot-subtitles-max-width`),this.lastSmartLayoutKey=null,this.resetWrapMemo(),this.resetRenderMemo(),this.resetSegmentationMemo(),this.applyManualFontSizeStyle(),this.update(),this.scheduleWrapRecompute(),this.scheduleReposition())}setFontSize(e){this.fontSize=e,this.fontSizeOverridden=!0,this.smartLayoutEnabled||(this.applyManualFontSizeStyle(),this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute(),this.scheduleReposition())}setFontFamily(e){this.fontFamily=e,this.applyFontFamilyStyle(),this.lastWrapKey=null,this.resetSegmentationMemo(),this.scheduleWrapRecompute(),this.scheduleReposition()}setOpacity(e){let t=Number(e);this.opacity=((100-(Number.isFinite(t)?zu(t,0,100):0))/100).toFixed(2),this.applyOpacityStyle()}stringifyTokens(e){let t=``;for(let n of e)t+=n.text;return t}resolveActiveLine(e,t){return au(e,t,this.maxActiveCueLookbackMs)}clearInactiveLineState(){if(this.lastActiveLineKey=null,this.subtitlesBlock||this.lastRenderKey!==null||this.strTokens){this.clearRenderedContent({releaseTooltip:!0});return}this.releaseTooltip()}refreshSmartLayoutIfNeeded(){if(!this.smartLayoutEnabled)return;let e=performance.now();if(this.lastSmartLayoutKey!==null&&e-this.lastSmartLayoutCheckTs<=500)return;this.lastSmartLayoutCheckTs=e;let t=this.getLayoutSize();if(!t.w||!t.h)return;let n=this.computeAnchorBoxLayout(t);n.w&&n.h&&this.ensureSmartLayout(n)}getRenderState(e,t,n){let r=this.processTokens(e.tokens,n);this.lastWrapTokens=r;let i=this.stringifyTokens(r),a=i!==this.strTokens;a&&(this.releaseTooltip(),this.strTokens=i,this.resetTranslationContext(),this.resetWrapMemo());let o=`${t}:${i}`;return{tokens:r,tokensChanged:a,passedFlags:this.highlightWords?this.buildPassedState(r,n,o):null,renderKey:`${t}:${i}:${this.breakAfterTokenIndices.join(`,`)}`}}syncRenderedTokens(e){this.subtitlesContainer=this.subtitlesContainer??this.createSubtitlesContainer(),q(wl`>>>>>> Stashed changes class="vot-subtitles" dir="auto" lang=${this.subtitleLang??``} @click=${this.onClick} > ${this.renderTokens(e)} +<<<<<<< Updated upstream `,this.subtitlesContainer);let t=this.subtitlesContainer.firstElementChild;this.subtitlesBlock=t instanceof HTMLElement&&t.classList.contains(`vot-subtitles`)?t:null,this.renderedHighlightEls=this.subtitlesBlock?Array.from(this.subtitlesBlock.querySelectorAll(`span[data-vot-highlight-index]`)):[]}update(){if(!this.video||!this.subtitles)return;let e=this.resolvePlaybackTimeMs(),t=this.subtitles.subtitles,n=this.resolveActiveLine(e,t);if(!n){this.clearInactiveLineState();return}this.lastActiveLineKey=n.lineKey,this.refreshSmartLayoutIfNeeded();let{tokens:r,tokensChanged:i,passedFlags:a,renderKey:o}=this.getRenderState(n.line,n.lineKey,e);if(o===this.lastRenderKey){this.highlightWords&&!i&&a&&this.updatePassedClasses(a),this.maybeRefreshPosition();return}this.lastRenderKey=o,this.syncRenderedTokens(r),this.highlightWords&&a&&this.updatePassedClasses(a),i?(this.applyPositionAfterContentRender(),this.scheduleWrapRecompute(r),this.scheduleReposition()):this.maybeRefreshPosition()}release(){this.detachDragDocumentListeners(),this.stopVideoFrameLoop(),this.abortController.abort(),this.resizeObserver?.disconnect(),this.clearPendingSchedulerState(),this.checkerUnsubscribe?.(),this.checkerUnsubscribe=null,this.releaseTooltip(),this.subtitlesContainer&&=(this.subtitlesContainer.remove(),null),this.fullscreenLayerController.release(),this.safeAreaProbeEl&&=(this.safeAreaProbeEl.remove(),null),this.guidesLayer&&(this.guidesLayer.remove(),this.guidesLayer=null,this.verticalGuide=null,this.horizontalGuide=null),this.measureCtx=null,this.measureCanvas=null,this.lastAppliedLeftPct=null,this.lastAppliedTopPct=null,this.passedStateKey=null,this.passedThresholds.length=0,this.insetCacheReady=!1}},Md=/^<\s*(\/?)\s*([a-z0-9]+)([^>]*)>/iu,Nd=/^\{([^}]*)\}/u,Pd=/^(\s*)>>\s*/u,Fd=/(\d{1,2}:\d{2}(?::\d{2})?)(?=[\p{L}\p{M}])/gu,Id=/([\p{L}\p{M}]+)(\d+)|(\d+)([\p{L}\p{M}]+)/gu,Ld=/\\[^\\]+/gu,Rd=/^\\([ibu])([01])$/u,zd=/^\\(?:1?c|c)&H([0-9a-f]{6,8})&$/iu,Bd=/^\\r(?:[^\\}]*)?$/u,Vd=e=>({italic:e.italic,bold:e.bold,underline:e.underline,color:e.color,classes:[...e.classes]}),Hd=(e,t)=>{e.italic=t.italic,e.bold=t.bold,e.underline=t.underline,e.color=t.color,e.classes=[...t.classes]},Ud=e=>{e.italic=!1,e.bold=!1,e.underline=!1,e.color=void 0,e.classes=[]},Wd=e=>ku({italic:e.italic,bold:e.bold,underline:e.underline,color:e.color,classes:e.classes}),Gd=(e,t,n)=>{if(!t)return;let r=Wd(n),i=e.at(-1);if(i&&ju(i.style,r)){i.text+=t;return}e.push({text:t,style:r})},Kd=e=>{let t=e.trim();if(!/^[0-9a-f]{6,8}$/iu.test(t))return;let n=t.slice(-6),r=n.slice(0,2),i=n.slice(2,4);return Ou(`#${n.slice(4,6)}${i}${r}`)},qd=(e,t)=>{let n=Rd.exec(e.trim());if(n){let e=n[2]===`1`;if(n[1]===`i`){t.italic=e;return}if(n[1]===`b`){t.bold=e;return}if(n[1]===`u`){t.underline=e;return}}if(Bd.test(e.trim())){Ud(t);return}let r=zd.exec(e.trim());r&&(t.color=Kd(r[1]))},Jd=(e,t)=>{let n=e.match(Ld)??[];for(let e of n)qd(e,t)},Yd=e=>{for(let t of e){if(!t.text)continue;let e=t.text.replace(Pd,`$1`);if(t.text=e,e.length>0)break}for(;e[0]?.text===``;)e.shift()},Xd=e=>{for(let t of e)t.text&&=t.text.replaceAll(Fd,`$1 `)},Zd=e=>{for(let t of e)t.text&&=t.text.replaceAll(Id,(e,t,n,r,i)=>{let a=t??i??``,o=n??r??``;return/^[A-Za-z]{1,3}$/u.test(a)||a.length===1&&a===a.toLocaleUpperCase()&&a!==a.toLocaleLowerCase()?e:t?`${a} ${o}`:`${o} ${a}`})},Qd=e=>{let t=e.trim();if(!t.startsWith(`.`))return;let n=t.split(/\s+/u,1)[0].split(`.`).filter(Boolean);return n.length?n:void 0},$d=e=>{let t=/\bcolor\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+))/iu.exec(e),n=t?.[1]??t?.[2]??t?.[3];return n?Ou(n):void 0},ef=(e,t,n)=>{for(let r=t.length-1;r>=0;--r){if(t[r].tagName!==e)continue;let[i]=t.splice(r,1);if(!i)return;Hd(n,i.previousStyle);return}if(e===`b`){n.bold=!1;return}if(e===`i`){n.italic=!1;return}if(e===`u`){n.underline=!1;return}if(e===`font`){n.color=void 0;return}e===`c`&&(n.classes=[])},tf=(e,t,n,r)=>{let i=e[1]===`/`,a=e[2].toLowerCase(),o=e[3]??``;if(a===`br`){Gd(t,` `,n);return}if(i){ef(a,r,n);return}if([`b`,`i`,`u`,`font`,`c`].includes(a)){if(r.push({tagName:a,previousStyle:Vd(n)}),a===`b`){n.bold=!0;return}if(a===`i`){n.italic=!0;return}if(a===`u`){n.underline=!0;return}if(a===`font`){let e=$d(o);e&&(n.color=e);return}n.classes=Qd(o)??[]}},nf=(e,t,n,r,i)=>{let a=e.slice(t);if(a.startsWith(`\\N`)||a.startsWith(`\\n`))return Gd(n,` `,r),t+2;if(a.startsWith(`\\h`))return Gd(n,` `,r),t+2;if(a[0]===` @@ -301,14 +332,38 @@ var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`} `),n=t[0]??``;if(!n.startsWith(`WEBVTT`))return jf();let r={headerText:n.slice(6).trim(),blocks:[]},i=[],a=1;for(;a=t.length)break;if(Mf(t[a])){let e=Nf(t,a);a=e.nextCursor,Kf(r.blocks,i.length,e.blockLines);continue}let e=Pf(t,a),n=Ff(t[e.timingCursor]??``);if(!n){a+=1;continue}let o=If(t,e.timingCursor+1);a=o.nextCursor;let s=o.payloadLines,c=s.join(` `),l=of(c),u=Tf(c);i.push({index:i.length,line:Af(i.length,{rawText:c,startMs:n.startMs,endMs:n.endMs,speakerId:u??`0`,displayModel:l,metadata:{vtt:{cueId:e.cueId,settings:wf(n.settingsRaw),voice:u,rawPayload:s}}}).line})}return{format:`vtt`,subtitles:Sf(i),metadata:{vtt:r}}},Jf=e=>{let t=bf(e),n=e.metadata?.vtt?.settings?.raw,r=n?` ${n}`:``;return`${hf(e.startMs,{delimiter:`.`,allowOptionalHours:!0,fractionDigits:3})} --> ${hf(t,{delimiter:`.`,allowOptionalHours:!0,fractionDigits:3})}${r}`},Yf=e=>{let t=e.metadata?.vtt,n=[`WEBVTT${t?.headerText?` ${t.headerText}`:``}`],r=new Map;for(let e of t?.blocks??[]){let t=r.get(e.cueIndex)??[];t.push(e.lines),r.set(e.cueIndex,t)}let i=e=>{for(let t of r.get(e)??[])n.push(t.join(` `))};return i(0),e.subtitles.forEach((t,r)=>{let a=t.metadata?.vtt?.cueId,o=[...a?[a]:[],Jf(t),(e.format===`vtt`?t.metadata?.vtt?.rawPayload:t.text.split(` +======= + `,this.subtitlesContainer);let t=this.subtitlesContainer.firstElementChild;this.subtitlesBlock=t instanceof HTMLElement&&t.classList.contains(`vot-subtitles`)?t:null,this.renderedHighlightEls=this.subtitlesBlock?Array.from(this.subtitlesBlock.querySelectorAll(`span[data-vot-highlight-index]`)):[]}update(){if(!this.video||!this.subtitles)return;let e=this.resolvePlaybackTimeMs(),t=this.subtitles.subtitles,n=this.resolveActiveLine(e,t);if(!n){this.clearInactiveLineState();return}this.lastActiveLineKey=n.lineKey,this.refreshSmartLayoutIfNeeded();let{tokens:r,tokensChanged:i,passedFlags:a,renderKey:o}=this.getRenderState(n.line,n.lineKey,e);if(o===this.lastRenderKey){this.highlightWords&&!i&&a&&this.updatePassedClasses(a),this.maybeRefreshPosition();return}this.lastRenderKey=o,this.syncRenderedTokens(r),this.highlightWords&&a&&this.updatePassedClasses(a),i?(this.applyPositionAfterContentRender(),this.scheduleWrapRecompute(r),this.scheduleReposition()):this.maybeRefreshPosition()}release(){this.detachDragDocumentListeners(),this.stopVideoFrameLoop(),this.abortController.abort(),this.resizeObserver?.disconnect(),this.clearPendingSchedulerState(),this.checkerUnsubscribe?.(),this.checkerUnsubscribe=null,this.releaseTooltip(),this.subtitlesContainer&&=(this.subtitlesContainer.remove(),null),Zl(this.tooltipMount),this.tooltipMount=void 0,this.fullscreenLayerController.release(),this.safeAreaProbeEl&&=(this.safeAreaProbeEl.remove(),null),this.guidesLayer&&(this.guidesLayer.remove(),this.guidesLayer=null,this.verticalGuide=null,this.horizontalGuide=null),this.measureCtx=null,this.measureCanvas=null,this.lastAppliedLeftPct=null,this.lastAppliedTopPct=null,this.passedStateKey=null,this.passedThresholds.length=0,this.insetCacheReady=!1}},Rd=/^<\s*(\/?)\s*([a-z0-9]+)([^>]*)>/iu,zd=/^\{([^}]*)\}/u,Bd=/^(\s*)>>\s*/u,Vd=/(\d{1,2}:\d{2}(?::\d{2})?)(?=[\p{L}\p{M}])/gu,Hd=/([\p{L}\p{M}]+)(\d+)|(\d+)([\p{L}\p{M}]+)/gu,Ud=/\\[^\\]+/gu,Wd=/^\\([ibu])([01])$/u,Gd=/^\\(?:1?c|c)&H([0-9a-f]{6,8})&$/iu,Kd=/^\\r(?:[^\\}]*)?$/u,qd=e=>({italic:e.italic,bold:e.bold,underline:e.underline,color:e.color,classes:[...e.classes]}),Jd=(e,t)=>{e.italic=t.italic,e.bold=t.bold,e.underline=t.underline,e.color=t.color,e.classes=[...t.classes]},Yd=e=>{e.italic=!1,e.bold=!1,e.underline=!1,e.color=void 0,e.classes=[]},Xd=e=>Fu({italic:e.italic,bold:e.bold,underline:e.underline,color:e.color,classes:e.classes}),Zd=(e,t,n)=>{if(!t)return;let r=Xd(n),i=e.at(-1);if(i&&Lu(i.style,r)){i.text+=t;return}e.push({text:t,style:r})},Qd=e=>{let t=e.trim();if(!/^[0-9a-f]{6,8}$/iu.test(t))return;let n=t.slice(-6),r=n.slice(0,2),i=n.slice(2,4);return Pu(`#${n.slice(4,6)}${i}${r}`)},$d=(e,t)=>{let n=Wd.exec(e.trim());if(n){let e=n[2]===`1`;if(n[1]===`i`){t.italic=e;return}if(n[1]===`b`){t.bold=e;return}if(n[1]===`u`){t.underline=e;return}}if(Kd.test(e.trim())){Yd(t);return}let r=Gd.exec(e.trim());r&&(t.color=Qd(r[1]))},ef=(e,t)=>{let n=e.match(Ud)??[];for(let e of n)$d(e,t)},tf=e=>{for(let t of e){if(!t.text)continue;let e=t.text.replace(Bd,`$1`);if(t.text=e,e.length>0)break}for(;e[0]?.text===``;)e.shift()},nf=e=>{for(let t of e)t.text&&=t.text.replaceAll(Vd,`$1 `)},rf=e=>{for(let t of e)t.text&&=t.text.replaceAll(Hd,(e,t,n,r,i)=>{let a=t??i??``,o=n??r??``;return/^[A-Za-z]{1,3}$/u.test(a)||a.length===1&&a===a.toLocaleUpperCase()&&a!==a.toLocaleLowerCase()?e:t?`${a} ${o}`:`${o} ${a}`})},af=e=>{let t=e.trim();if(!t.startsWith(`.`))return;let n=t.split(/\s+/u,1)[0].split(`.`).filter(Boolean);return n.length?n:void 0},of=e=>{let t=/\bcolor\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+))/iu.exec(e),n=t?.[1]??t?.[2]??t?.[3];return n?Pu(n):void 0},sf=(e,t,n)=>{for(let r=t.length-1;r>=0;--r){if(t[r].tagName!==e)continue;let[i]=t.splice(r,1);if(!i)return;Jd(n,i.previousStyle);return}if(e===`b`){n.bold=!1;return}if(e===`i`){n.italic=!1;return}if(e===`u`){n.underline=!1;return}if(e===`font`){n.color=void 0;return}e===`c`&&(n.classes=[])},cf=(e,t,n,r)=>{let i=e[1]===`/`,a=e[2].toLowerCase(),o=e[3]??``;if(a===`br`){Zd(t,` +`,n);return}if(i){sf(a,r,n);return}if([`b`,`i`,`u`,`font`,`c`].includes(a)){if(r.push({tagName:a,previousStyle:qd(n)}),a===`b`){n.bold=!0;return}if(a===`i`){n.italic=!0;return}if(a===`u`){n.underline=!0;return}if(a===`font`){let e=of(o);e&&(n.color=e);return}n.classes=af(o)??[]}},lf=(e,t,n,r,i)=>{let a=e.slice(t);if(a.startsWith(`\\N`)||a.startsWith(`\\n`))return Zd(n,` +`,r),t+2;if(a.startsWith(`\\h`))return Zd(n,` `,r),t+2;if(a[0]===` +`)return Zd(n,` +`,r),t+1;let o=zd.exec(a);if(o)return ef(o[1],r),t+o[0].length;let s=Rd.exec(a);return s?(cf(s,n,r,i),t+s[0].length):null},uf=e=>{let t=[],n=``;for(let r of e){if(!r.text)continue;let e=n.length;n+=r.text,t.push({start:e,end:n.length,style:r.style})}return{text:n,styledSpans:t}},df=(e,t)=>{let n=e.replaceAll(`\xA0`,` `),r=/^\s*/u.exec(n)?.[0].length??0,i=/\s*$/u.exec(n)?.[0].length??0,a=Math.max(r,n.length-i),o=n.slice(r,a);return{text:o,styledSpans:t.map(e=>({start:Math.max(0,e.start-r),end:Math.max(0,e.end-r),style:e.style})).filter(e=>e.end>e.start&&e.start({...e,end:Math.min(e.end,o.length)}))}},ff=e=>{let t=[],n={italic:!1,bold:!1,underline:!1,color:void 0,classes:[]},r=[],i=0;for(;i{if(!(!e?.length||n<=t))return e.find(e=>te.start&&e.style)?.style},mf=``,hf=/\{[^}]*\}/gu,gf=/^\s*(?\d{1,2}:\d{2}:\d{2}[,.]\d{1,3})\s*-->\s*(?\d{1,2}:\d{2}:\d{2}[,.]\d{1,3})\s*$/u,_f=/^(?(?:\d{2}:)?\d{2}:\d{2}\.\d{3})\s+-->\s+(?(?:\d{2}:)?\d{2}:\d{2}\.\d{3})(?(?:[ \t]+.+)?)$/u,vf=e=>e.replace(mf,``).replaceAll(/\r\n?/gu,` +`),yf=e=>e.length>=3?e.slice(0,3):e.padEnd(3,`0`),bf=(e,t)=>{let n=e.trim().split(`:`);if(n.length<2||n.length>3)return null;let[r,i,a]=n.length===2?[`00`,...n]:n,[o,s=`0`]=a.split(/[.,]/u);if(!/^\d+$/u.test(r)||!/^\d{2}$/u.test(i)||!/^\d{2}$/u.test(o)||!/^\d+$/u.test(s))return null;let c=Number(r),l=Number(i),u=Number(o),d=Number(yf(s).slice(0,t));return!Number.isFinite(c)||!Number.isFinite(l)||!Number.isFinite(u)||l>59||u>59?null:((c*60+l)*60+u)*1e3+d},xf=(e,{delimiter:t,allowOptionalHours:n,fractionDigits:r})=>{let{hours:i,minutes:a,seconds:o,milliseconds:s}=Sf(e,Math.round),c=s.toString().padStart(3,`0`).slice(0,r);return`${n&&i===0?``:`${i.toString().padStart(2,`0`)}:`}${a.toString().padStart(2,`0`)}:${o.toString().padStart(2,`0`)}${t}${c}`},Sf=(e,t)=>{let n=Math.max(0,t(e));return{hours:Math.floor(n/36e5),minutes:Math.floor(n%36e5/6e4),seconds:Math.floor(n%6e4/1e3),milliseconds:n%1e3}},Cf=e=>{let{hours:t,minutes:n,seconds:r,milliseconds:i}=Sf(e,Math.round),a=Math.floor(i/10);return`${t}:${n.toString().padStart(2,`0`)}:${r.toString().padStart(2,`0`)}.${a.toString().padStart(2,`0`)}`},wf=e=>{let t=/^(?\d+):(?\d{2}):(?\d{2})\.(?\d{2})$/u.exec(e.trim());if(!t?.groups)return null;let n=Number(t.groups.hours),r=Number(t.groups.minutes),i=Number(t.groups.seconds),a=Number(t.groups.centiseconds);return r>59||i>59||!Number.isFinite(n)||!Number.isFinite(a)?null:((n*60+r)*60+i)*1e3+a*10},Tf=e=>ff(e).text,Ef=e=>e.startMs+Math.max(0,e.durationMs),Df=(e,t)=>Math.max(0,t-e),Of=e=>e.sort((e,t)=>{let n=e.line.startMs-t.line.startMs;if(n!==0)return n;let r=Ef(e.line)-Ef(t.line);return r===0?e.index-t.index:r}).map(({line:e})=>e),kf=e=>{let t=0,n=e.length;for(;tt&&e[n-1]===``;)--n;return e.slice(t,n)},Af=e=>{let t=e.trim();if(!t)return;let n={};for(let e of t.split(/\s+/u)){let t=e.indexOf(`:`);t<=0||(n[e.slice(0,t)]=e.slice(t+1))}return{raw:t,values:n}},jf=e=>(/^\s*]+)?(?:\s+([^>]*?))?>/iu.exec(e)??/^\s*]*?)>/iu.exec(e))?.[1]?.trim()||void 0,Mf=(e,t)=>{let n=e[t]?.trim()??``,r=e[t+1]?.trim()??``;return gf.test(n)||/^\d+$/u.test(n)&&gf.test(r)},Nf=(e,t)=>/^\d+$/u.test(e[t]?.trim()??``)&&gf.test(e[t+1]?.trim()??``)?t+1:t,Pf=(e,t)=>{let n=gf.exec(e[t]?.trim()??``);if(!n?.groups)return null;let r=bf(n.groups.start,3),i=bf(n.groups.end,3);return r==null||i==null||i{let n=t,r=[];for(;n0&&Mf(e,n))break;r.push(e[n]),n+=1}return{rawText:kf(r).join(` +`),nextCursor:n}},If=(e,{rawText:t,startMs:n,endMs:r,speakerId:i,displayModel:a,metadata:o})=>({index:e,line:{text:a.text,startMs:n,durationMs:Df(n,r),speakerId:i,tokens:[],metadata:{rawText:t,styledSpans:a.styledSpans,...o}}}),Lf=()=>({format:`vtt`,subtitles:[],metadata:{vtt:{headerText:``,blocks:[]}}}),Rf=e=>e.startsWith(`NOTE`)||e===`STYLE`||e===`REGION`,zf=(e,t)=>{let n=[],r=t;for(;r!_f.test(e[t]??``)&&_f.test(e[t+1]??``)?{cueId:e[t],timingCursor:t+1}:{cueId:void 0,timingCursor:t},Vf=e=>{let t=_f.exec(e);if(!t?.groups)return null;let n=bf(t.groups.start,3),r=bf(t.groups.end,3);return n==null||r==null||r{let n=[],r=t;for(;re.slice(7).split(`,`).map(e=>e.trim()),Wf=(e,t)=>e.length||!t.eventFormat?e:Uf(t.eventFormat),Gf=(e,t)=>{let n=np(t,e.length);return Object.fromEntries(e.map((e,t)=>[e,n[t]??``]))},Kf=(e,t)=>{if(t.startsWith(`Format:`)){e.styleFormat=t;return}if(t.startsWith(`Style:`)){e.styleLines.push(t);return}e.preEventLines.push(t)},qf=(e,t)=>{let n=wf(t.Start??``),r=wf(t.End??``);if(n==null||r==null||r{if(t.startsWith(`Format:`))return{eventFields:Uf(t),cue:null};if(!t.includes(`:`))return e.preEventLines.push(t),{eventFields:r,cue:null};let i=t.indexOf(`:`),a=t.slice(0,i).trim(),o=t.slice(i+1).trim(),s=Wf(r,e),c=Gf(s,o);return a===`Comment`?(e.commentLines.push(t),{eventFields:s,cue:null}):a===`Dialogue`?{eventFields:s,cue:qf(n,c)}:(e.preEventLines.push(t),{eventFields:s,cue:null})},Yf=e=>{let t=vf(e).split(` +`),n=[],r=0,i=0;for(;r=t.length)break;let e=Nf(t,r),a=Pf(t,e);if(!a){r+=1;continue}let o=Ff(t,e+1);r=o.nextCursor;let s=o.rawText,c=ff(s);n.push(If(i,{rawText:s,startMs:a.startMs,endMs:a.endMs,speakerId:`0`,displayModel:c})),i+=1}return{format:`srt`,subtitles:Of(n)}},Xf=(e,t,n)=>e.format===n?t.metadata?.rawText??t.text:n===`ass`?t.text.replaceAll(` +`,`\\N`):t.text,Zf=e=>e.subtitles.map((t,n)=>{let r=Xf(e,t,`srt`),i=Ef(t);return[String(n+1),`${xf(t.startMs,{delimiter:`,`,allowOptionalHours:!1,fractionDigits:3})} --> ${xf(i,{delimiter:`,`,allowOptionalHours:!1,fractionDigits:3})}`,r].join(` +`)}).join(` + +`),Qf=(e,t,n)=>{e.push({cueIndex:t,lines:n})},$f=e=>{let t=vf(e).split(` +`),n=t[0]??``;if(!n.startsWith(`WEBVTT`))return Lf();let r={headerText:n.slice(6).trim(),blocks:[]},i=[],a=1;for(;a=t.length)break;if(Rf(t[a])){let e=zf(t,a);a=e.nextCursor,Qf(r.blocks,i.length,e.blockLines);continue}let e=Bf(t,a),n=Vf(t[e.timingCursor]??``);if(!n){a+=1;continue}let o=Hf(t,e.timingCursor+1);a=o.nextCursor;let s=o.payloadLines,c=s.join(` +`),l=ff(c),u=jf(c);i.push({index:i.length,line:If(i.length,{rawText:c,startMs:n.startMs,endMs:n.endMs,speakerId:u??`0`,displayModel:l,metadata:{vtt:{cueId:e.cueId,settings:Af(n.settingsRaw),voice:u,rawPayload:s}}}).line})}return{format:`vtt`,subtitles:Of(i),metadata:{vtt:r}}},ep=e=>{let t=Ef(e),n=e.metadata?.vtt?.settings?.raw,r=n?` ${n}`:``;return`${xf(e.startMs,{delimiter:`.`,allowOptionalHours:!0,fractionDigits:3})} --> ${xf(t,{delimiter:`.`,allowOptionalHours:!0,fractionDigits:3})}${r}`},tp=e=>{let t=e.metadata?.vtt,n=[`WEBVTT${t?.headerText?` ${t.headerText}`:``}`],r=new Map;for(let e of t?.blocks??[]){let t=r.get(e.cueIndex)??[];t.push(e.lines),r.set(e.cueIndex,t)}let i=e=>{for(let t of r.get(e)??[])n.push(t.join(` +`))};return i(0),e.subtitles.forEach((t,r)=>{let a=t.metadata?.vtt?.cueId,o=[...a?[a]:[],ep(t),(e.format===`vtt`?t.metadata?.vtt?.rawPayload:t.text.split(` +>>>>>>> Stashed changes `))?.join(` `)??t.text];n.push(o.join(` `)),i(r+1)}),n.filter(Boolean).join(` +<<<<<<< Updated upstream `)},Xf=(e,t)=>{if(t<=1)return[e];let n=[],r=0;for(let i=0;i({scriptInfoLines:[],styleFormat:``,styleLines:[],eventFormat:``,preEventLines:[],commentLines:[]}),Qf=(e=`Exported subtitles`)=>({scriptInfoLines:[`Title: ${e}`,`ScriptType: v4.00+`,`WrapStyle: 0`,`ScaledBorderAndShadow: yes`],styleFormat:`Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding`,styleLines:[`Style: Default,Arial,42,&H00FFFFFF,&H000000FF,&H00000000,&H64000000,0,0,0,0,100,100,0,0,1,2,0,2,20,20,20,1`],eventFormat:`Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text`,preEventLines:[],commentLines:[]}),$f=e=>{let t=ff(e).split(` `),n=Zf(),r=[],i=``,a=[];return t.forEach((e,t)=>{let o=e.trim();if(!o)return;let s=/^\[(.+)\]$/u.exec(o);if(s){i=s[1];return}if(i===`Script Info`){n.scriptInfoLines.push(e);return}if(i===`V4+ Styles`||i===`V4 Styles`){Bf(n,e);return}if(i===`Events`){e.startsWith(`Format:`)&&(n.eventFormat=e);let i=Hf(n,e,t,a);a=i.eventFields,i.cue&&r.push(i.cue)}}),{format:`ass`,subtitles:Sf(r),metadata:{ass:n}}},ep=e=>{let t=e.metadata?.ass,n=bf(e),r=t?.rawText??e.metadata?.rawText??e.text.replaceAll(` `,`\\N`);return[t?.kind===`comment`?`Comment`:`Dialogue`,`: `,[t?.layer??`0`,_f(e.startMs),_f(n),t?.style??`Default`,t?.name??``,t?.marginL??`0`,t?.marginR??`0`,t?.marginV??`0`,t?.effect??``,r].join(`,`)].join(``)},tp=(e,t)=>{if(!t)return e;let n=`Title: ${t}`,r=[...e.scriptInfoLines],i=r.findIndex(e=>e.startsWith(`Title:`));return i>=0?r[i]===`Title: Exported subtitles`&&(r[i]=n):r.unshift(n),{...e,scriptInfoLines:r}},np=(e,t)=>{let n=e.metadata?.ass,r=tp(n&&n.scriptInfoLines.length>0&&n.styleFormat&&n.styleLines.length>0&&n.eventFormat?n:Qf(t?.assTitle),t?.assTitle);return[`[Script Info]`,...r.scriptInfoLines,``,`[V4+ Styles]`,r.styleFormat,...r.styleLines,...r.preEventLines,``,`[Events]`,r.eventFormat,...r.commentLines,...e.subtitles.map(t=>ep({...t,metadata:e.format===`ass`?t.metadata:{...t.metadata,rawText:Wf(e,t,`ass`)}}))].join(` `).trim()},rp=(e,t)=>t===`srt`?Uf(e):t===`vtt`?qf(e):$f(e),ip=e=>({...e,subtitles:Sf(e.subtitles.map((e,t)=>({index:t,line:e})))}),ap=e=>{let t=e.subtitles.map(e=>({text:e.text,startMs:e.startMs,durationMs:e.durationMs,speakerId:e.speakerId,tokens:e.tokens.map(e=>({text:e.text,startMs:e.startMs,durationMs:e.durationMs}))}));return{containsTokens:t.some(e=>e.tokens.length>0),subtitles:t}},op=(e,t,n)=>t===`json`?ap(e):t===`srt`?Gf(e):t===`vtt`?Yf(e):np(e,n);function sp(e){return new Uint8Array([e>>>24&255,e>>>16&255,e>>>8&255,e&255])}function cp(e){return new Uint8Array([e>>>21&127,e>>>14&127,e>>>7&127,e&127])}function lp(e,t){let n=new TextEncoder().encode(t),r=new Uint8Array(n.length+1);r[0]=3,r.set(n,1);let i=new Uint8Array(10+r.length);i.set([84,73,84,50],0),i.set(sp(r.length),4),i.set(r,10);let a=new Uint8Array(10);a.set([73,68,51,3,0,0],0),a.set(cp(i.length),6);let o=new Uint8Array(e),s=new Uint8Array(a.length+i.length+o.length);return s.set(a,0),s.set(i,a.length),s.set(o,a.length+i.length),new Blob([s],{type:`audio/mpeg`})}function up(e,t,n){let r=n+t.byteLength,i=e;if(r>i.length){let e=new Uint8Array(Math.max(r,i.length*2));e.set(i.subarray(0,n)),i=e}return i.set(t,n),{out:i,loaded:r}}function dp(e,t){let n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.byteLength;return n.buffer}async function fp(e,t){let n=Number(e.headers.get(`Content-Length`)??0);if(!e.body)return e.arrayBuffer();let r=e.body.getReader(),i=0,a=n>0?new Uint8Array(n):null,o=[];for(;;){let{done:e,value:s}=await r.read();if(e)break;if(!(!s||s.byteLength===0)){if(a){let e=up(a,s,i);a=e.out,i=e.loaded}else o.push(s),i+=s.byteLength;n>0&&t(R(Math.round(i/n*100)))}}return a?a.buffer.slice(0,i):dp(o,i)}async function pp(e,t,n=()=>{},r={}){return await Yi(await mp(e,t,n),`${t}.mp3`,r)}async function mp(e,t,n=()=>{}){let r=await fp(e,n);return n(100),lp(r,t)}function hp(e,t){return e.root===t.root&&e.portalContainer===t.portalContainer&&e.subtitlesMountContainer===t.subtitlesMountContainer&&e.tooltipLayoutRoot===t.tooltipLayoutRoot}function gp(e,t,n){return hp(e,t)?e:(n(t),t)}function _p(e,t){return e.root!==t.root||e.tooltipLayoutRoot!==t.tooltipLayoutRoot}function vp(e){return e instanceof Error&&e.name===`AbortError`}async function yp(e){if(!e.videoData?.videoId||(bp(e)&&(e.videoData=await e.getVideoData()),!e.videoData?.videoId))throw new U(`VOTNoVideoIDFound`);return e.videoData}function bp(e){return e.site.host===`vk`&&e.site.additionalData===`clips`||e.site.host===`douyin`}async function xp(e){let t=e.videoHandler;if(t){if(L.log(`[handleTranslationBtnClick] click translationBtn`),t.hasActiveSource()){L.log(`[handleTranslationBtnClick] video has active source`),await t.stopTranslation();return}if(e.currentStatus===`error`&&!e.currentLoading&&e.transformBtn(`none`,V.get(`translateVideo`)),e.currentStatus!==`none`||e.currentLoading){L.log(`[handleTranslationBtnClick] translationBtn isn't in none state`),t.actionsAbortController.abort(),await t.stopTranslation();return}try{L.log(`[handleTranslationBtnClick] trying execute translation`);let e=await yp(t);await t.videoManager.ensureDetectedLanguageForTranslation(e),L.log(`[handleTranslationBtnClick] Run translateFunc`,e.videoId),await t.translateFunc(e.videoId,e.isStream,e.detectedLanguage,e.responseLanguage,e.translationHelp)}catch(t){if(vp(t)){e.transformBtn(`none`,V.get(`translateVideo`));return}if(console.error(`[VOT]`,t),!(t instanceof Error)){e.transformBtn(`error`,String(t));return}let n=t.name===`VOTLocalizedError`?t.localizedMessage:t.message;e.transformBtn(`error`,n)}}}var Sp=G` +======= +`)},np=(e,t)=>{if(t<=1)return[e];let n=[],r=0;for(let i=0;i({scriptInfoLines:[],styleFormat:``,styleLines:[],eventFormat:``,preEventLines:[],commentLines:[]}),ip=(e=`Exported subtitles`)=>({scriptInfoLines:[`Title: ${e}`,`ScriptType: v4.00+`,`WrapStyle: 0`,`ScaledBorderAndShadow: yes`],styleFormat:`Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding`,styleLines:[`Style: Default,Arial,42,&H00FFFFFF,&H000000FF,&H00000000,&H64000000,0,0,0,0,100,100,0,0,1,2,0,2,20,20,20,1`],eventFormat:`Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text`,preEventLines:[],commentLines:[]}),ap=e=>{let t=vf(e).split(` +`),n=rp(),r=[],i=``,a=[];return t.forEach((e,t)=>{let o=e.trim();if(!o)return;let s=/^\[(.+)\]$/u.exec(o);if(s){i=s[1];return}if(i===`Script Info`){n.scriptInfoLines.push(e);return}if(i===`V4+ Styles`||i===`V4 Styles`){Kf(n,e);return}if(i===`Events`){e.startsWith(`Format:`)&&(n.eventFormat=e);let i=Jf(n,e,t,a);a=i.eventFields,i.cue&&r.push(i.cue)}}),{format:`ass`,subtitles:Of(r),metadata:{ass:n}}},op=e=>{let t=e.metadata?.ass,n=Ef(e),r=t?.rawText??e.metadata?.rawText??e.text.replaceAll(` +`,`\\N`);return[t?.kind===`comment`?`Comment`:`Dialogue`,`: `,[t?.layer??`0`,Cf(e.startMs),Cf(n),t?.style??`Default`,t?.name??``,t?.marginL??`0`,t?.marginR??`0`,t?.marginV??`0`,t?.effect??``,r].join(`,`)].join(``)},sp=(e,t)=>{if(!t)return e;let n=`Title: ${t}`,r=[...e.scriptInfoLines],i=r.findIndex(e=>e.startsWith(`Title:`));return i>=0?r[i]===`Title: Exported subtitles`&&(r[i]=n):r.unshift(n),{...e,scriptInfoLines:r}},cp=(e,t)=>{let n=e.metadata?.ass,r=sp(n&&n.scriptInfoLines.length>0&&n.styleFormat&&n.styleLines.length>0&&n.eventFormat?n:ip(t?.assTitle),t?.assTitle);return[`[Script Info]`,...r.scriptInfoLines,``,`[V4+ Styles]`,r.styleFormat,...r.styleLines,...r.preEventLines,``,`[Events]`,r.eventFormat,...r.commentLines,...e.subtitles.map(t=>op({...t,metadata:e.format===`ass`?t.metadata:{...t.metadata,rawText:Xf(e,t,`ass`)}}))].join(` +`).trim()},lp=(e,t)=>t===`srt`?Yf(e):t===`vtt`?$f(e):ap(e),up=e=>({...e,subtitles:Of(e.subtitles.map((e,t)=>({index:t,line:e})))}),dp=e=>{let t=e.subtitles.map(e=>({text:e.text,startMs:e.startMs,durationMs:e.durationMs,speakerId:e.speakerId,tokens:e.tokens.map(e=>({text:e.text,startMs:e.startMs,durationMs:e.durationMs}))}));return{containsTokens:t.some(e=>e.tokens.length>0),subtitles:t}},fp=(e,t,n)=>t===`json`?dp(e):t===`srt`?Zf(e):t===`vtt`?tp(e):cp(e,n);function pp(e){return new Uint8Array([e>>>24&255,e>>>16&255,e>>>8&255,e&255])}function mp(e){return new Uint8Array([e>>>21&127,e>>>14&127,e>>>7&127,e&127])}function hp(e,t){let n=new TextEncoder().encode(t),r=new Uint8Array(n.length+1);r[0]=3,r.set(n,1);let i=new Uint8Array(10+r.length);i.set([84,73,84,50],0),i.set(pp(r.length),4),i.set(r,10);let a=new Uint8Array(10);a.set([73,68,51,3,0,0],0),a.set(mp(i.length),6);let o=new Uint8Array(e),s=new Uint8Array(a.length+i.length+o.length);return s.set(a,0),s.set(i,a.length),s.set(o,a.length+i.length),new Blob([s],{type:`audio/mpeg`})}function gp(e,t,n){let r=n+t.byteLength,i=e;if(r>i.length){let e=new Uint8Array(Math.max(r,i.length*2));e.set(i.subarray(0,n)),i=e}return i.set(t,n),{out:i,loaded:r}}function _p(e,t){let n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.byteLength;return n.buffer}async function vp(e,t){let n=Number(e.headers.get(`Content-Length`)??0);if(!e.body)return e.arrayBuffer();let r=e.body.getReader(),i=0,a=n>0?new Uint8Array(n):null,o=[];for(;;){let{done:e,value:s}=await r.read();if(e)break;if(!(!s||s.byteLength===0)){if(a){let e=gp(a,s,i);a=e.out,i=e.loaded}else o.push(s),i+=s.byteLength;n>0&&t(R(Math.round(i/n*100)))}}return a?a.buffer.slice(0,i):_p(o,i)}async function yp(e,t,n=()=>{},r={}){return await Ji(await bp(e,t,n),`${t}.mp3`,r)}async function bp(e,t,n=()=>{}){let r=await vp(e,n);return n(100),hp(r,t)}function xp(e,t){return e.root===t.root&&e.portalContainer===t.portalContainer&&e.subtitlesMountContainer===t.subtitlesMountContainer}function Sp(e,t,n){return xp(e,t)?e:(n(t),t)}function Cp(e){return e instanceof Error&&e.name===`AbortError`}async function wp(e){if(!e.videoData?.videoId||(Tp(e)&&(e.videoData=await e.getVideoData()),!e.videoData?.videoId))throw new U(`VOTNoVideoIDFound`);return e.videoData}function Tp(e){return e.site.host===`vk`&&e.site.additionalData===`clips`||e.site.host===`douyin`}async function Ep(e){let t=e.videoHandler;if(t){if(L.log(`[handleTranslationBtnClick] click translationBtn`),t.hasActiveSource()){L.log(`[handleTranslationBtnClick] video has active source`),await t.stopTranslation();return}if(e.currentStatus===`error`&&!e.currentLoading&&e.transformBtn(`none`,V.get(`translateVideo`)),e.currentStatus!==`none`||e.currentLoading){L.log(`[handleTranslationBtnClick] translationBtn isn't in none state`),t.actionsAbortController.abort(),await t.stopTranslation();return}try{L.log(`[handleTranslationBtnClick] trying execute translation`);let e=await wp(t);await t.videoManager.ensureDetectedLanguageForTranslation(e),L.log(`[handleTranslationBtnClick] Run translateFunc`,e.videoId),await t.translateFunc(e.videoId,e.isStream,e.detectedLanguage,e.responseLanguage,e.translationHelp)}catch(t){if(Cp(t)){e.transformBtn(`none`,V.get(`translateVideo`));return}if(console.error(`[VOT]`,t),!(t instanceof Error)){e.transformBtn(`error`,String(t));return}let n=t.name===`VOTLocalizedError`?t.localizedMessage:t.message;e.transformBtn(`error`,n)}}}var Dp=G` +>>>>>>> Stashed changes +<<<<<<< Updated upstream `,Cp=G` `,Np=G` +======= +`,Op=G` + +`,kp=G` + +`,Ap=G` + + +`,jp=G` + +`,Mp=G` + +`,Np=G` + +`,Pp=G` + +`,Fp=G` + +`,Ip=G` + + + +`,Lp=G` + + + +`,Rp=G` +>>>>>>> Stashed changes +<<<<<<< Updated upstream `,Pp=G` `;function Fp(e,t,n){e[t].addListener(n)}function Ip(e,t,n){e[t].removeListener(n)}function X(e,t){e.hidden=t}function Z(e){return e.hidden}var Lp=class{button;loaderMain;loaderCircle;onClick=new H;events={click:this.onClick};_progress=0;constructor(){let e=this.createElements();this.button=e.button,this.loaderMain=e.loaderMain,this.loaderCircle=e.loaderCircle,this.progress=0}createElements(){let e=J.createIconButton(Tp,{ariaLabel:`Download translation`}),t=e.querySelector(`.vot-loader-main`);if(!t)throw Error(`[VOT] DownloadButton loader main element not found`);let n=e.querySelector(`.vot-loader-progress`);if(!n)throw Error(`[VOT] DownloadButton loader circle element not found`);return e.addEventListener(`click`,()=>{this.onClick.dispatch()}),{button:e,loaderMain:t,loaderCircle:n}}addEventListener(e,t){return Fp(this.events,`click`,t),this}removeEventListener(e,t){return Ip(this.events,`click`,t),this}get progress(){return this._progress}set progress(e){let t=Rp(e);this._progress=t;let n=this.getCircleCircumference();this.loaderCircle.style.strokeDasharray=`${n}`;let r=n*(1-t/100);this.loaderCircle.style.strokeDashoffset=`${r}`,this.loaderMain.style.opacity=t===0?`1`:`0`,this.loaderCircle.style.opacity=t===0?`0`:`1`}getCircleCircumference(){let e=this.loaderCircle.r?.baseVal?.value??0;return 2*Math.PI*e}set hidden(e){X(this.button,e)}get hidden(){return Z(this.button)}};function Rp(e){if(!Number.isFinite(e))return 0;let t=e<1?e*100:e;return Math.max(0,Math.min(100,Math.round(t)))}var zp=class{container;icon;text;_labelText;_icon;constructor({labelText:e,icon:t}){this._labelText=e,this._icon=t;let n=this.createElements();this.container=n.container,this.icon=n.icon,this.text=n.text}createElements(){let e=J.createEl(`vot-block`,[`vot-label`]),t=J.createEl(`span`,[`vot-label-text`]);t.textContent=this._labelText;let n=J.createEl(`span`,[`vot-label-icon`]);return this._icon?q(this._icon,n):n.hidden=!0,e.append(t,n),{container:e,icon:n,text:t}}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},Bp=class{container;backdrop;box;contentWrapper;headerContainer;titleContainer;title;closeButton;bodyContainer;footerContainer;onClose=new H;events={close:this.onClose};previouslyFocused=null;keydownListener;adaptiveAlignObserver;adaptiveAlignRaf=null;handleViewportChange=()=>{this.scheduleAdaptiveVerticalAlign()};titleId=typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`vot-dialog-title-${Math.random().toString(36).slice(2)}`;_titleHtml;_isTemp;constructor({titleHtml:e,isTemp:t=!1}){this._titleHtml=e,this._isTemp=t;let n=this.createElements();this.container=n.container,this.backdrop=n.backdrop,this.box=n.box,this.contentWrapper=n.contentWrapper,this.headerContainer=n.headerContainer,this.titleContainer=n.titleContainer,this.title=n.title,this.closeButton=n.closeButton,this.bodyContainer=n.bodyContainer,this.footerContainer=n.footerContainer}createElements(){let e=J.createEl(`vot-block`,[`vot-dialog-container`]);this._isTemp&&e.classList.add(`vot-dialog-temp`),e.hidden=!this._isTemp,e.setAttribute(`aria-hidden`,e.hidden?`true`:`false`),e.toggleAttribute(`inert`,e.hidden);let t=J.createEl(`vot-block`,[`vot-dialog-backdrop`]),n=J.createEl(`vot-block`,[`vot-dialog`]);n.dataset.verticalAlign=`center`,n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.tabIndex=-1;let r=J.createEl(`vot-block`,[`vot-dialog-content-wrapper`]),i=J.createEl(`vot-block`,[`vot-dialog-header-container`]),a=J.createEl(`vot-block`,[`vot-dialog-title-container`]),o=J.createEl(`vot-block`,[`vot-dialog-title`]);o.id=this.titleId,o.append(this._titleHtml),a.appendChild(o),n.setAttribute(`aria-labelledby`,this.titleId);let s=J.createIconButton(Ap,{ariaLabel:`Close`});s.classList.add(`vot-dialog-close-button`),t.addEventListener(`click`,()=>{this.close()}),s.addEventListener(`click`,()=>{this.close()}),i.append(a,s);let c=J.createEl(`vot-block`,[`vot-dialog-body-container`]),l=J.createEl(`vot-block`,[`vot-dialog-footer-container`]);return r.append(i,c,l),n.appendChild(r),e.append(t,n),n.addEventListener(`click`,e=>{e.stopPropagation()}),{container:e,backdrop:t,box:n,contentWrapper:r,headerContainer:i,titleContainer:a,title:o,closeButton:s,bodyContainer:c,footerContainer:l}}addEventListener(e,t){return Fp(this.events,`close`,t),this}removeEventListener(e,t){return Ip(this.events,`close`,t),this}open(){return this.previouslyFocused??=document.activeElement,this.hidden=!1,this.attachKeydownTrap(),this.attachAdaptiveVerticalAlign(),queueMicrotask(()=>this.focusFirst()),this}remove(){return this.detachAdaptiveVerticalAlign(),this.detachKeydownTrap(),this.container.remove(),this.restoreFocus(),this.onClose.dispatch(),this}close(){return this._isTemp?this.remove():(this.detachAdaptiveVerticalAlign(),this.detachKeydownTrap(),this.hidden=!0,this.restoreFocus(),this.onClose.dispatch(),this)}attachAdaptiveVerticalAlign(){if(this.adaptiveAlignObserver){this.scheduleAdaptiveVerticalAlign();return}typeof ResizeObserver<`u`&&(this.adaptiveAlignObserver=new ResizeObserver(()=>{this.scheduleAdaptiveVerticalAlign()}),this.adaptiveAlignObserver.observe(this.contentWrapper)),globalThis.addEventListener(`resize`,this.handleViewportChange,{passive:!0}),globalThis.visualViewport&&(globalThis.visualViewport.addEventListener(`resize`,this.handleViewportChange,{passive:!0}),globalThis.visualViewport.addEventListener(`scroll`,this.handleViewportChange,{passive:!0})),this.scheduleAdaptiveVerticalAlign()}detachAdaptiveVerticalAlign(){this.adaptiveAlignObserver&&=(this.adaptiveAlignObserver.disconnect(),void 0),globalThis.removeEventListener(`resize`,this.handleViewportChange),globalThis.visualViewport?.removeEventListener(`resize`,this.handleViewportChange),globalThis.visualViewport?.removeEventListener(`scroll`,this.handleViewportChange),this.adaptiveAlignRaf!==null&&(cancelAnimationFrame(this.adaptiveAlignRaf),this.adaptiveAlignRaf=null)}scheduleAdaptiveVerticalAlign(){this.adaptiveAlignRaf!==null&&cancelAnimationFrame(this.adaptiveAlignRaf),this.adaptiveAlignRaf=requestAnimationFrame(()=>{this.adaptiveAlignRaf=null,this.updateAdaptiveVerticalAlign()})}updateAdaptiveVerticalAlign(){let e=globalThis.visualViewport?.height??globalThis.innerHeight;if(!e||e<=0)return;let t=Math.max(160,Math.round(e*.75)),n=Math.max(160,Math.round(e-32)),r=this.contentWrapper.scrollHeight,i=this.box.dataset.verticalAlign===`top`,a=t-8,o=Math.round(e*.6);(i?r>o:r>=a)?(this.box.dataset.verticalAlign=`top`,this.box.style.setProperty(`--vot-dialog-max-height`,`${n}px`)):(this.box.dataset.verticalAlign=`center`,this.box.style.setProperty(`--vot-dialog-max-height`,`${t}px`))}restoreFocus(){let e=this.previouslyFocused;this.previouslyFocused=null,e&&e instanceof HTMLElement&&document.contains(e)&&e.focus()}getFocusableElements(){return Array.from(this.container.querySelectorAll([`button:not([disabled])`,`[href]`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex='-1'])`,`[role='button']:not([aria-disabled='true'])`].join(`,`))).filter(e=>!e.hidden&&e.getClientRects().length>0)}focusFirst(){(this.getFocusableElements()[0]??this.closeButton??this.box).focus?.()}attachKeydownTrap(){this.keydownListener||(this.keydownListener=e=>{if(e.key===`Escape`){e.preventDefault(),this.close();return}if(e.key!==`Tab`)return;let t=this.getFocusableElements();if(!t.length){e.preventDefault(),this.box.focus();return}let n=t[0],r=t.at(-1)??n,i=document.activeElement;e.shiftKey?(i===n||i===this.box)&&(e.preventDefault(),r.focus()):i===r&&(e.preventDefault(),n.focus())},this.container.addEventListener(`keydown`,this.keydownListener))}detachKeydownTrap(){this.keydownListener&&=(this.container.removeEventListener(`keydown`,this.keydownListener),void 0)}set hidden(e){X(this.container,e),this.container.setAttribute(`aria-hidden`,e?`true`:`false`),this.container.toggleAttribute(`inert`,e)}get hidden(){return Z(this.container)}get isDialogOpen(){return!this.container.hidden}},Vp=class{container;input;label;onInput=new H;onChange=new H;events={input:this.onInput,change:this.onChange};_labelHtml;_multiline;_placeholder;_value;constructor({labelHtml:e=``,placeholder:t=``,value:n=``,multiline:r=!1}){this._labelHtml=e,this._multiline=r,this._placeholder=t,this._value=n;let i=this.createElements();this.container=i.container,this.input=i.input,this.label=i.label}createElements(){let e=J.createEl(`vot-block`,[`vot-textfield`]),t=document.createElement(this._multiline?`textarea`:`input`);this._labelHtml||t.classList.add(`vot-show-placeholer`,`vot-show-placeholder`),t.placeholder=this._placeholder,t.value=this._value;let n=J.createEl(`span`);return n.append(this._labelHtml),e.append(t,n),t.addEventListener(`input`,()=>{this._value=this.input.value,this.onInput.dispatch(this._value)}),t.addEventListener(`change`,()=>{this._value=this.input.value,this.onChange.dispatch(this._value)}),{container:e,label:n,input:t}}addEventListener(e,t){return Fp(this.events,e,t),this}removeEventListener(e,t){return Ip(this.events,e,t),this}get value(){return this._value}set value(e){this._value!==e&&(this.input.value=this._value=e,this.onChange.dispatch(this._value))}get placeholder(){return this._placeholder}set placeholder(e){this.input.placeholder=this._placeholder=e}get disabled(){return this.input.disabled}set disabled(e){this.input.disabled=e}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},Q=class{container;outer;arrowIcon;title;dialogParent;labelElement;_selectTitle;_dialogTitle;multiSelect;baseItems;_items;searchItemsProvider;isLoading=!1;isDialogOpen=!1;searchRequestId=0;onSelectItem=new H;onBeforeOpen=new H;events={selectItem:this.onSelectItem,beforeOpen:this.onBeforeOpen};contentList;contentItemSearchDatasetKey=`votSearchLabel`;contentItemIndexDatasetKey=`votIndex`;selectedItems=[];selectedValues;constructor({selectTitle:e,dialogTitle:t,items:n,searchItemsProvider:r,labelElement:i,dialogParent:a=document.documentElement,multiSelect:o}){this._selectTitle=e,this._dialogTitle=t,this.baseItems=this.cloneItems(n),this._items=this.cloneItems(n),this.searchItemsProvider=r,this.multiSelect=o??!1,this.labelElement=i,this.dialogParent=a,this.selectedValues=this.calcSelectedValues();let s=this.createElements();this.container=s.container,this.outer=s.outer,this.arrowIcon=s.arrowIcon,this.title=s.title}cloneItems(e){return e.map(e=>({...e}))}static genLanguageItems(e,t){return e.map(e=>{let n=`langs.${e}`,r=V.get(n);return{label:r===n?e.toUpperCase():r,value:e,selected:t===e}})}multiSelectItemHandle=e=>{let t=e.value;this.selectedValues.has(t)&&this.selectedValues.size>1?this.selectedValues.delete(t):this.selectedValues.add(t),this.syncItemsSelectionState(),this.syncItemsSelectionState(this.baseItems),this.updateSelectedState(),this.onSelectItem.dispatch(Array.from(this.selectedValues))};singleSelectItemHandle=e=>{let t=e.value;this.selectedValues=new Set([t]),this.syncItemsSelectionState(),this.syncItemsSelectionState(this.baseItems),this.updateSelectedState(),this.onSelectItem.dispatch(t)};onContentItemClick=e=>{if(!(e.target instanceof HTMLElement))return;let t=e.target.closest(`.vot-select-content-item`);if(!t||t.inert||!this.contentList?.contains(t))return;let n=t.dataset[this.contentItemIndexDatasetKey];if(!n)return;let r=this._items[Number(n)];if(r){if(this.multiSelect){this.multiSelectItemHandle(r);return}this.singleSelectItemHandle(r)}};syncItemsSelectionState(e=this._items){for(let t of e)t.selected=this.selectedValues.has(t.value)}restoreBaseItems(){this._items=this.cloneItems(this.baseItems),this.syncItemsSelectionState(),this.updateSelectedState()}createDialogContentList(){let e=J.createEl(`vot-block`,[`vot-select-content-list`]);for(let[t,n]of this._items.entries()){let r=J.createEl(`vot-block`,[`vot-select-content-item`]);r.textContent=n.label,r.dataset.votSelected=n.selected===!0?`true`:`false`,r.dataset.votValue=n.value,r.dataset[this.contentItemSearchDatasetKey]=n.label.toLowerCase(),r.dataset[this.contentItemIndexDatasetKey]=String(t),n.disabled&&(r.inert=!0),e.appendChild(r)}return e.addEventListener(`click`,this.onContentItemClick),this.selectedItems=Array.from(e.children),e}createElements(){let e=J.createEl(`vot-block`,[`vot-select`]);this.labelElement?(e.classList.add(`vot-select--labeled`),e.append(this.labelElement)):e.classList.add(`vot-select--control-only`);let t=J.createEl(`vot-block`,[`vot-select-outer`]);J.makeButtonLike(t),t.setAttribute(`aria-haspopup`,`dialog`),t.setAttribute(`aria-expanded`,`false`);let n=J.createEl(`vot-block`,[`vot-select-title`]);n.textContent=this.visibleText;let r=J.createEl(`vot-block`,[`vot-select-arrow-icon`]);return q(Op,r),t.append(n,r),t.addEventListener(`click`,()=>{if(!this.disabled&&!(this.isLoading||this.isDialogOpen))try{this.isLoading=!0;let e=new Bp({titleHtml:this._dialogTitle,isTemp:!0});this.onBeforeOpen.dispatch(e),this.dialogParent.appendChild(e.container),this.isDialogOpen=!0,t.setAttribute(`aria-expanded`,`true`);let n=new Vp({labelHtml:V.get(`searchField`)});n.addEventListener(`input`,async e=>{let t=++this.searchRequestId;if(this.searchItemsProvider){let n=await this.searchItemsProvider(e);if(t!==this.searchRequestId)return;this.updateItems(n,{persist:!1})}let n=e.toLowerCase();for(let e of this.selectedItems)e.hidden=!(e.dataset[this.contentItemSearchDatasetKey]??``).includes(n)}),this.contentList=this.createDialogContentList(),e.bodyContainer.append(n.container,this.contentList),e.addEventListener(`close`,()=>{this.isDialogOpen=!1,this.restoreBaseItems(),this.selectedItems=[],this.contentList=void 0,t.setAttribute(`aria-expanded`,`false`)}),e.open()}finally{this.isLoading=!1}}),e.appendChild(t),{container:e,outer:t,arrowIcon:r,title:n}}calcSelectedValues(){return new Set(this._items.filter(e=>e.selected).map(e=>e.value))}addEventListener(e,t){return Fp(this.events,e,t),this}removeEventListener(e,t){return Ip(this.events,e,t),this}updateTitle(){return this.title.textContent=this.visibleText,this}updateSelectedState(){if(this.selectedItems.length>0)for(let e of this.selectedItems){let t=e.dataset.votValue;t!==void 0&&(e.dataset.votSelected=this.selectedValues.has(t).toString())}return this.updateTitle(),this}setSelectedValue(e){let t=Array.isArray(e)?e:[e],n;return n=this.multiSelect?t:t.length>0?[t[0]]:[],this.selectedValues=new Set(n),this.syncItemsSelectionState(),this.syncItemsSelectionState(this.baseItems),this.updateSelectedState(),this}updateItems(e,t={}){let{persist:n=!0}=t,r=this.cloneItems(e);n&&(this.baseItems=this.cloneItems(r)),this._items=r,this.selectedValues=this.calcSelectedValues(),this.updateSelectedState();let i=this.contentList?.parentElement;if(!this.contentList||!i)return this;let a=this.contentList;return this.contentList=this.createDialogContentList(),i.replaceChild(this.contentList,a),this}get visibleText(){return this.multiSelect?this._items.filter(e=>this.selectedValues.has(e.value)).map(e=>e.label).join(`, `)||this._selectTitle:this._items.find(e=>e.selected)?.label??this._selectTitle}set selectTitle(e){this._selectTitle=e,this.updateTitle()}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get disabled(){return this.outer.getAttribute(`disabled`)===`true`||this.outer.getAttribute(`aria-disabled`)===`true`}set disabled(e){if(e){this.outer.setAttribute(`disabled`,`true`);return}this.outer.removeAttribute(`disabled`)}},Hp=class{container;fromSelect;directionIcon;toSelect;dialogParent;_fromSelectTitle;_fromDialogTitle;_fromItems;_toSelectTitle;_toDialogTitle;_toItems;constructor({from:{selectTitle:e=V.get(`videoLanguage`),dialogTitle:t=V.get(`videoLanguage`),items:n},to:{selectTitle:r=V.get(`translationLanguage`),dialogTitle:i=V.get(`translationLanguage`),items:a},dialogParent:o=document.documentElement}){this._fromSelectTitle=e,this._fromDialogTitle=t,this._fromItems=n,this._toSelectTitle=r,this._toDialogTitle=i,this._toItems=a,this.dialogParent=o;let s=this.createElements();this.container=s.container,this.fromSelect=s.fromSelect,this.directionIcon=s.directionIcon,this.toSelect=s.toSelect}createElements(){let e=J.createEl(`vot-block`,[`vot-lang-select`]),t=new Q({selectTitle:this._fromSelectTitle,dialogTitle:this._fromDialogTitle,items:this._fromItems,dialogParent:this.dialogParent}),n=J.createEl(`vot-block`,[`vot-lang-select-icon`]);q(kp,n);let r=new Q({selectTitle:this._toSelectTitle,dialogTitle:this._toDialogTitle,items:this._toItems,dialogParent:this.dialogParent});return e.append(t.container,n,r.container),{container:e,fromSelect:t,directionIcon:n,toSelect:r}}setSelectedValues(e,t){return this.fromSelect.setSelectedValue(e),this.toSelect.setSelectedValue(t),this}updateItems(e,t){return this._fromItems=e,this._toItems=t,this.fromSelect=this.fromSelect.updateItems(e),this.toSelect=this.toSelect.updateItems(t),this}},Up=class{container;input;label;onInput=new H;_labelHtml;_value;_min;_max;_step;constructor({labelHtml:e,value:t=50,min:n=0,max:r=100,step:i=1}){this._labelHtml=e,this._value=t,this._min=n,this._max=r,this._step=i;let a=this.createElements();this.container=a.container,this.input=a.input,this.label=a.label,this.update()}updateProgress(){let e=this._max-this._min,t=e<=0?0:(this._value-this._min)/e,n=Math.max(0,Math.min(1,t));return this.container.style.setProperty(`--vot-progress`,n.toString()),this}update(){return this._value=this.input.valueAsNumber,this._min=+this.input.min,this._max=+this.input.max,this.updateProgress(),this}createElements(){let e=J.createEl(`vot-block`,[`vot-slider`]),t=document.createElement(`input`);t.type=`range`,t.min=this._min.toString(),t.max=this._max.toString(),t.step=this._step.toString(),t.value=this._value.toString();let n=J.createEl(`span`);return q(this._labelHtml,n),e.append(t,n),t.addEventListener(`input`,()=>{this.update(),this.onInput.dispatch(this._value,!1)}),{container:e,label:n,input:t}}addEventListener(e,t){return this.onInput.addListener(t),this}removeEventListener(e,t){return this.onInput.removeListener(t),this}get value(){return this._value}set value(e){this._value=Wp(e,this._min,this._max),this.input.value=this._value.toString(),this.updateProgress(),this.onInput.dispatch(this._value,!0)}get min(){return this._min}set min(e){this._min=e,this.input.min=this._min.toString(),this._value=Wp(this._value,this._min,this._max),this.input.value=this._value.toString(),this.updateProgress()}get max(){return this._max}set max(e){this._max=e,this.input.max=this._max.toString(),this._value=Wp(this._value,this._min,this._max),this.input.value=this._value.toString(),this.updateProgress()}get step(){return this._step}set step(e){this._step=e,this.input.step=this._step.toString()}get disabled(){return this.input.disabled}set disabled(e){this.input.disabled=e}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}};function Wp(e,t,n){return!Number.isFinite(e)||n=66?`right`:`default`:`default`}static calcDirection(e){return[`default`,`top`].includes(e)?`row`:`column`}createElements(){let e=J.createEl(`vot-block`,[`vot-segmented-button`]);e.dataset.position=this._position,e.dataset.direction=this._direction,e.dataset.status=this._status;let t=J.createEl(`vot-block`,[`vot-segment`,`vot-translate-button`]);t.setAttribute(`role`,`button`),t.tabIndex=0,t.setAttribute(`aria-label`,this._labelText||`Translate`),q(Sp,t);let n=J.createEl(`span`,[`vot-segment-label`]);n.textContent=this._labelText,t.appendChild(n);let r=J.createEl(`vot-block`,[`vot-separator`]),i=J.createEl(`vot-block`,[`vot-segment-only-icon`]);i.setAttribute(`role`,`button`),i.tabIndex=0,i.setAttribute(`aria-label`,`Picture in picture`),q(Cp,i);let a=J.createEl(`vot-block`,[`vot-separator`]),o=J.createEl(`vot-block`,[`vot-segment-only-icon`]);return o.setAttribute(`role`,`button`),o.tabIndex=0,o.setAttribute(`aria-label`,`Menu`),o.setAttribute(`aria-haspopup`,`dialog`),o.setAttribute(`aria-expanded`,`false`),q(wp,o),e.append(t,r,i,a,o),{container:e,translateButton:t,separator:r,pipButton:i,separator2:a,menuButton:o,label:n}}showPiPButton(e){return this.separator2.hidden=this.pipButton.hidden=!e,this}setText(e){return this._labelText=e,this.label.textContent=e,this.translateButton.setAttribute(`aria-label`,e||`Translate`),this}remove(){return this.container.remove(),this}get tooltipPos(){switch(this.position){case`left`:return`right`;case`right`:return`left`;default:return`bottom`}}set status(e){this._status=this.container.dataset.status=e}get status(){return this._status}set loading(e){this.container.dataset.loading=e.toString()}get loading(){return this.container.dataset.loading===`true`}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get position(){return this._position}set position(e){this._position=this.container.dataset.position=e}get direction(){return this._direction}set direction(e){this._direction=this.container.dataset.direction=e}set opacity(e){let t=Number.isFinite(e)?e:1;this._opacity=t;let n=t<=.01;this.container.classList.toggle(`vot-segmented-button--hidden`,n)}get opacity(){return this._opacity}},qp=class{container;contentWrapper;headerContainer;bodyContainer;footerContainer;titleContainer;title;_position;_titleHtml;menuId=typeof crypto<`u`&&`randomUUID`in crypto?`vot-menu-${crypto.randomUUID()}`:`vot-menu-${Math.random().toString(36).slice(2)}`;titleId=typeof crypto<`u`&&`randomUUID`in crypto?`vot-menu-title-${crypto.randomUUID()}`:`vot-menu-title-${Math.random().toString(36).slice(2)}`;constructor({position:e=`default`,titleHtml:t=``}){this._position=e,this._titleHtml=t;let n=this.createElements();this.container=n.container,this.contentWrapper=n.contentWrapper,this.headerContainer=n.headerContainer,this.bodyContainer=n.bodyContainer,this.footerContainer=n.footerContainer,this.titleContainer=n.titleContainer,this.title=n.title}createElements(){let e=J.createEl(`vot-block`,[`vot-menu`]);e.hidden=!0,e.id=this.menuId,e.dataset.position=this._position,e.setAttribute(`role`,`dialog`),e.setAttribute(`aria-modal`,`false`),e.setAttribute(`aria-hidden`,`true`),e.toggleAttribute(`inert`,!0);let t=J.createEl(`vot-block`,[`vot-menu-content-wrapper`]);e.appendChild(t);let n=J.createEl(`vot-block`,[`vot-menu-header-container`]),r=J.createEl(`vot-block`,[`vot-menu-title-container`]);n.appendChild(r);let i=J.createEl(`vot-block`,[`vot-menu-title`]);i.id=this.titleId,i.append(this._titleHtml),r.appendChild(i),e.setAttribute(`aria-labelledby`,this.titleId);let a=J.createEl(`vot-block`,[`vot-menu-body-container`]),o=J.createEl(`vot-block`,[`vot-menu-footer-container`]);return t.append(n,a,o),{container:e,contentWrapper:t,headerContainer:n,bodyContainer:a,footerContainer:o,titleContainer:r,title:i}}setText(e){return this._titleHtml=this.title.textContent=e,this}remove(){return this.container.remove(),this}set hidden(e){X(this.container,e),this.container.setAttribute(`aria-hidden`,e?`true`:`false`),this.container.toggleAttribute(`inert`,e)}get hidden(){return Z(this.container)}get position(){return this._position}set position(e){this._position=this.container.dataset.position=e}},Jp=class e{static BIG_CONTAINER_WIDTH_PX=550;mount;globalPortal;abortController=null;defaultVolumePersistTimer;defaultVolumePersistDelayMs=250;dragging=!1;dragCandidate=!1;dragDirty=!1;dragStartX=0;dragStartY=0;currentClientX=0;activePointerId=null;dragThresholdPx=6;containerRect=null;dragIsBigContainer=null;checkerUnsubscribe=null;initialized=!1;data;videoHandler;intervalIdleChecker;events={"click:settings":new H,"click:pip":new H,"click:downloadTranslation":new H,"click:downloadSubtitles":new H,"click:translate":new H,"input:videoVolume":new H,"input:translationVolume":new H,"select:fromLanguage":new H,"select:toLanguage":new H,"select:subtitles":new H};votButton;votButtonTooltip;votMenu;downloadTranslationButton;downloadSubtitlesButton;openSettingsButton;languagePairSelect;subtitlesSelectLabel;subtitlesSelect;videoVolumeSliderLabel;videoVolumeSlider;translationVolumeSliderLabel;translationVolumeSlider;constructor({mount:e,globalPortal:t,data:n={},videoHandler:r,intervalIdleChecker:i}){this.mount=e,this.globalPortal=t,this.data=n,this.videoHandler=r,this.intervalIdleChecker=i}get root(){return this.mount.root}get portalContainer(){return this.mount.portalContainer}get tooltipLayoutRoot(){return this.mount.tooltipLayoutRoot}updateMount(e){let t=this.mount.root,n=e.root,r=this.mount.tooltipLayoutRoot,i=e.tooltipLayoutRoot;return this.mount=e,this.isInitialized()?(t!==n&&(this.votButton&&n.appendChild(this.votButton.container),this.votMenu&&n.appendChild(this.votMenu.container)),this.votButtonTooltip&&_p({root:t,portalContainer:this.mount.portalContainer,subtitlesMountContainer:this.mount.subtitlesMountContainer,tooltipLayoutRoot:r},e)&&this.votButtonTooltip.updateMount({layoutRoot:i??document.documentElement}),this):this}isInitialized(){return this.initialized}calcButtonLayout(e){return this.isBigContainer&&Yp(e)?{direction:`column`,position:e}:{direction:`row`,position:`default`}}addEventListener(e,t){return this.events[e].addListener(t),this}removeEventListener(e,t){return this.events[e].removeListener(t),this}scheduleDefaultVolumePersist(){this.defaultVolumePersistTimer!==void 0&&globalThis.clearTimeout(this.defaultVolumePersistTimer),this.defaultVolumePersistTimer=globalThis.setTimeout(()=>{this.defaultVolumePersistTimer=void 0,this.flushDefaultVolumePersist()},this.defaultVolumePersistDelayMs)}flushDefaultVolumePersist(){this.defaultVolumePersistTimer!==void 0&&(globalThis.clearTimeout(this.defaultVolumePersistTimer),this.defaultVolumePersistTimer=void 0),typeof this.data.defaultVolume==`number`&&B.set(`defaultVolume`,this.data.defaultVolume)}initUI(e=`default`){if(this.isInitialized())throw Error(`[VOT] OverlayView is already initialized`);this.initialized=!0;let{position:t,direction:n}=this.calcButtonLayout(e);this.votButton=new Kp({position:t,direction:n,status:`none`,labelHtml:V.get(`translateVideo`)}),this.votButton.opacity=0,this.pipButtonVisible||this.votButton.showPiPButton(!1),this.root.appendChild(this.votButton.container),this.votButtonTooltip=new Y({target:this.votButton.translateButton,content:V.get(`translateVideo`),position:this.votButton.tooltipPos,autoLayout:!1,hidden:n===`row`,bordered:!1,parentElement:this.globalPortal,layoutRoot:this.tooltipLayoutRoot}),this.votMenu=new qp({titleHtml:V.get(`VOTSettings`),position:t}),this.root.appendChild(this.votMenu.container),this.votButton.menuButton.setAttribute(`aria-controls`,this.votMenu.container.id),this.downloadTranslationButton=new Lp,this.downloadTranslationButton.hidden=!0,this.downloadSubtitlesButton=J.createIconButton(Ep,{ariaLabel:`Download subtitles`}),this.downloadSubtitlesButton.hidden=!0,this.openSettingsButton=J.createIconButton(Dp,{ariaLabel:V.get(`VOTSettings`)}),this.votMenu.headerContainer.append(this.downloadTranslationButton.button,this.downloadSubtitlesButton,this.openSettingsButton);let r=this.videoHandler?.videoData?.detectedLanguage??`en`,i=this.data.responseLanguage??`ru`;this.languagePairSelect=new Hp({from:{selectTitle:V.get(`langs.${r}`),items:Q.genLanguageItems(bn,r)},to:{selectTitle:V.get(`langs.${i}`),items:Q.genLanguageItems(xn,i)},dialogParent:this.globalPortal}),this.subtitlesSelectLabel=new zp({labelText:V.get(`VOTSubtitles`)}),this.subtitlesSelect=new Q({selectTitle:V.get(`VOTSubtitlesDisabled`),dialogTitle:V.get(`VOTSubtitles`),labelElement:this.subtitlesSelectLabel.container,dialogParent:this.globalPortal,items:[{label:V.get(`VOTSubtitlesDisabled`),value:`disabled`,selected:!0}]});let a=this.videoHandler?this.videoHandler.getVideoVolume()*100:100;this.videoVolumeSliderLabel=new Gp({labelText:V.get(`VOTVolume`),value:a}),this.videoVolumeSlider=new Up({labelHtml:this.videoVolumeSliderLabel.container,value:a}),this.videoVolumeSlider.hidden=!this.data.showVideoSlider||this.votButton.status!==`success`;let o=this.data.defaultVolume??100;return this.translationVolumeSliderLabel=new Gp({labelText:V.get(`VOTVolumeTranslation`),value:o}),this.translationVolumeSlider=new Up({labelHtml:this.translationVolumeSliderLabel.container,value:o,max:this.data.audioBooster&&!this.data.syncVolume?900:100}),this.translationVolumeSlider.hidden=this.votButton.status!==`success`,this.votMenu.bodyContainer.append(this.languagePairSelect.container,this.subtitlesSelect.container,this.videoVolumeSlider.container,this.translationVolumeSlider.container),this}initUIEvents(){if(!this.isInitialized())throw Error(`[VOT] OverlayView isn't initialized`);this.abortController=new AbortController;let e=this.abortController.signal;this.checkerUnsubscribe?.(),this.checkerUnsubscribe=this.intervalIdleChecker.subscribe(()=>{this.onCheckerTick()}),this.votButton.container.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation()},{signal:e});let t=e=>t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),e())},n=e=>e.isPrimary&&e.button===0,r=(e,{returnFocusToToggle:t=!1}={})=>{this.isInitialized()&&(this.votMenu.hidden=!e,this.votButton.menuButton.setAttribute(`aria-expanded`,e.toString()),this.votButtonTooltip&&(this.votButtonTooltip.hidden=e||this.votButton.direction===`row`),e?queueMicrotask(()=>this.openSettingsButton?.focus?.()):t?queueMicrotask(()=>this.votButton.menuButton.focus?.()):this.votButton.menuButton.blur())},i=()=>r(this.votMenu.hidden),a=(e=!1)=>r(!1,{returnFocusToToggle:e});this.votButton.translateButton.addEventListener(`pointerdown`,e=>{n(e)&&(a(),this.events[`click:translate`].dispatch())},{signal:e}),this.votButton.translateButton.addEventListener(`keydown`,t(()=>{a(),this.events[`click:translate`].dispatch()}),{signal:e}),this.votButton.pipButton.addEventListener(`pointerdown`,e=>{n(e)&&(a(),this.events[`click:pip`].dispatch())},{signal:e}),this.votButton.pipButton.addEventListener(`keydown`,t(()=>{a(),this.events[`click:pip`].dispatch()}),{signal:e}),this.votButton.menuButton.addEventListener(`pointerdown`,e=>{n(e)&&(e.preventDefault(),i())},{signal:e}),this.votButton.menuButton.addEventListener(`keydown`,t(i),{signal:e});let o=`none`;this.votButton.container.style.touchAction=o,this.votButton.translateButton.style.touchAction=o,this.votButton.pipButton.style.touchAction=o,this.votButton.menuButton.style.touchAction=o,this.votButton.container.addEventListener(`pointerdown`,this.onDragStart,{signal:e}),this.votButton.container.addEventListener(`pointermove`,this.onPointerMove,{signal:e}),this.votButton.container.addEventListener(`pointerup`,this.onDragEnd,{signal:e}),this.votButton.container.addEventListener(`pointercancel`,this.onDragEnd,{signal:e}),this.votButton.container.addEventListener(`lostpointercapture`,this.onDragEnd,{signal:e}),this.votMenu.container.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation()},{signal:e});for(let t of[`pointerdown`,`mousedown`])this.votMenu.container.addEventListener(t,e=>{e.stopImmediatePropagation()},{signal:e});return document.addEventListener(`pointerdown`,e=>{if(this.votMenu.hidden)return;let t=e.target,n=typeof e.composedPath==`function`?e.composedPath():[],r=t&&this.votMenu.container.contains(t)||n.includes(this.votMenu.container),i=t&&this.votButton.menuButton.contains(t)||n.includes(this.votButton.menuButton),o=t&&this.votButton.container.contains(t)||n.includes(this.votButton.container),s=t instanceof HTMLElement&&!!t.closest(`.vot-dialog-container`);r||i||o||s||a(!1)},{signal:e,capture:!0,passive:!0}),this.votMenu.container.addEventListener(`keydown`,e=>{if(e.key!==`Escape`)return;let t=document.documentElement.classList.contains(`vot-keyboard-nav`);e.preventDefault(),e.stopPropagation(),a(t),this.votButton.container.matches(`:hover`)||this.votMenu.container.matches(`:hover`)||this.videoHandler?.overlayVisibility?.queueAutoHide?.()},{signal:e}),this.downloadTranslationButton.addEventListener(`click`,()=>{this.events[`click:downloadTranslation`].dispatch()}),this.downloadSubtitlesButton.addEventListener(`click`,()=>{this.events[`click:downloadSubtitles`].dispatch()},{signal:e}),this.openSettingsButton.addEventListener(`click`,()=>{a(),this.events[`click:settings`].dispatch()},{signal:e}),this.languagePairSelect.fromSelect.addEventListener(`selectItem`,e=>{this.videoHandler?.videoData&&(this.videoHandler.videoData.detectedLanguage=e,this.videoHandler.videoManager.rememberUserLanguageSelection(this.videoHandler.videoData.videoId,e)),this.events[`select:fromLanguage`].dispatch(e)}),this.languagePairSelect.toSelect.addEventListener(`selectItem`,async e=>{this.videoHandler?.videoData&&(this.videoHandler.translateToLang=this.videoHandler.videoData.responseLanguage=e);let t=this.data.responseLanguage;t!==e&&(this.data.responseLanguage=e,await B.set(`responseLanguage`,this.data.responseLanguage)),this.data.enabledDontTranslateLanguages&&Array.isArray(this.data.dontTranslateLanguages)&&this.data.dontTranslateLanguages.length===1&&t!==e&&typeof t==`string`&&this.data.dontTranslateLanguages[0]===t&&(this.data.dontTranslateLanguages=[e],await B.set(`dontTranslateLanguages`,this.data.dontTranslateLanguages)),this.events[`select:toLanguage`].dispatch(e)}),this.subtitlesSelect.addEventListener(`beforeOpen`,async e=>{if(!this.videoHandler?.videoData)return;let t=this.videoHandler.getPreferredSubtitlesLanguage(this.videoHandler.videoData.detectedLanguage,this.videoHandler.videoData.responseLanguage);if(!t)return;let n=this.videoHandler.getSubtitlesCacheKey(this.videoHandler.videoData.videoId,this.videoHandler.videoData.detectedLanguage,t);if(this.videoHandler.subtitlesCacheKey===n)return;if(this.videoHandler.cacheManager.getSubtitles(n)!==void 0){await this.videoHandler.ensureSubtitlesForCurrentLangPair();return}let r=this.votButton?.loading??!1;this.votButton&&(this.votButton.loading=!0);let i=J.createInlineLoader();i.style.margin=`0 auto`,e.footerContainer.appendChild(i);try{await this.videoHandler.ensureSubtitlesForCurrentLangPair()}finally{i.remove(),this.votButton&&(this.votButton.loading=r)}}),this.subtitlesSelect.addEventListener(`selectItem`,e=>{this.events[`select:subtitles`].dispatch(e)}),this.videoVolumeSlider.addEventListener(`input`,(e,t)=>{this.videoVolumeSliderLabel&&(this.videoVolumeSliderLabel.value=e),!t&&this.events[`input:videoVolume`].dispatch(e)}),this.translationVolumeSlider.addEventListener(`input`,(e,t)=>{this.translationVolumeSliderLabel&&(this.translationVolumeSliderLabel.value=e),this.data.defaultVolume!==e&&(this.data.defaultVolume=e,this.scheduleDefaultVolumePersist()),!t&&this.events[`input:translationVolume`].dispatch(e)}),this}updateButtonLayout(e,t){return this.isInitialized()?(this.votMenu.position=e,this.votButton.position=e,this.votButton.direction=t,this.votButtonTooltip.hidden=t===`row`,this.votButtonTooltip.setPosition(this.votButton.tooltipPos),this):this}moveButton(e){if(!this.isInitialized())return this;let t=this.dragIsBigContainer??this.isBigContainer,n=Kp.calcPosition(e,t);if(n===this.votButton.position)return this;let r=Kp.calcDirection(n);return this.data.buttonPos=n,this.updateButtonLayout(n,r),this}startDragSession(e,t,n){this.dragCandidate=!0,this.dragging=!1,this.dragStartX=e,this.dragStartY=t,this.currentClientX=e,this.containerRect=this.root.getBoundingClientRect(),this.dragIsBigContainer=this.isBigContainer,this.dragDirty=!1,this.intervalIdleChecker.markActivity(n),this.intervalIdleChecker.requestImmediateTick()}queueDragTick(e){this.dragDirty||(this.dragDirty=!0,this.intervalIdleChecker.markActivity(e),this.intervalIdleChecker.requestImmediateTick())}updateDragFromMove(e,t,n){this.currentClientX=e,this.dragCandidate&&(this.dragging||Math.abs(this.currentClientX-this.dragStartX)+Math.abs(t-this.dragStartY)>=this.dragThresholdPx&&(this.dragging=!0),this.dragging&&this.queueDragTick(n))}onDragStart=e=>{!e.isPrimary||e.button!==0||(e.preventDefault(),this.activePointerId=e.pointerId,this.startDragSession(e.clientX,e.clientY,`overlay-pointer-down`))};onPointerMove=e=>{if(this.activePointerId!==e.pointerId)return;let t=this.dragging;if(this.updateDragFromMove(e.clientX,e.clientY,`overlay-pointer-move`),!t&&this.dragging)try{this.votButton?.container.setPointerCapture(e.pointerId)}catch{}this.dragging&&e.preventDefault()};applyDragFromState=()=>{if(!this.dragging||!this.dragDirty||!this.containerRect)return;let e=this.containerRect.width;if(!(e>0&&Number.isFinite(e)))return;this.dragDirty=!1;let t=this.currentClientX-this.containerRect.left,n=Math.max(0,Math.min(t,e))/e*100;this.moveButton(n)};onCheckerTick=()=>{this.applyDragFromState()};onDragEnd=e=>{if(e&&this.activePointerId!==null&&e.pointerId!==this.activePointerId)return;let t=this.activePointerId;if(t!==null)try{this.votButton?.container.hasPointerCapture(t)&&this.votButton.container.releasePointerCapture(t)}catch{}this.applyDragFromState();let n=this.dragIsBigContainer??this.isBigContainer;this.dragging&&n&&this.data.buttonPos&&B.set(`buttonPos`,this.data.buttonPos),this.dragging=!1,this.dragCandidate=!1,this.dragDirty=!1,this.containerRect=null,this.dragIsBigContainer=null,this.activePointerId=null};updateButtonOpacity(e){return!this.isInitialized()||!this.votMenu.hidden||Math.abs(this.votButton.opacity-e)>.01&&(this.votButton.opacity=e),this}doReleaseUI(){this.votButton?.remove(),this.votMenu?.remove(),this.votButtonTooltip?.release()}doReleaseUIEvents(){this.abortController?.abort(),this.abortController=null,this.checkerUnsubscribe?.(),this.checkerUnsubscribe=null,this.onDragEnd(),this.flushDefaultVolumePersist();for(let e of Object.values(this.events))e.clear()}release(){return this.isInitialized()?(this.doReleaseUIEvents(),this.doReleaseUI(),this.initialized=!1,this):this}get isBigContainer(){let t=this.videoHandler?.video?.getBoundingClientRect?.().width;if(typeof t==`number`&&Number.isFinite(t))return t>e.BIG_CONTAINER_WIDTH_PX;let n=this.videoHandler?.container?.getBoundingClientRect?.().width;return typeof n==`number`&&Number.isFinite(n)?n>e.BIG_CONTAINER_WIDTH_PX:this.root.clientWidth>e.BIG_CONTAINER_WIDTH_PX}get pipButtonVisible(){return Gi()&&!!this.data.showPiPButton}};function Yp(e){return e===`left`||e===`right`}var Xp=[`default`,`top`,`left`,`right`],Zp=d(c(((e,t)=>{(function(n,r){typeof e==`object`&&typeof t==`object`?t.exports=r():typeof define==`function`&&define.amd?define([],r):typeof e==`object`?e.bowser=r():n.bowser=r()})(e,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){typeof Symbol<`u`&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),Object.defineProperty(e,`__esModule`,{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t||4&t&&typeof e==`object`&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,`default`,{enumerable:!0,value:e}),2&t&&typeof e!=`string`)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,`a`,t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p=``,n(n.s=90)}({17:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r=n(18);t.default=function(){function e(){}return e.getFirstMatch=function(e,t){var n=t.match(e);return n&&n.length>0&&n[1]||``},e.getSecondMatch=function(e,t){var n=t.match(e);return n&&n.length>1&&n[2]||``},e.matchAndReturnConst=function(e,t,n){if(e.test(t))return n},e.getWindowsVersionName=function(e){switch(e){case`NT`:return`NT`;case`XP`:return`XP`;case`NT 5.0`:return`2000`;case`NT 5.1`:return`XP`;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}},e.getMacOSVersionName=function(e){var t=e.split(`.`).splice(0,2).map((function(e){return parseInt(e,10)||0}));t.push(0);var n=t[0],r=t[1];if(n===10)switch(r){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}switch(n){case 11:return`Big Sur`;case 12:return`Monterey`;case 13:return`Ventura`;case 14:return`Sonoma`;case 15:return`Sequoia`;default:return}},e.getAndroidVersionName=function(e){var t=e.split(`.`).splice(0,2).map((function(e){return parseInt(e,10)||0}));if(t.push(0),!(t[0]===1&&t[1]<5))return t[0]===1&&t[1]<6?`Cupcake`:t[0]===1&&t[1]>=6?`Donut`:t[0]===2&&t[1]<2?`Eclair`:t[0]===2&&t[1]===2?`Froyo`:t[0]===2&&t[1]>2?`Gingerbread`:t[0]===3?`Honeycomb`:t[0]===4&&t[1]<1?`Ice Cream Sandwich`:t[0]===4&&t[1]<4?`Jelly Bean`:t[0]===4&&t[1]>=4?`KitKat`:t[0]===5?`Lollipop`:t[0]===6?`Marshmallow`:t[0]===7?`Nougat`:t[0]===8?`Oreo`:t[0]===9?`Pie`:void 0},e.getVersionPrecision=function(e){return e.split(`.`).length},e.compareVersions=function(t,n,r){r===void 0&&(r=!1);var i=e.getVersionPrecision(t),a=e.getVersionPrecision(n),o=Math.max(i,a),s=0,c=e.map([t,n],(function(t){var n=o-e.getVersionPrecision(t),r=t+Array(n+1).join(`.0`);return e.map(r.split(`.`),(function(e){return Array(20-e.length).join(`0`)+e})).reverse()}));for(r&&(s=o-Math.min(i,a)),--o;o>=s;){if(c[0][o]>c[1][o])return 1;if(c[0][o]===c[1][o]){if(o===s)return 0;--o}else if(c[0][o]1?i-1:0),o=1;o0){var o=Object.keys(n),c=s.default.find(o,(function(e){return t.isOS(e)}));if(c){var l=this.satisfies(n[c]);if(l!==void 0)return l}var u=s.default.find(o,(function(e){return t.isPlatform(e)}));if(u){var d=this.satisfies(n[u]);if(d!==void 0)return d}}if(a>0){var f=Object.keys(i),p=s.default.find(f,(function(e){return t.isBrowser(e,!0)}));if(p!==void 0)return this.compareVersion(i[p])}},t.isBrowser=function(e,t){t===void 0&&(t=!1);var n=this.getBrowserName().toLowerCase(),r=e.toLowerCase(),i=s.default.getBrowserTypeByAlias(r);return t&&i&&(r=i.toLowerCase()),r===n},t.compareVersion=function(e){var t=[0],n=e,r=!1,i=this.getBrowserVersion();if(typeof i==`string`)return e[0]===`>`||e[0]===`<`?(n=e.substr(1),e[1]===`=`?(r=!0,n=e.substr(2)):t=[],e[0]===`>`?t.push(1):t.push(-1)):e[0]===`=`?n=e.substr(1):e[0]===`~`&&(r=!0,n=e.substr(1)),t.indexOf(s.default.compareVersions(i,n,r))>-1},t.isOS=function(e){return this.getOSName(!0)===String(e).toLowerCase()},t.isPlatform=function(e){return this.getPlatformType(!0)===String(e).toLowerCase()},t.isEngine=function(e){return this.getEngineName(!0)===String(e).toLowerCase()},t.is=function(e,t){return t===void 0&&(t=!1),this.isBrowser(e,t)||this.isOS(e)||this.isPlatform(e)},t.some=function(e){var t=this;return e===void 0&&(e=[]),e.some((function(e){return t.is(e)}))},e}(),e.exports=t.default},92:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=/version\/(\d+(\.?_?\d+)+)/i;t.default=[{test:[/gptbot/i],describe:function(e){var t={name:`GPTBot`},n=i.default.getFirstMatch(/gptbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/chatgpt-user/i],describe:function(e){var t={name:`ChatGPT-User`},n=i.default.getFirstMatch(/chatgpt-user\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/oai-searchbot/i],describe:function(e){var t={name:`OAI-SearchBot`},n=i.default.getFirstMatch(/oai-searchbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/claudebot/i,/claude-web/i,/claude-user/i,/claude-searchbot/i],describe:function(e){var t={name:`ClaudeBot`},n=i.default.getFirstMatch(/(?:claudebot|claude-web|claude-user|claude-searchbot)\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/omgilibot/i,/webzio-extended/i],describe:function(e){var t={name:`Omgilibot`},n=i.default.getFirstMatch(/(?:omgilibot|webzio-extended)\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/diffbot/i],describe:function(e){var t={name:`Diffbot`},n=i.default.getFirstMatch(/diffbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/perplexitybot/i],describe:function(e){var t={name:`PerplexityBot`},n=i.default.getFirstMatch(/perplexitybot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/perplexity-user/i],describe:function(e){var t={name:`Perplexity-User`},n=i.default.getFirstMatch(/perplexity-user\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/youbot/i],describe:function(e){var t={name:`YouBot`},n=i.default.getFirstMatch(/youbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-webindexer/i],describe:function(e){var t={name:`Meta-WebIndexer`},n=i.default.getFirstMatch(/meta-webindexer\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-externalads/i],describe:function(e){var t={name:`Meta-ExternalAds`},n=i.default.getFirstMatch(/meta-externalads\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-externalagent/i],describe:function(e){var t={name:`Meta-ExternalAgent`},n=i.default.getFirstMatch(/meta-externalagent\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/meta-externalfetcher/i],describe:function(e){var t={name:`Meta-ExternalFetcher`},n=i.default.getFirstMatch(/meta-externalfetcher\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/googlebot/i],describe:function(e){var t={name:`Googlebot`},n=i.default.getFirstMatch(/googlebot\/(\d+(\.\d+))/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/linespider/i],describe:function(e){var t={name:`Linespider`},n=i.default.getFirstMatch(/(?:linespider)(?:-[-\w]+)?[\s/](\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/amazonbot/i],describe:function(e){var t={name:`AmazonBot`},n=i.default.getFirstMatch(/amazonbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/bingbot/i],describe:function(e){var t={name:`BingCrawler`},n=i.default.getFirstMatch(/bingbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/baiduspider/i],describe:function(e){var t={name:`BaiduSpider`},n=i.default.getFirstMatch(/baiduspider\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/duckduckbot/i],describe:function(e){var t={name:`DuckDuckBot`},n=i.default.getFirstMatch(/duckduckbot\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/ia_archiver/i],describe:function(e){var t={name:`InternetArchiveCrawler`},n=i.default.getFirstMatch(/ia_archiver\/(\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/facebookexternalhit/i,/facebookcatalog/i],describe:function(){return{name:`FacebookExternalHit`}}},{test:[/slackbot/i,/slack-imgProxy/i],describe:function(e){var t={name:`SlackBot`},n=i.default.getFirstMatch(/(?:slackbot|slack-imgproxy)(?:-[-\w]+)?[\s/](\d+(\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/yahoo!?[\s/]*slurp/i],describe:function(){return{name:`YahooSlurp`}}},{test:[/yandexbot/i,/yandexmobilebot/i],describe:function(){return{name:`YandexBot`}}},{test:[/pingdom/i],describe:function(){return{name:`PingdomBot`}}},{test:[/opera/i],describe:function(e){var t={name:`Opera`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:opera)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/opr\/|opios/i],describe:function(e){var t={name:`Opera`},n=i.default.getFirstMatch(/(?:opr|opios)[\s/](\S+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/SamsungBrowser/i],describe:function(e){var t={name:`Samsung Internet for Android`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:SamsungBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/Whale/i],describe:function(e){var t={name:`NAVER Whale Browser`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:whale)[\s/](\d+(?:\.\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/PaleMoon/i],describe:function(e){var t={name:`Pale Moon`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:PaleMoon)[\s/](\d+(?:\.\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/MZBrowser/i],describe:function(e){var t={name:`MZ Browser`},n=i.default.getFirstMatch(/(?:MZBrowser)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/focus/i],describe:function(e){var t={name:`Focus`},n=i.default.getFirstMatch(/(?:focus)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/swing/i],describe:function(e){var t={name:`Swing`},n=i.default.getFirstMatch(/(?:swing)[\s/](\d+(?:\.\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/coast/i],describe:function(e){var t={name:`Opera Coast`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:coast)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/opt\/\d+(?:.?_?\d+)+/i],describe:function(e){var t={name:`Opera Touch`},n=i.default.getFirstMatch(/(?:opt)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/yabrowser/i],describe:function(e){var t={name:`Yandex Browser`},n=i.default.getFirstMatch(/(?:yabrowser)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/ucbrowser/i],describe:function(e){var t={name:`UC Browser`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:ucbrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/Maxthon|mxios/i],describe:function(e){var t={name:`Maxthon`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:Maxthon|mxios)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/epiphany/i],describe:function(e){var t={name:`Epiphany`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:epiphany)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/puffin/i],describe:function(e){var t={name:`Puffin`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:puffin)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/sleipnir/i],describe:function(e){var t={name:`Sleipnir`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:sleipnir)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/k-meleon/i],describe:function(e){var t={name:`K-Meleon`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/(?:k-meleon)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/micromessenger/i],describe:function(e){var t={name:`WeChat`},n=i.default.getFirstMatch(/(?:micromessenger)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/qqbrowser/i],describe:function(e){var t={name:/qqbrowserlite/i.test(e)?`QQ Browser Lite`:`QQ Browser`},n=i.default.getFirstMatch(/(?:qqbrowserlite|qqbrowser)[/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/msie|trident/i],describe:function(e){var t={name:`Internet Explorer`},n=i.default.getFirstMatch(/(?:msie |rv:)(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/\sedg\//i],describe:function(e){var t={name:`Microsoft Edge`},n=i.default.getFirstMatch(/\sedg\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/edg([ea]|ios)/i],describe:function(e){var t={name:`Microsoft Edge`},n=i.default.getSecondMatch(/edg([ea]|ios)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/vivaldi/i],describe:function(e){var t={name:`Vivaldi`},n=i.default.getFirstMatch(/vivaldi\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/seamonkey/i],describe:function(e){var t={name:`SeaMonkey`},n=i.default.getFirstMatch(/seamonkey\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/sailfish/i],describe:function(e){var t={name:`Sailfish`},n=i.default.getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i,e);return n&&(t.version=n),t}},{test:[/silk/i],describe:function(e){var t={name:`Amazon Silk`},n=i.default.getFirstMatch(/silk\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/phantom/i],describe:function(e){var t={name:`PhantomJS`},n=i.default.getFirstMatch(/phantomjs\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/slimerjs/i],describe:function(e){var t={name:`SlimerJS`},n=i.default.getFirstMatch(/slimerjs\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t={name:`BlackBerry`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/blackberry[\d]+\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t={name:`WebOS Browser`},n=i.default.getFirstMatch(a,e)||i.default.getFirstMatch(/w(?:eb)?[o0]sbrowser\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/bada/i],describe:function(e){var t={name:`Bada`},n=i.default.getFirstMatch(/dolfin\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/tizen/i],describe:function(e){var t={name:`Tizen`},n=i.default.getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/qupzilla/i],describe:function(e){var t={name:`QupZilla`},n=i.default.getFirstMatch(/(?:qupzilla)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/librewolf/i],describe:function(e){var t={name:`LibreWolf`},n=i.default.getFirstMatch(/(?:librewolf)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/firefox|iceweasel|fxios/i],describe:function(e){var t={name:`Firefox`},n=i.default.getFirstMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/electron/i],describe:function(e){var t={name:`Electron`},n=i.default.getFirstMatch(/(?:electron)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/sogoumobilebrowser/i,/metasr/i,/se 2\.[x]/i],describe:function(e){var t={name:`Sogou Browser`},n=i.default.getFirstMatch(/(?:sogoumobilebrowser)[\s/](\d+(\.?_?\d+)+)/i,e),r=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,e),a=i.default.getFirstMatch(/se ([\d.]+)x/i,e),o=n||r||a;return o&&(t.version=o),t}},{test:[/MiuiBrowser/i],describe:function(e){var t={name:`Miui`},n=i.default.getFirstMatch(/(?:MiuiBrowser)[\s/](\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){return!!e.hasBrand(`DuckDuckGo`)||e.test(/\sDdg\/[\d.]+$/i)},describe:function(e,t){var n={name:`DuckDuckGo`};if(t){var r=t.getBrandVersion(`DuckDuckGo`);if(r)return n.version=r,n}var a=i.default.getFirstMatch(/\sDdg\/([\d.]+)$/i,e);return a&&(n.version=a),n}},{test:function(e){return e.hasBrand(`Brave`)},describe:function(e,t){var n={name:`Brave`};if(t){var r=t.getBrandVersion(`Brave`);if(r)return n.version=r,n}return n}},{test:[/chromium/i],describe:function(e){var t={name:`Chromium`},n=i.default.getFirstMatch(/(?:chromium)[\s/](\d+(\.?_?\d+)+)/i,e)||i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/chrome|crios|crmo/i],describe:function(e){var t={name:`Chrome`},n=i.default.getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/GSA/i],describe:function(e){var t={name:`Google Search`},n=i.default.getFirstMatch(/(?:GSA)\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){var t=!e.test(/like android/i),n=e.test(/android/i);return t&&n},describe:function(e){var t={name:`Android Browser`},n=i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/playstation 4/i],describe:function(e){var t={name:`PlayStation 4`},n=i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/safari|applewebkit/i],describe:function(e){var t={name:`Safari`},n=i.default.getFirstMatch(a,e);return n&&(t.version=n),t}},{test:[/.*/i],describe:function(e){var t=e.search(`\\(`)===-1?/^(.*)\/(.*) /:/^(.*)\/(.*)[ \t]\((.*)/;return{name:i.default.getFirstMatch(t,e),version:i.default.getSecondMatch(t,e)}}}],e.exports=t.default},93:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=n(18);t.default=[{test:[/Roku\/DVP/],describe:function(e){var t=i.default.getFirstMatch(/Roku\/DVP-(\d+\.\d+)/i,e);return{name:a.OS_MAP.Roku,version:t}}},{test:[/windows phone/i],describe:function(e){var t=i.default.getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.WindowsPhone,version:t}}},{test:[/windows /i],describe:function(e){var t=i.default.getFirstMatch(/Windows ((NT|XP)( \d\d?.\d)?)/i,e),n=i.default.getWindowsVersionName(t);return{name:a.OS_MAP.Windows,version:t,versionName:n}}},{test:[/Macintosh(.*?) FxiOS(.*?)\//],describe:function(e){var t={name:a.OS_MAP.iOS},n=i.default.getSecondMatch(/(Version\/)(\d[\d.]+)/,e);return n&&(t.version=n),t}},{test:[/macintosh/i],describe:function(e){var t=i.default.getFirstMatch(/mac os x (\d+(\.?_?\d+)+)/i,e).replace(/[_\s]/g,`.`),n=i.default.getMacOSVersionName(t),r={name:a.OS_MAP.MacOS,version:t};return n&&(r.versionName=n),r}},{test:[/(ipod|iphone|ipad)/i],describe:function(e){var t=i.default.getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i,e).replace(/[_\s]/g,`.`);return{name:a.OS_MAP.iOS,version:t}}},{test:[/OpenHarmony/i],describe:function(e){var t=i.default.getFirstMatch(/OpenHarmony\s+(\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.HarmonyOS,version:t}}},{test:function(e){var t=!e.test(/like android/i),n=e.test(/android/i);return t&&n},describe:function(e){var t=i.default.getFirstMatch(/android[\s/-](\d+(\.\d+)*)/i,e),n=i.default.getAndroidVersionName(t),r={name:a.OS_MAP.Android,version:t};return n&&(r.versionName=n),r}},{test:[/(web|hpw)[o0]s/i],describe:function(e){var t=i.default.getFirstMatch(/(?:web|hpw)[o0]s\/(\d+(\.\d+)*)/i,e),n={name:a.OS_MAP.WebOS};return t&&t.length&&(n.version=t),n}},{test:[/blackberry|\bbb\d+/i,/rim\stablet/i],describe:function(e){var t=i.default.getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i,e)||i.default.getFirstMatch(/blackberry\d+\/(\d+([_\s]\d+)*)/i,e)||i.default.getFirstMatch(/\bbb(\d+)/i,e);return{name:a.OS_MAP.BlackBerry,version:t}}},{test:[/bada/i],describe:function(e){var t=i.default.getFirstMatch(/bada\/(\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.Bada,version:t}}},{test:[/tizen/i],describe:function(e){var t=i.default.getFirstMatch(/tizen[/\s](\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.Tizen,version:t}}},{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(e){var t=i.default.getFirstMatch(/PlayStation 4[/\s](\d+(\.\d+)*)/i,e);return{name:a.OS_MAP.PlayStation4,version:t}}}],e.exports=t.default},94:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=n(18);t.default=[{test:[/googlebot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Google`}}},{test:[/linespider/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Line`}}},{test:[/amazonbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Amazon`}}},{test:[/gptbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`OpenAI`}}},{test:[/chatgpt-user/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`OpenAI`}}},{test:[/oai-searchbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`OpenAI`}}},{test:[/baiduspider/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Baidu`}}},{test:[/bingbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Bing`}}},{test:[/duckduckbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`DuckDuckGo`}}},{test:[/claudebot/i,/claude-web/i,/claude-user/i,/claude-searchbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Anthropic`}}},{test:[/omgilibot/i,/webzio-extended/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Webz.io`}}},{test:[/diffbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Diffbot`}}},{test:[/perplexitybot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Perplexity AI`}}},{test:[/perplexity-user/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Perplexity AI`}}},{test:[/youbot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`You.com`}}},{test:[/ia_archiver/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Internet Archive`}}},{test:[/meta-webindexer/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/meta-externalads/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/meta-externalagent/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/meta-externalfetcher/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/facebookexternalhit/i,/facebookcatalog/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Meta`}}},{test:[/slackbot/i,/slack-imgProxy/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Slack`}}},{test:[/yahoo/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Yahoo`}}},{test:[/yandexbot/i,/yandexmobilebot/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Yandex`}}},{test:[/pingdom/i],describe:function(){return{type:a.PLATFORMS_MAP.bot,vendor:`Pingdom`}}},{test:[/huawei/i],describe:function(e){var t=i.default.getFirstMatch(/(can-l01)/i,e)&&`Nova`,n={type:a.PLATFORMS_MAP.mobile,vendor:`Huawei`};return t&&(n.model=t),n}},{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(e){var t=e.test(/ipod|iphone/i),n=e.test(/like (ipod|iphone)/i);return t&&!n},describe:function(e){var t=i.default.getFirstMatch(/(ipod|iphone)/i,e);return{type:a.PLATFORMS_MAP.mobile,vendor:`Apple`,model:t}}},{test:[/nexus\s*[0-6].*/i,/galaxy nexus/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:`Nexus`}}},{test:[/Nokia/i],describe:function(e){var t=i.default.getFirstMatch(/Nokia\s+([0-9]+(\.[0-9]+)?)/i,e),n={type:a.PLATFORMS_MAP.mobile,vendor:`Nokia`};return t&&(n.model=t),n}},{test:[/[^-]mobi/i],describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(e){return e.getBrowserName(!0)===`blackberry`},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:`BlackBerry`}}},{test:function(e){return e.getBrowserName(!0)===`bada`},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:function(e){return e.getBrowserName()===`windows phone`},describe:function(){return{type:a.PLATFORMS_MAP.mobile,vendor:`Microsoft`}}},{test:function(e){var t=Number(String(e.getOSVersion()).split(`.`)[0]);return e.getOSName(!0)===`android`&&t>=3},describe:function(){return{type:a.PLATFORMS_MAP.tablet}}},{test:function(e){return e.getOSName(!0)===`android`},describe:function(){return{type:a.PLATFORMS_MAP.mobile}}},{test:[/smart-?tv|smarttv/i],describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:[/netcast/i],describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:function(e){return e.getOSName(!0)===`macos`},describe:function(){return{type:a.PLATFORMS_MAP.desktop,vendor:`Apple`}}},{test:function(e){return e.getOSName(!0)===`windows`},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(e){return e.getOSName(!0)===`linux`},describe:function(){return{type:a.PLATFORMS_MAP.desktop}}},{test:function(e){return e.getOSName(!0)===`playstation 4`},describe:function(){return{type:a.PLATFORMS_MAP.tv}}},{test:function(e){return e.getOSName(!0)===`roku`},describe:function(){return{type:a.PLATFORMS_MAP.tv}}}],e.exports=t.default},95:function(e,t,n){"use strict";t.__esModule=!0,t.default=void 0;var r,i=(r=n(17))&&r.__esModule?r:{default:r},a=n(18);t.default=[{test:function(e){return e.getBrowserName(!0)===`microsoft edge`},describe:function(e){if(/\sedg\//i.test(e))return{name:a.ENGINE_MAP.Blink};var t=i.default.getFirstMatch(/edge\/(\d+(\.?_?\d+)+)/i,e);return{name:a.ENGINE_MAP.EdgeHTML,version:t}}},{test:[/trident/i],describe:function(e){var t={name:a.ENGINE_MAP.Trident},n=i.default.getFirstMatch(/trident\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){return e.test(/presto/i)},describe:function(e){var t={name:a.ENGINE_MAP.Presto},n=i.default.getFirstMatch(/presto\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:function(e){var t=e.test(/gecko/i),n=e.test(/like gecko/i);return t&&!n},describe:function(e){var t={name:a.ENGINE_MAP.Gecko},n=i.default.getFirstMatch(/gecko\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}},{test:[/(apple)?webkit\/537\.36/i],describe:function(){return{name:a.ENGINE_MAP.Blink}}},{test:[/(apple)?webkit/i],describe:function(e){var t={name:a.ENGINE_MAP.WebKit},n=i.default.getFirstMatch(/webkit\/(\d+(\.?_?\d+)+)/i,e);return n&&(t.version=n),t}}],e.exports=t.default}})}))}))(),1).default.getParser(globalThis.navigator.userAgent).getResult(),Qp=`unknown`,$p=(...e)=>e.filter(Boolean).join(` `).trim()||Qp;function em(){return typeof document<`u`&&document.hidden}function tm(){return{os:$p(Zp.os?.name,Zp.os?.version),browser:$p(Zp.browser?.name,Zp.browser?.version),loader:(()=>{let e=GM_info?.scriptHandler,t=GM_info?.version;return e&&t?`${e} v${t}`:e||t||Qp})(),scriptVersion:GM_info?.script?.version??Qp,scriptName:GM_info?.script?.name??Qp,url:globalThis?.location?.href??Qp}}var nm=class{container;accountWrapper;buttons;usernameEl;avatarEl;avatarImg;actionButton;refreshButton;tokenButton;onClick=new H;onRefresh=new H;onClickSecret=new H;events={click:this.onClick,"click:secret":this.onClickSecret,refresh:this.onRefresh};_loggedIn;_username;_avatarId;constructor({loggedIn:e=!1,username:t=`unnamed`,avatarId:n=`0/0-0`}={}){this._loggedIn=e,this._username=t,this._avatarId=n;let r=this.createElements();this.container=r.container,this.accountWrapper=r.accountWrapper,this.buttons=r.buttons,this.usernameEl=r.usernameEl,this.avatarEl=r.avatarEl,this.avatarImg=r.avatarImg,this.actionButton=r.actionButton,this.refreshButton=r.refreshButton,this.tokenButton=r.tokenButton}createElements(){let e=J.createEl(`vot-block`,[`vot-account`]),t=J.createEl(`vot-block`,[`vot-account-wrapper`]);t.hidden=!this._loggedIn;let n=J.createEl(`img`,[`vot-account-avatar-img`]);n.src=`${vi}/${this._avatarId}/islands-retina-middle`,n.loading=`lazy`,n.alt=`user avatar`;let r=J.createEl(`vot-block`,[`vot-account-avatar`],n),i=J.createEl(`vot-block`,[`vot-account-username`]);i.textContent=this._username,t.append(r,i);let a=J.createEl(`vot-block`,[`vot-account-buttons`]),o=J.createOutlinedButton(this.buttonText);o.addEventListener(`click`,()=>{this.onClick.dispatch()});let s=J.createIconButton(Pp,{ariaLabel:V.get(`VOTLoginViaToken`)});s.hidden=this._loggedIn,s.addEventListener(`click`,()=>{this.onClickSecret.dispatch()});let c=J.createIconButton(Np,{ariaLabel:V.get(`VOTRefresh`)});return c.addEventListener(`click`,()=>{this.onRefresh.dispatch()}),a.append(o,s,c),e.append(t,a),{container:e,accountWrapper:t,buttons:a,usernameEl:i,avatarImg:n,avatarEl:r,actionButton:o,refreshButton:c,tokenButton:s}}addEventListener(e,t){return Fp(this.events,e,t),this}removeEventListener(e,t){return Ip(this.events,e,t),this}get buttonText(){return this._loggedIn?V.get(`VOTLogout`):V.get(`VOTLogin`)}get loggedIn(){return this._loggedIn}set loggedIn(e){this._loggedIn=e,this.accountWrapper.hidden=!this._loggedIn,this.actionButton.textContent=this.buttonText,this.tokenButton.hidden=this._loggedIn}get avatarId(){return this._avatarId}set avatarId(e){this._avatarId=e??`0/0-0`,this.avatarImg.src=`${vi}/${this._avatarId}/islands-retina-middle`}get username(){return this._username}set username(e){this._username=e??`unnamed`,this.usernameEl.textContent=this._username}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},$=class{container;input;label;onChange=new H;events={change:this.onChange};_labelHtml;_checked;_isSubCheckbox;constructor({labelHtml:e,checked:t=!1,isSubCheckbox:n=!1}){this._labelHtml=e,this._checked=t,this._isSubCheckbox=n;let r=this.createElements();this.container=r.container,this.input=r.input,this.label=r.label}createElements(){let e=J.createEl(`label`,[`vot-checkbox`]);this._isSubCheckbox&&e.classList.add(`vot-checkbox-sub`);let t=document.createElement(`input`);t.type=`checkbox`,t.checked=this._checked,t.addEventListener(`change`,()=>{this._checked=t.checked,this.onChange.dispatch(this._checked)});let n=J.createEl(`span`);return q(this._labelHtml,n),e.append(t,n),{container:e,input:t,label:n}}addEventListener(e,t){return Fp(this.events,`change`,t),this}removeEventListener(e,t){return Ip(this.events,`change`,t),this}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get disabled(){return this.input.disabled}set disabled(e){this.input.disabled=e}get checked(){return this._checked}set checked(e){this._checked!==e&&(this._checked=this.input.checked=e,this.onChange.dispatch(this._checked))}},rm=class{container;header;arrowIcon;onClick=new H;events={click:this.onClick};_titleHtml;constructor({titleHtml:e}){this._titleHtml=e;let t=this.createElements();this.container=t.container,this.header=t.header,this.arrowIcon=t.arrowIcon}createElements(){let e=J.createEl(`vot-block`,[`vot-details`]);J.makeButtonLike(e);let t=J.createEl(`vot-block`);t.append(this._titleHtml);let n=J.createEl(`vot-block`,[`vot-details-arrow-icon`]);return q(Op,n),e.append(t,n),e.addEventListener(`click`,()=>{this.onClick.dispatch()}),{container:e,header:t,arrowIcon:n}}addEventListener(e,t){return Fp(this.events,`click`,t),this}removeEventListener(e,t){return Ip(this.events,`click`,t),this}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},im=class{container;button;onChange=new H;events={change:this.onChange};_labelHtml;_key;pressedKeys;comboKeys;recording=!1;constructor({labelHtml:e,key:t=null}){this._labelHtml=e,this._key=t,this.pressedKeys=new Set,this.comboKeys=new Set;let n=this.createElements();this.container=n.container,this.button=n.button}stopRecordingKeys(){this.recording=!1,document.removeEventListener(`keydown`,this.keydownHandle),document.removeEventListener(`keyup`,this.keyupOrBlurHandle),globalThis.removeEventListener(`blur`,this.blurHandle),delete this.button.dataset.status,this.pressedKeys.clear(),this.comboKeys.clear()}keydownHandle=e=>{if(!(!this.recording||e.repeat)){if(e.preventDefault(),e.code===`Escape`){this.key=null,this.button.textContent=this.keyText,this.stopRecordingKeys();return}this.pressedKeys.add(e.code),this.comboKeys.add(e.code),this.button.textContent=om(this.pressedKeys)}};keyupOrBlurHandle=e=>{this.recording&&(e&&(this.pressedKeys.delete(e.code),this.button.textContent=this.pressedKeys.size?om(this.pressedKeys):om(this.comboKeys),this.pressedKeys.size)||(this.key=this.comboKeys.size?am(this.comboKeys):null,this.stopRecordingKeys()))};blurHandle=()=>{this.keyupOrBlurHandle()};createElements(){let e=J.createEl(`vot-block`,[`vot-hotkey`]),t=J.createEl(`vot-block`,[`vot-hotkey-label`]);t.textContent=this._labelHtml;let n=J.createEl(`vot-block`,[`vot-hotkey-button`]);return J.makeButtonLike(n),n.textContent=this.keyText,n.addEventListener(`click`,()=>{if(this.recording){this.stopRecordingKeys(),this.button.textContent=this.keyText;return}n.dataset.status=`active`,this.recording=!0,this.pressedKeys.clear(),this.comboKeys.clear(),this.button.textContent=V.get(`PressTheKeyCombination`),document.addEventListener(`keydown`,this.keydownHandle),document.addEventListener(`keyup`,this.keyupOrBlurHandle),globalThis.addEventListener(`blur`,this.blurHandle)}),e.append(t,n),{container:e,button:n,label:t}}addEventListener(e,t){return Fp(this.events,`change`,t),this}removeEventListener(e,t){return Ip(this.events,`change`,t),this}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get key(){return this._key}get keyText(){return this._key?om(this._key):V.get(`None`)}set key(e){this._key!==e&&(this._key=e,this.button.textContent=this.keyText,this.onChange.dispatch(this._key))}};function am(e){return(Array.isArray(e)?e:Array.from(e)).map(e=>e.replace(`Key`,``).replace(`Digit`,``)).join(`+`)}function om(e){let t;t=typeof e==`string`?e.split(`+`).filter(Boolean):Array.isArray(e)?e:Array.from(e);let n=e=>{switch(e){case`ControlLeft`:case`ControlRight`:case`Control`:return`Ctrl`;case`ShiftLeft`:case`ShiftRight`:case`Shift`:return`Shift`;case`AltLeft`:case`AltRight`:case`Alt`:return`Alt`;case`MetaLeft`:case`MetaRight`:case`Meta`:return`Meta`;case`Space`:return`Space`;case`ArrowUp`:return`↑`;case`ArrowDown`:return`↓`;case`ArrowLeft`:return`←`;case`ArrowRight`:return`→`;default:return e.replace(`Key`,``).replace(`Digit`,``)}},r=e=>{let t=n(e);return t===`Ctrl`?0:t===`Alt`?1:t===`Shift`?2:t===`Meta`?3:10};return t.slice().sort((e,t)=>r(e)-r(t)).map(n).join(`+`)}var sm=[`click:bugReport`,`click:resetSettings`,`update:account`,`change:autoTranslate`,`change:autoSubtitles`,`change:showVideoVolume`,`change:audioBooster`,`change:syncVolume`,`change:useLivelyVoice`,`change:subtitlesHighlightWords`,`change:subtitlesSmartLayout`,`select:responseLanguageSubtitles`,`select:subtitlesFontFamily`,`change:proxyWorkerHost`,`change:useNewAudioPlayer`,`change:onlyBypassMediaCSP`,`change:showPiPButton`,`input:subtitlesMaxLength`,`input:subtitlesFontSize`,`input:subtitlesBackgroundOpacity`,`input:autoHideButtonDelay`,`select:proxyTranslationStatus`,`select:translationTextService`,`select:buttonPosition`,`select:menuLanguage`];function cm(){let e={};for(let t of sm)e[t]=new H;return e}var lm=30,[um,dm]=Di,fm={"default-sans":`Default Sans`,arial:`Arial`,helvetica:`Helvetica`,roboto:`Roboto`,verdana:`Verdana`,"open-sans":`Open Sans`,poppins:`Poppins`,lato:`Lato`,montserrat:`Montserrat`,barlow:`Barlow`};function pm(e){return su(e)?fm[e]:gu(e)??`Default Sans`}function mm(){return Object.keys(V.defaultLocale).filter(e=>e.startsWith(`langs.`)&&e!==`langs.auto`).map(e=>e.slice(6)).sort((e,t)=>V.getLangLabel(e).localeCompare(V.getLangLabel(t)))}function hm(e){return e===dm?V.get(`VOTOriginalVideoLanguage`):V.getLangLabel(e)}function gm(e){return[{label:hm(um),value:um,selected:e===um},{label:hm(dm),value:dm,selected:e===dm},...mm().map(t=>({label:hm(t),value:t,selected:e===t}))]}var _m=class e{static PERSIST_DELAY_MS=250;globalPortal;initialized=!1;data;videoHandler;suppressSubtitlesSmartLayoutCheckboxChange=!1;events=cm();persistTimerIds={};onAuthRefreshMessage=e=>{so(e.data)&&this.refreshAccountFromStorage()};dialog;accountButton;accountButtonRefreshTooltip;accountButtonTokenTooltip;accountStorageListenerCleanup;autoTranslateCheckbox;autoSubtitlesCheckbox;dontTranslateLanguagesCheckbox;dontTranslateLanguagesSelect;autoSetVolumeSliderLabel;autoSetVolumeCheckbox;smartDuckingCheckbox;autoSetVolumeSlider;showVideoVolumeSliderCheckbox;audioBoosterCheckbox;audioBoosterTooltip;syncVolumeCheckbox;downloadWithNameCheckbox;sendNotifyOnCompleteCheckbox;useLivelyVoiceCheckbox;useLivelyVoiceTooltip;useAudioDownloadCheckbox;useAudioDownloadCheckboxLabel;useAudioDownloadCheckboxTooltip;responseLanguageSubtitlesSelectLabel;responseLanguageSubtitlesSelect;subtitlesDownloadFormatSelectLabel;subtitlesDownloadFormatSelect;subtitlesHighlightWordsCheckbox;subtitlesSmartLayoutCheckbox;subtitlesMaxLengthSliderLabel;subtitlesMaxLengthSlider;subtitlesFontSizeSliderLabel;subtitlesFontSizeSlider;subtitlesFontFamilySelectLabel;subtitlesFontFamilySelect;subtitlesBackgroundOpacitySliderLabel;subtitlesBackgroundOpacitySlider;translateHotkeyButton;subtitlesHotkeyButton;proxyWorkerHostTextfield;proxyTranslationStatusSelectLabel;proxyTranslationStatusSelectTooltip;proxyTranslationStatusSelect;translateAPIErrorsCheckbox;useNewAudioPlayerCheckbox;useNewAudioPlayerTooltip;onlyBypassMediaCSPCheckbox;onlyBypassMediaCSPTooltip;translationTextServiceLabel;translationTextServiceSelect;translationTextServiceTooltip;detectServiceLabel;detectServiceSelect;showPiPButtonCheckbox;autoHideButtonDelaySliderLabel;autoHideButtonDelaySlider;buttonPositionSelectLabel;buttonPositionSelect;buttonPositionTooltip;menuLanguageSelectLabel;menuLanguageSelect;bugReportButton;resetSettingsButton;constructor({globalPortal:e,data:t={},videoHandler:n}){this.globalPortal=e,this.data=t,this.videoHandler=n}isInitialized(){return this.initialized}createAccordionSection(e,t={}){let n=J.createEl(`vot-block`,[`vot-settings-section`]),r=new rm({titleHtml:e});r.container.classList.add(`vot-settings-section-header`);let i=typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}`,a=`vot-settings-section-header-${i}`,o=`vot-settings-section-content-${i}`;r.container.id=a;let s=J.createEl(`vot-block`,[`vot-settings-section-content`]);s.id=o,s.setAttribute(`role`,`region`),s.setAttribute(`aria-labelledby`,a),r.container.setAttribute(`aria-controls`,o);let c=e=>{r.container.dataset.open=e?`true`:`false`,r.container.setAttribute(`aria-expanded`,e?`true`:`false`),s.hidden=!e};return c(!!t.open),r.addEventListener(`click`,()=>{c(r.container.dataset.open!==`true`)}),n.append(r.container,s),{title:e,container:n,header:r.container,content:s,setOpen:c,getOpen:()=>r.container.dataset.open===`true`}}setSubtitlesSmartLayout(e){this.data.subtitlesSmartLayout=e,B.set(`subtitlesSmartLayout`,e),L.log(`subtitlesSmartLayout value changed. New value:`,e),this.subtitlesSmartLayoutCheckbox?.checked!==e&&(this.suppressSubtitlesSmartLayoutCheckboxChange=!0,this.subtitlesSmartLayoutCheckbox.checked=e,this.suppressSubtitlesSmartLayoutCheckboxChange=!1),this.events[`change:subtitlesSmartLayout`].dispatch(e)}scheduleStoragePersist(t,n){let r=this.persistTimerIds[t];r!==void 0&&globalThis.clearTimeout(r),this.persistTimerIds[t]=globalThis.setTimeout(()=>{this.persistTimerIds[t]=void 0,B.set(t,n)},e.PERSIST_DELAY_MS)}flushStoragePersists(){for(let e of Object.keys(this.persistTimerIds)){let t=this.persistTimerIds[e];if(t===void 0)continue;globalThis.clearTimeout(t),this.persistTimerIds[e]=void 0;let n=this.data[e];typeof n==`number`&&B.set(e,n)}}bindPersistedSetting({control:e,event:t,apply:n,storageKey:r,readPersistedValue:i,logLabel:a,dispatch:o,afterPersist:s}){e.addEventListener(t,async e=>{n(e),await B.set(r,i()),L.log(`${a} value changed. New value:`,e),s&&await s(e),o?.(e)})}createSettingsSections(){let e=[this.createAccordionSection(V.get(`VOTMyAccount`),{open:!0}),this.createAccordionSection(V.get(`translationSettings`),{open:!0}),this.createAccordionSection(V.get(`subtitlesSettings`)),this.createAccordionSection(V.get(`hotkeysSettings`)),this.createAccordionSection(V.get(`proxySettings`)),this.createAccordionSection(V.get(`miscSettings`)),this.createAccordionSection(V.get(`appearance`)),this.createAccordionSection(V.get(`aboutExtension`))];return{accountSection:e[0],translationSection:e[1],subtitlesSection:e[2],hotkeysSection:e[3],proxySection:e[4],miscSection:e[5],appearanceSection:e[6],aboutSection:e[7],sections:e}}initAccountControls(){this.accountButton=new nm({avatarId:this.data.account?.avatarId,username:this.data.account?.username,loggedIn:!!this.data.account?.token}),B.isSupportOnlyLS?(this.accountButton.refreshButton.setAttribute(`disabled`,`true`),this.accountButton.actionButton.setAttribute(`disabled`,`true`)):this.accountButtonRefreshTooltip=new Y({target:this.accountButton.refreshButton,content:V.get(`VOTRefresh`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),this.accountButtonTokenTooltip=new Y({target:this.accountButton.tokenButton,content:V.get(`VOTLoginViaToken`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})}bindAccountStorageListener(){this.accountStorageListenerCleanup?.(),this.accountStorageListenerCleanup=B.addValueChangeListener(`account`,(e,t,n)=>{this.data.account=n??{},!(!this.isInitialized()||!this.accountButton)&&this.updateAccountInfo()})}async refreshAccountFromStorage(){B.isSupportOnlyLS||(this.data.account=await B.get(`account`,{}),!(!this.isInitialized()||!this.accountButton)&&this.updateAccountInfo())}buildSubtitleFontItems(e,t=[]){let n=tu.map(t=>({label:fm[t],value:t,selected:t===e})),r=t.filter(e=>{let t=e.toLowerCase();return!n.some(e=>e.label.toLowerCase()===t)}).map(t=>{let n=hu(t);return{label:t,value:n,selected:n===e}});if(!su(e)&&!r.some(t=>t.value===e)){let t=gu(e);t&&r.unshift({label:t,value:e,selected:!0})}return[...n,...r]}async searchSubtitleFontItems(e,t){let n=Array.from(this.subtitlesFontFamilySelect?.selectedValues??[])[0]??t,r=e.trim().toLowerCase();if(!r)return this.buildSubtitleFontItems(n);let i=(await xu()).filter(e=>e.toLowerCase().includes(r)).slice(0,lm);return this.buildSubtitleFontItems(n,i)}initUI(){if(this.isInitialized())throw Error(`[VOT] SettingsView is already initialized`);this.dialog=new Bp({titleHtml:V.get(`VOTSettings`)}),this.globalPortal.appendChild(this.dialog.container);let{accountSection:e,translationSection:t,subtitlesSection:n,hotkeysSection:r,proxySection:i,miscSection:a,appearanceSection:o,aboutSection:s,sections:c}=this.createSettingsSections();this.dialog.bodyContainer.append(...c.map(e=>e.container)),this.initAccountControls(),this.autoTranslateCheckbox=new $({labelHtml:V.get(`VOTAutoTranslate`),checked:this.data.autoTranslate}),this.autoSubtitlesCheckbox=new $({labelHtml:V.get(`VOTAutoSubtitles`),checked:this.data.autoSubtitles});let l=this.data.dontTranslateLanguages??[];this.dontTranslateLanguagesCheckbox=new $({labelHtml:V.get(`DontTranslateSelectedLanguages`),checked:this.data.enabledDontTranslateLanguages}),this.dontTranslateLanguagesSelect=new Q({dialogParent:this.globalPortal,dialogTitle:V.get(`DontTranslateSelectedLanguages`),selectTitle:l.map(e=>V.get(`langs.${e}`)).join(`, `)||V.get(`DontTranslateSelectedLanguages`),items:Q.genLanguageItems(bn).map(e=>({...e,selected:l.includes(e.value)})),multiSelect:!0,labelElement:this.dontTranslateLanguagesCheckbox.container}),this.dontTranslateLanguagesSelect.disabled=!this.dontTranslateLanguagesCheckbox.checked;let u=this.data.autoVolume??15;this.autoSetVolumeSliderLabel=new Gp({labelText:V.get(`VOTAutoSetVolume`),value:u}),this.autoSetVolumeCheckbox=new $({labelHtml:this.autoSetVolumeSliderLabel.container,checked:this.data.enabledAutoVolume??!0}),this.autoSetVolumeSlider=new Up({labelHtml:this.autoSetVolumeCheckbox.container,value:u,min:0});let d=!!this.data.syncVolume;this.autoSetVolumeSlider.disabled=!this.autoSetVolumeCheckbox.checked,this.smartDuckingCheckbox=new $({labelHtml:V.get(`smartDucking`),checked:this.data.enabledSmartDucking??!0}),this.smartDuckingCheckbox.disabled=d||!this.autoSetVolumeCheckbox.checked,this.showVideoVolumeSliderCheckbox=new $({labelHtml:V.get(`showVideoVolumeSlider`),checked:this.data.showVideoSlider}),this.audioBoosterCheckbox=new $({labelHtml:V.get(`VOTAudioBooster`),checked:this.data.audioBooster}),this.videoHandler?.isAudioContextSupported||(this.audioBoosterCheckbox.disabled=!0,this.audioBoosterTooltip=new Y({target:this.audioBoosterCheckbox.container,content:V.get(`VOTNeedWebAudioAPI`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.syncVolumeCheckbox=new $({labelHtml:V.get(`VOTSyncVolume`),checked:this.data.syncVolume}),this.downloadWithNameCheckbox=new $({labelHtml:V.get(`VOTDownloadWithName`),checked:this.data.downloadWithName}),this.downloadWithNameCheckbox.disabled=!La,this.sendNotifyOnCompleteCheckbox=new $({labelHtml:V.get(`VOTSendNotifyOnComplete`),checked:this.data.sendNotifyOnComplete}),this.useLivelyVoiceCheckbox=new $({labelHtml:V.get(`VOTUseLivelyVoice`),checked:this.data.useLivelyVoice}),this.useLivelyVoiceTooltip=new Y({target:this.useLivelyVoiceCheckbox.container,content:V.get(`VOTAccountRequired`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal,hidden:!!this.data.account?.token}),this.data.account?.token||(this.useLivelyVoiceCheckbox.disabled=!0),this.useAudioDownloadCheckboxLabel=new zp({labelText:V.get(`VOTUseAudioDownload`),icon:jp}),this.useAudioDownloadCheckbox=new $({labelHtml:this.useAudioDownloadCheckboxLabel.container,checked:this.data.useAudioDownload}),La||(this.useAudioDownloadCheckbox.disabled=!0),this.useAudioDownloadCheckboxTooltip=new Y({target:this.useAudioDownloadCheckboxLabel.container,content:V.get(`VOTUseAudioDownloadWarning`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),e.content.append(this.accountButton.container),t.content.append(this.autoTranslateCheckbox.container,this.autoSubtitlesCheckbox.container,this.dontTranslateLanguagesSelect.container,this.autoSetVolumeSlider.container,this.smartDuckingCheckbox.container,this.showVideoVolumeSliderCheckbox.container,this.audioBoosterCheckbox.container,this.syncVolumeCheckbox.container,this.downloadWithNameCheckbox.container,this.sendNotifyOnCompleteCheckbox.container,this.useLivelyVoiceCheckbox.container,this.useAudioDownloadCheckbox.container),this.subtitlesDownloadFormatSelectLabel=new zp({labelText:V.get(`VOTSubtitlesDownloadFormat`)}),this.subtitlesDownloadFormatSelect=new Q({selectTitle:this.data.subtitlesDownloadFormat??V.get(`VOTSubtitlesDownloadFormat`),dialogTitle:V.get(`VOTSubtitlesDownloadFormat`),dialogParent:this.globalPortal,labelElement:this.subtitlesDownloadFormatSelectLabel.container,items:eu.map(e=>({label:e.toUpperCase(),value:e,selected:e===this.data.subtitlesDownloadFormat}))});let f=this.data.responseLanguageSubtitles??um;this.responseLanguageSubtitlesSelectLabel=new zp({labelText:V.get(`VOTDefaultSubtitlesLanguage`)}),this.responseLanguageSubtitlesSelect=new Q({selectTitle:hm(f),dialogTitle:V.get(`VOTDefaultSubtitlesLanguage`),dialogParent:this.globalPortal,labelElement:this.responseLanguageSubtitlesSelectLabel.container,items:gm(f)}),this.subtitlesHighlightWordsCheckbox=new $({labelHtml:V.get(`VOTHighlightWords`),checked:this.data.highlightWords});let p=this.data.subtitlesSmartLayout??!0;this.subtitlesSmartLayoutCheckbox=new $({labelHtml:V.get(`subtitlesSmartLayout`),checked:p});let m=this.data.subtitlesMaxLength??300;this.subtitlesMaxLengthSliderLabel=new Gp({labelText:V.get(`VOTSubtitlesMaxLength`),labelEOL:`:`,value:m,symbol:``}),this.subtitlesMaxLengthSlider=new Up({labelHtml:this.subtitlesMaxLengthSliderLabel.container,value:m,min:50,max:300});let h=this.data.subtitlesFontSize??20;this.subtitlesFontSizeSliderLabel=new Gp({labelText:V.get(`VOTSubtitlesFontSize`),labelEOL:`:`,value:h,symbol:`px`}),this.subtitlesFontSizeSlider=new Up({labelHtml:this.subtitlesFontSizeSliderLabel.container,value:h,min:8,max:50});let g=typeof this.data.subtitlesFontFamily==`string`?this.data.subtitlesFontFamily:void 0,_=g&&(su(g)||gu(g))?g:`default-sans`;this.subtitlesFontFamilySelectLabel=new zp({labelText:V.get(`VOTSubtitlesFont`)}),this.subtitlesFontFamilySelect=new Q({selectTitle:pm(_),dialogTitle:V.get(`VOTSubtitlesFont`),dialogParent:this.globalPortal,labelElement:this.subtitlesFontFamilySelectLabel.container,items:this.buildSubtitleFontItems(_),searchItemsProvider:e=>this.searchSubtitleFontItems(e,_)}),this.subtitlesFontFamilySelect.addEventListener(`selectItem`,e=>{this.subtitlesFontFamilySelect&&(this.subtitlesFontFamilySelect.updateItems(this.buildSubtitleFontItems(e)),this.subtitlesFontFamilySelect.selectTitle=pm(e))});let v=this.data.subtitlesOpacity??20;this.subtitlesBackgroundOpacitySliderLabel=new Gp({labelText:V.get(`VOTSubtitlesOpacity`),labelEOL:`:`,value:v,symbol:`%`}),this.subtitlesBackgroundOpacitySlider=new Up({labelHtml:this.subtitlesBackgroundOpacitySliderLabel.container,value:v,min:0,max:100}),n.content.append(this.responseLanguageSubtitlesSelect.container,this.subtitlesDownloadFormatSelect.container,this.subtitlesFontFamilySelect.container,this.subtitlesHighlightWordsCheckbox.container,this.subtitlesSmartLayoutCheckbox.container,this.subtitlesMaxLengthSlider.container,this.subtitlesFontSizeSlider.container,this.subtitlesBackgroundOpacitySlider.container),this.translateHotkeyButton=new im({labelHtml:V.get(`translateVideo`),key:this.data.translationHotkey}),this.subtitlesHotkeyButton=new im({labelHtml:V.get(`VOTSubtitles`),key:this.data.subtitlesHotkey}),r.content.append(this.translateHotkeyButton.container,this.subtitlesHotkeyButton.container),this.proxyWorkerHostTextfield=new Vp({labelHtml:V.get(`VOTProxyWorkerHost`),value:this.data.proxyWorkerHost,placeholder:pi});let ee=[V.get(`VOTTranslateProxyDisabled`),V.get(`VOTTranslateProxyEnabled`),V.get(`VOTTranslateProxyEverything`)],te=this.data.translateProxyEnabled??0,ne=$g&&wi.includes($g);this.proxyTranslationStatusSelectLabel=new zp({icon:ne?jp:void 0,labelText:V.get(`VOTTranslateProxyStatus`)}),ne&&(this.proxyTranslationStatusSelectTooltip=new Y({target:this.proxyTranslationStatusSelectLabel.icon,content:V.get(`VOTTranslateProxyStatusDefault`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.proxyTranslationStatusSelect=new Q({selectTitle:ee[te],dialogTitle:V.get(`VOTTranslateProxyStatus`),dialogParent:this.globalPortal,labelElement:this.proxyTranslationStatusSelectLabel.container,items:ee.map((e,t)=>({label:e,value:t.toString(),selected:t===te,disabled:t===0&&Fa}))}),i.content.append(this.proxyWorkerHostTextfield.container,this.proxyTranslationStatusSelect.container),this.translateAPIErrorsCheckbox=new $({labelHtml:V.get(`VOTTranslateAPIErrors`),checked:this.data.translateAPIErrors??!0}),this.translateAPIErrorsCheckbox.hidden=V.lang===`ru`,this.useNewAudioPlayerCheckbox=new $({labelHtml:V.get(`VOTNewAudioPlayer`),checked:this.data.newAudioPlayer}),this.videoHandler?.isAudioContextSupported||(this.useNewAudioPlayerCheckbox.disabled=!0,this.useNewAudioPlayerTooltip=new Y({target:this.useNewAudioPlayerCheckbox.container,content:V.get(`VOTNeedWebAudioAPI`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.onlyBypassMediaCSPCheckbox=new $({labelHtml:this.videoHandler?.site.needBypassCSP?`${V.get(`VOTOnlyBypassMediaCSP`)} (${V.get(`VOTMediaCSPEnabledOnSite`)})`:V.get(`VOTOnlyBypassMediaCSP`),checked:this.data.onlyBypassMediaCSP,isSubCheckbox:!0}),this.videoHandler?.isAudioContextSupported||(this.onlyBypassMediaCSPTooltip=new Y({target:this.onlyBypassMediaCSPCheckbox.container,content:V.get(`VOTNeedWebAudioAPI`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.onlyBypassMediaCSPCheckbox.disabled=!this.data.newAudioPlayer&&!!this.videoHandler?.isAudioContextSupported,this.data.newAudioPlayer||(this.onlyBypassMediaCSPCheckbox.hidden=!0),this.translationTextServiceLabel=new zp({labelText:V.get(`VOTTranslationTextService`),icon:Mp});let re=this.data.translationService??`yandexbrowser`;this.translationTextServiceSelect=new Q({selectTitle:V.get(`services.${re}`),dialogTitle:V.get(`VOTTranslationTextService`),dialogParent:this.globalPortal,labelElement:this.translationTextServiceLabel.container,items:gc.map(e=>({label:V.get(`services.${e}`),value:e,selected:e===re}))}),this.translationTextServiceTooltip=new Y({target:this.translationTextServiceLabel.icon,content:V.get(`VOTNotAffectToVoice`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),this.detectServiceLabel=new zp({labelText:V.get(`VOTDetectService`)});let ie=this.data.detectService??`yandexbrowser`;this.detectServiceSelect=new Q({selectTitle:V.get(`services.${ie}`),dialogTitle:V.get(`VOTDetectService`),dialogParent:this.globalPortal,labelElement:this.detectServiceLabel.container,items:xc.map(e=>({label:V.get(`services.${e}`),value:e,selected:e===ie}))}),this.showPiPButtonCheckbox=new $({labelHtml:V.get(`VOTShowPiPButton`),checked:this.data.showPiPButton}),this.showPiPButtonCheckbox.hidden=!Gi();let ae=Math.round((this.data.autoHideButtonDelay??1e3)/1e3*10)/10;this.autoHideButtonDelaySliderLabel=new Gp({labelText:V.get(`autoHideButtonDelay`),labelEOL:`:`,value:ae,symbol:` ${V.get(`secs`)}`}),this.autoHideButtonDelaySlider=new Up({labelHtml:this.autoHideButtonDelaySliderLabel.container,value:ae,min:.1,max:3,step:.1}),this.buttonPositionSelectLabel=new zp({labelText:V.get(`buttonPosition`),icon:Mp});let y=this.data.buttonPos??`default`;this.buttonPositionSelect=new Q({selectTitle:V.get(`position.${y}`),dialogTitle:V.get(`buttonPosition`),labelElement:this.buttonPositionSelectLabel.container,dialogParent:this.globalPortal,items:Xp.map(e=>({label:V.get(`position.${e}`),value:e,selected:e===y}))}),this.buttonPositionTooltip=new Y({target:this.buttonPositionSelectLabel.icon,content:V.get(`minButtonPositionContainer`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),this.menuLanguageSelectLabel=new zp({labelText:V.get(`VOTMenuLanguage`)}),this.menuLanguageSelect=new Q({selectTitle:V.get(`langs.${V.langOverride}`),dialogTitle:V.get(`VOTMenuLanguage`),labelElement:this.menuLanguageSelectLabel.container,dialogParent:this.globalPortal,items:Q.genLanguageItems(V.getAvailableLangs(),V.langOverride)}),this.bugReportButton=J.createOutlinedButton(V.get(`VOTBugReport`)),this.resetSettingsButton=J.createButton(V.get(`resetSettings`)),a.content.append(this.translateAPIErrorsCheckbox.container,this.useNewAudioPlayerCheckbox.container,this.onlyBypassMediaCSPCheckbox.container),t.content.append(this.translationTextServiceSelect.container,this.detectServiceSelect.container),o.content.append(this.showPiPButtonCheckbox.container,this.autoHideButtonDelaySlider.container,this.buttonPositionSelect.container,this.menuLanguageSelect.container);let oe=tm(),se=J.createInformation(`${V.get(`VOTVersion`)}:`,oe.scriptVersion||GM_info.script.version||V.get(`notFound`)),ce=J.createInformation(`${V.get(`VOTAuthors`)}:`,GM_info.script.author||`Toil, SashaXser, MrSoczekXD, mynovelhost, sodapng`),le=J.createInformation(`${V.get(`VOTLoader`)}:`,oe.loader),ue=J.createInformation(`${V.get(`VOTBrowser`)}:`,`${oe.browser} (${oe.os})`),de=new Date((this.data.localeUpdatedAt??0)*1e3).toLocaleString(),b=Tl`${this.data.localeHash??V.get(`notFound`)}
(${V.get(`VOTUpdatedAt`)} @@ -374,6 +467,22 @@ var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`} `;return{text:n.text,startMs:a[i]?.startMs??t,durationMs:o?0:a[i]?.durationMs??0,isWordLike:!o&&e.isWordLike,style:o?void 0:sf(r,e.index+n.startOffset,e.index+n.endOffset)}})},tv=e=>e.reduce((e,t,n)=>(t.isWordLike&&t.text.trim()&&e.push(n),e),[]),nv=(e,t)=>{if(!t.length)return e;let n=tv(e);if(!n.length)return e;let r=n.length;for(let i=0;i{if(!n)return[];if(Z_(e,t,n))return X_(e.tokens);let r=t.language,i=e.metadata?.styledSpans??of(e.metadata?.rawText??e.text??n).styledSpans,a=u_(n,r);if(!a.length)return[];let o=q_(a.map(e=>e.text),e.startMs,e.durationMs),s=[];for(let t=0;t{let n=await z(e,{timeout:7e3});return t===`vtt`||t===`srt`||t===`ass`?rp(await n.text(),t):n.json()},av=(e,t)=>t.source===`youtube`?cv.formatYoutubeSubtitles(e,!!t.isAutoGenerated):(t.format===`srt`||t.format===`vtt`||t.format,ip(H_(e))),ov=(e,t)=>{let n=cv.autoMerge(e,t);return{...n,subtitles:cv.processTokens(n,t)}},sv=e=>{let t=[],n=new Set;for(let r of e.subtitles??[])r.language&&!n.has(r.language)&&(n.add(r.language),t.push({source:`yandex`,format:`json`,language:r.language,url:r.url})),r.translatedLanguage&&t.push({source:`yandex`,format:`json`,language:r.translatedLanguage,translatedFromLanguage:r.language,url:r.translatedUrl??r.url});return t},cv={processTokens(e,t){let n=[];for(let r of e.subtitles){let e=K_(r),i=rv(r,t,e);n.push({...r,text:e,tokens:i})}return n},formatYoutubeSubtitles(e,t=!1){let n=e.events??[];if(!n.length)return console.error(`[VOT] Invalid YouTube subtitles format:`,e),{format:`json`,subtitles:[]};let r=[];for(let e=0;ee.tokens.length>0)?e:{...e,subtitles:C_(e.subtitles,t.language)}},async fetchSubtitles(e,t,n){let r=ou(e);if(!r&&D_(e)&&(r=E_(e,t,n)),!r)return{format:`json`,subtitles:[]};let{source:i,format:a}=r,{url:o}=r;i===`youtube`&&(o=O_(o));try{let e=ov(av(await iv(o,a),r),r);return L.log(`[VOT] Processed subtitles:`,e),e}catch(e){return console.error(`[VOT] Failed to process subtitles:`,e),{format:`json`,subtitles:[]}}},async getSubtitles(e,t){let{host:n,url:r,detectedLanguage:i,videoId:a,duration:o,subtitles:s=[]}=t;try{let t={videoData:{host:n,url:r,videoId:a,duration:o},requestLang:i},c=await Promise.race([e.getSubtitles(t),new Promise((e,t)=>{setTimeout(()=>t(Error(`Timeout`)),5e3)})]);return L.log(`[VOT] Subtitles response:`,c),c.waiting&&console.error(`[VOT] Failed to get Yandex subtitles`),I_([...sv(c),...s],i)}catch(e){let t=`Error in getSubtitles function`;throw e instanceof Error&&e.message===`Timeout`&&(t=`Failed to get Yandex subtitles: timeout`),console.error(`[VOT] ${t}`,e),e}}},lv=new WeakMap;function uv(e){let t=e.videoData;return e.getPreferredSubtitlesLanguage(t?.detectedLanguage,t?.responseLanguage)}function dv(e){let t=e.videoData;if(!t?.videoId)return null;let n=t.detectedLanguage?.toLowerCase();if(!n||n===`auto`)return null;let r=uv(e);return r?e.getSubtitlesCacheKey(t.videoId,n,r):null}async function fv(e){if(!e.videoData?.videoId)return!1;await e.videoManager.ensureDetectedLanguageForTranslation(e.videoData);let t=e.videoData.detectedLanguage?.toLowerCase();return!!(t&&t!==`auto`)}function pv(e){return[e.source,e.format,e.language,e.translatedFromLanguage??``,e.isAutoGenerated?`1`:`0`,e.url].join(`|`)}function mv(e){let t=new Set,n=[];for(let r of e){let e=pv(r);t.has(e)||(t.add(e),n.push(r))}return n}function hv(e,t){let n=e.videoData;if(!n)throw Error(`Video data is required to load subtitles`);if(e.site.host!==`youtube`||!t)return n;let r=F.getSubtitles(t);return r.length?{...n,subtitles:mv([...Array.isArray(n.subtitles)?n.subtitles:[],...r])}:n}function gv(e){let t=(lv.get(e)??0)+1;return lv.set(e,t),t}function _v(e,t){return lv.get(e)===t}function vv(e,t){return e.hasSubtitlesWidget()&&e.subtitlesWidget?.setContent(null),t.downloadSubtitlesButton.hidden=!0,e.yandexSubtitles=null,e}async function yv(e){L.log(`[onchange] subtitles`,e);let t=gv(this),n=this.uiManager.votOverlayView;if(!n?.subtitlesSelect||!n.downloadSubtitlesButton)return this;if(n.subtitlesSelect.setSelectedValue(e),e===`disabled`)return vv(this,n);let r=Yh(e);if(r==null)return vv(this,n);let i=Xh(this.subtitles,r);if(!i)return vv(this,n);let a={...i},o=Uh(a.url,{translateProxyEnabled:this.data?.translateProxyEnabled,proxyWorkerHost:this.data?.proxyWorkerHost});o!==a.url&&(a={...a,url:o},console.log(`[VOT] Subs proxied via ${a.url}`));let s=await cv.fetchSubtitles(a);return _v(this,t)?(this.yandexSubtitles=s,this.getSubtitlesWidget().setContent(this.yandexSubtitles,a.language),n.downloadSubtitlesButton.hidden=!1,this):this}async function bv(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return;let t=$h(Jh(this.subtitles));e.subtitlesSelect.updateItems(t),await this.changeSubtitlesLang(Wh)}async function xv(){if(!await fv(this))return(this.subtitlesCacheKey!==null||this.subtitles.length>0)&&(this.subtitles=[],this.subtitlesCacheKey=null,await this.updateSubtitlesLangSelect()),this;let e=dv(this);if(!e)return(this.subtitlesCacheKey!==null||this.subtitles.length>0)&&(this.subtitles=[],this.subtitlesCacheKey=null,await this.updateSubtitlesLangSelect()),this;if(this.subtitlesCacheKey===e){let t=this.cacheManager.getSubtitles(e)!==void 0;if(this.subtitles.length>0||t)return this}let t=this.cacheManager.getSubtitles(e);return t===void 0?(await this.loadSubtitles(),this):(this.subtitles=Array.isArray(t)?t:[],this.subtitlesCacheKey=e,await this.updateSubtitlesLangSelect(),this)}async function Sv(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return this;try{await xv.call(this)}catch{return this}let t=this.videoData?.detectedLanguage??this.translateFromLang,n=uv(this);if(!n)return this;let r=ag(Jh(this.subtitles),t,n);return r==null||eg(e.subtitlesSelect.selectedValues)===String(r)||await this.changeSubtitlesLang(String(r)),this}async function Cv(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return this;let t=eg(e.subtitlesSelect.selectedValues);return t&&t!==`disabled`?(await this.changeSubtitlesLang(Wh),this):(await this.enableSubtitlesForCurrentLangPair(),this)}async function wv(){if(!this.videoData?.videoId){console.error(`[VOT] ${V.getDefault(`VOTNoVideoIDFound`)}`),this.subtitles=[],this.subtitlesCacheKey=null;return}if(!await fv(this)){this.subtitles=[],this.subtitlesCacheKey=null,await this.updateSubtitlesLangSelect();return}let e=uv(this);if(!e){this.subtitles=[],this.subtitlesCacheKey=null,await this.updateSubtitlesLangSelect();return}let t=this.getSubtitlesCacheKey(this.videoData.videoId,this.videoData.detectedLanguage,e);try{let n=this.cacheManager.getSubtitles(t);if(!n){let r=this.subtitlesLoadPromises.get(t);if(r===void 0){let n=hv(this,e);r=cv.getSubtitles(this.votClient,n),this.subtitlesLoadPromises.set(t,r)}try{n=await r,n=Array.isArray(n)?n:[],this.cacheManager.setSubtitles(t,n)}finally{this.subtitlesLoadPromises.get(t)===r&&this.subtitlesLoadPromises.delete(t)}}this.subtitles=Array.isArray(n)?n:[],this.subtitlesCacheKey=t}catch(e){console.error(`[VOT] Failed to load subtitles:`,e),this.subtitles=[],this.subtitlesCacheKey=null}await this.updateSubtitlesLangSelect()}new Set(xn);var Tv=Promise.resolve(),Ev=class{video;container;site;translateFromLang=`auto`;translateToLang=Pi;data;videoData;firstPlay=!0;audioContext;votClient;audioPlayer;abortController;actionsAbortController;actionsGeneration=0;notifier=new Lm;cacheManager;votSessionStorage=new fa;subtitlesLoadPromises=new Map;downloadTranslationUrl=null;isRefreshingTranslation=!1;autoRetry;votOpts;volumeOnStart;volumeLinkState={initialized:!1,lastVideoPercent:0,lastTranslationPercent:0};internalVideoVolumeSetAt=0;internalVideoVolumeSetPercent=null;internalVideoVolumeSuppressionMs=250;internalVideoVolumeSetHistory=[];internalVideoVolumeSetHistoryLimit=48;smartVolumeDuckingInterval;smartVolumeDuckingTarget=.2;smartVolumeDuckingBaseline;smartVolumeLastApplied;smartVolumeLastTickAt=0;smartVolumeLastSoundAt=0;smartVolumeRmsMissingSinceAt=null;smartVolumeRmsEnvelope=0;smartVolumeSpeechGateOpen=!1;smartVolumeIsDucked=!1;longWaitingResCount=0;hadAsyncWait=!1;subtitles=[];subtitlesCacheKey=null;subtitlesWidget;activeTranslation=null;stopTranslatePromise=null;interactionChecker;uiManager;overlayVisibility;overlayVisibilityTargetsAbortController;translationOrchestrator;lifecycleController;translationHandler;videoManager;yandexSubtitles=null;resizeObserver;syncVolumeObserver;initialized=!1;mountCache;errorTranslationCache=new Map;getFullscreenOverlayRoot(){let e=document;return Po(e.fullscreenElement??e.webkitFullscreenElement,[this.container])}getOverlayMountPoints(e=this.container){let t=this.getFullscreenOverlayRoot(),{base:n,root:r,portalContainer:i,subtitlesMountContainer:a}=Vo({container:e,site:this.site,fullscreenRoot:t}),o=this.mountCache;return o?.container===e&&o.base===n&&o.subtitlesMountContainer===a&&o.fullscreenRoot===t&&(o.root.isConnected??document.documentElement.contains(o.root))?{root:o.root,portalContainer:o.portalContainer,subtitlesMountContainer:o.subtitlesMountContainer,fullscreenRoot:o.fullscreenRoot}:(this.mountCache={container:e,base:n,root:r,portalContainer:i,subtitlesMountContainer:a,fullscreenRoot:t},{root:r,portalContainer:i,subtitlesMountContainer:a,fullscreenRoot:t})}getOverlayMount(e=this.container){let{root:t,portalContainer:n,subtitlesMountContainer:r,fullscreenRoot:i}=this.getOverlayMountPoints(e);return{root:t,portalContainer:n,subtitlesMountContainer:r,tooltipLayoutRoot:i??this.tooltipLayoutRoot}}getTranslationCacheKey(e,t,n,r){let i=this.getRequestLangForTranslation(t,n),a=this.isLivelyVoiceAllowed(i,n)&&this.data?.useLivelyVoice,o=r==null?``:Ui(r);return`${e}_${i}_${n}_${a}_${o?Wi(o):`0`}`}getSubtitlesCacheKey(e,t,n){return`${e}_${t}_${n}_${!!this.data?.useLivelyVoice}`}getPreferredSubtitlesLanguage(e=this.videoData?.detectedLanguage??`auto`,t=this.videoData?.responseLanguage??this.translateToLang,n=this.data?.responseLanguageSubtitles){return ig(n,e,t)}isActionStale(e){return e?this.actionsGeneration!==e.gen||this.videoData?.videoId!==e.videoId:!1}updateVOTClientRequestSignal(){this.votClient&&(this.votClient.fetchOpts={...this.votClient.fetchOpts,signal:this.actionsAbortController.signal})}resetActionsAbortController(e){try{this.actionsAbortController?.abort(e)}catch{}this.actionsAbortController=new AbortController,this.actionsGeneration++,this.updateVOTClientRequestSignal()}constructor(e,t,n){L.log(`[VideoHandler] add video:`,e,`container:`,t,this),this.video=e,this.container=t,this.site=n,this.abortController=new AbortController,this.actionsAbortController=new AbortController,this.cacheManager=new pa,this.interactionChecker=Em(),this.interactionChecker.start(),this.uiManager=new vm({mount:this.getOverlayMount(t),data:this.data,videoHandler:this,intervalIdleChecker:this.interactionChecker}),this.overlayVisibility=new ym({checker:this.interactionChecker,getOverlayView:()=>this.uiManager.votOverlayView??null,getAutoHideDelay:()=>this.getAutoHideDelay(),isInteractiveNode:e=>this.isOverlayInteractiveNode(e)}),this.translationOrchestrator=new Ys({isFirstPlay:()=>this.firstPlay,setFirstPlay:e=>{this.firstPlay=e},isAutoTranslateEnabled:()=>!!this.data?.autoTranslate,getVideoId:()=>this.videoData?.videoId,scheduleAutoTranslate:()=>this.runAutoTranslate(),isMobileYouTubeMuted:()=>this.site.host===`youtube`&&this.site.additionalData===`mobile`&&this.video.muted,setMuteWatcher:e=>{let t=!1,n=()=>{t||(t=!0,this.video.removeEventListener(`volumechange`,r),e())},r=()=>{this.video.muted||n()};this.video.addEventListener(`volumechange`,r,{signal:this.abortController.signal}),queueMicrotask(()=>{this.video.muted||n()})}}),this.lifecycleController=new $s(ec(this,e=>this.getOverlayMount(e))),this.translationHandler=new Js(this),this.videoManager=new nl(this)}getSubtitlesWidget(){if(!this.subtitlesWidget){let{subtitlesMountContainer:e}=this.getOverlayMountPoints();this.subtitlesWidget=new jd(this.video,e,this.interactionChecker,this.tooltipLayoutRoot),this.applySavedSubtitlesWidgetSettings(this.subtitlesWidget)}return this.subtitlesWidget}applySavedSubtitlesWidgetSettings(e){this.data&&(e.setSmartLayout(typeof this.data.subtitlesSmartLayout==`boolean`?this.data.subtitlesSmartLayout:!0),typeof this.data.subtitlesMaxLength==`number`&&e.setMaxLength(this.data.subtitlesMaxLength),typeof this.data.highlightWords==`boolean`&&e.setHighlightWords(this.data.highlightWords),typeof this.data.subtitlesFontSize==`number`&&e.setFontSize(this.data.subtitlesFontSize),typeof this.data.subtitlesFontFamily==`string`&&e.setFontFamily(this.data.subtitlesFontFamily),typeof this.data.subtitlesOpacity==`number`&&e.setOpacity(this.data.subtitlesOpacity))}hasSubtitlesWidget(){return!!this.subtitlesWidget}resetSubtitlesWidget(){this.hasSubtitlesWidget()&&(this.subtitlesWidget?.release(),this.subtitlesWidget=void 0)}get uiRoot(){return this.getOverlayMountPoints().root}get portalContainer(){return this.getOverlayMountPoints().portalContainer}get tooltipLayoutRoot(){switch(this.site.host){case`kickstarter`:return document.getElementById(`react-project-header`)??void 0;case`custom`:return;default:return this.container}}getEventContainer(){return this.site.eventSelector?document.querySelector(this.site.eventSelector)??this.container:this.container}async runAutoTranslate(){await this.videoManager.videoValidator(),await this.uiManager.handleTranslationBtnClick()}getAudioContext(){if(this.audioContext)return this.audioContext;if(this.isAudioContextSupported)try{return this.audioContext=Qr(),this.audioContext}catch(e){console.warn(`[VOT] Failed to init AudioContext, falling back:`,e);return}}get isAudioContextSupported(){return globalThis.AudioContext!==void 0||globalThis.webkitAudioContext!==void 0}getPreferAudio(){return!this.getAudioContext()||!this.data||!this.data.newAudioPlayer||this.videoData?.isStream?!0:this.data.newAudioPlayer&&!this.data.onlyBypassMediaCSP?!1:!this.site.needBypassCSP}createPlayer(){let e=this.getPreferAudio();return L.log(`preferAudio:`,e),this.audioPlayer=new ri({video:this.video,debug:!1,fetchFn:z,fetchOpts:{timeout:0},preferAudio:e}),this}isLikelyInternalVideoVolumeChange(e){let t=Date.now(),n=this.internalVideoVolumeSetHistory;if(n.length>0){let r=0,i=!1;for(let a of n)t-a.at>a.suppressMs||(n[r++]=a,!i&&Math.abs(e-a.percent)<=1&&(i=!0));return n.length=r,i}return this.internalVideoVolumeSetPercent===null||t-this.internalVideoVolumeSetAt>this.internalVideoVolumeSuppressionMs?!1:Math.abs(e-this.internalVideoVolumeSetPercent)<=1}callModule(e,...t){return e.call(this,...t)}callModuleAsync(e,...t){return e.call(this,...t)}init(){return r_.call(this)}async initVOTClient(){let e=Lh(this.data??{}),t=this.data?.translateProxyEnabled===1?fi:e?Ih(this.data?.proxyWorkerHost):ui;this.votOpts={fetchFn:z,fetchOpts:{signal:this.actionsAbortController.signal,forceGmXhr:zh({...this.data,gmXhrSupported:La})},apiToken:this.data?.account?.token,hostVOT:mi,host:t},this.votClient=new(e?$t:Qt)(this.votOpts),this.votClient.sessions=await this.votSessionStorage.restore(t,this.votClient.sessions);let n=this.votClient.getSession.bind(this.votClient);return this.votClient.getSession=async e=>{let r=await n(e);return await this.votSessionStorage.persist(t,this.votClient.sessions),r},this}transformBtn(e,t){return this.uiManager.transformBtn(e,t),this}hasActiveSource(){return!!this.audioPlayer?.player?.src}initExtraEvents(){return this.callModule(Jg)}refreshOverlayMount(){this.mountCache=void 0;let e=this.getOverlayMount(this.container),t=!hp(this.uiManager.mount,e);this.uiManager.updateMount(e),t&&this.rebindOverlayVisibilityTargets()}rebindOverlayVisibilityTargets=Yg;setCanPlay(){return this.lifecycleController.setCanPlay()}isOverlayInteractiveNode(e){return this.callModule(Xg,e)}getAutoHideDelay(){return this.callModule(Zg)}changeSubtitlesLang=yv;updateSubtitlesLangSelect=bv;ensureSubtitlesForCurrentLangPair=xv;loadSubtitles=wv;enableSubtitlesForCurrentLangPair(){return this.callModuleAsync(Sv)}toggleSubtitlesForCurrentLangPair(){return this.callModuleAsync(Cv)}getRequestLangForTranslation(e,t){return this.data?.useLivelyVoice&&this.data?.account?.token&&t===`ru`?`en`:e}isLivelyVoiceAllowed(e=this.videoData?.detectedLanguage??`auto`,t=this.videoData?.responseLanguage??this.translateToLang){return!(this.getRequestLangForTranslation(e,t)!==`en`||t!==`ru`||!this.data?.account?.token)}getVideoVolume(){return this.videoManager.getVideoVolume()}setVideoVolume(e,t={}){let n=jc(e),r=typeof t.suppressSyncMs==`number`&&Number.isFinite(t.suppressSyncMs)?Math.max(0,t.suppressSyncMs):this.internalVideoVolumeSuppressionMs,i=Date.now(),a=Oc(n);return this.internalVideoVolumeSetAt=i,this.internalVideoVolumeSetPercent=a,this.internalVideoVolumeSetHistory.push({at:i,percent:a,suppressMs:r}),this.internalVideoVolumeSetHistory.length>this.internalVideoVolumeSetHistoryLimit&&this.internalVideoVolumeSetHistory.splice(0,this.internalVideoVolumeSetHistory.length-this.internalVideoVolumeSetHistoryLimit),this.videoManager.setVideoVolume(n),this}onVideoVolumeSliderSynced(e){let t=W(e);if(!this.volumeLinkState.initialized){Gm(this.volumeLinkState,t);return}this.data?.syncVolume&&this.hasActiveSource()&&!this.isLikelyInternalVideoVolumeChange(t)||Gm(this.volumeLinkState,t)}onTranslationVolumeSliderSynced(e){if(!this.volumeLinkState.initialized){Km(this.volumeLinkState,e);return}Km(this.volumeLinkState,e)}resetVolumeLinkState(e,t){Gm(this.volumeLinkState,e),Km(this.volumeLinkState,t),this.volumeLinkState.initialized=!0}clearVolumeLinkState(){this.volumeLinkState.initialized=!1,this.volumeLinkState.lastVideoPercent=0,this.volumeLinkState.lastTranslationPercent=0}isMuted(){return this.videoManager.isMuted()}syncVideoVolumeSlider(){this.videoManager.syncVideoVolumeSlider()}setSelectMenuValues(e,t){this.videoManager.setSelectMenuValues(e,t)}syncVolumeWrapper(e,t){let n=this.uiManager.votOverlayView;if(!n?.isInitialized())return;let r=n.videoVolumeSlider,i=n.translationVolumeSlider;if(!r||!i)return;let{nextVideo:a,nextTranslation:o}=Jm({state:this.volumeLinkState,fromType:e,newVolume:t,currentVideo:Number(r.value),currentTranslation:Number(i.value),translationMin:i.min,translationMax:i.max});if(typeof o==`number`){i.value=o,this.audioPlayer?.player&&(this.audioPlayer.player.volume=o/100);return}typeof a==`number`&&(r.value=a,this.setVideoVolume(a/100))}getVideoData(){return this.videoManager.getVideoData()}videoValidator(){return this.videoManager.videoValidator()}stopTranslate(){if(this.stopTranslatePromise!==null)return this.stopTranslatePromise;let e=(async()=>{if(this.audioPlayer?.player){try{this.audioPlayer.player.removeVideoEvents(),this.audioPlayer.player.src=``,await this.audioPlayer.player.clear()}catch(e){L.log(`[stopTranslate] audioPlayer cleanup error`,e)}L.log(`audioPlayer after stopTranslate`,this.audioPlayer)}this.activeTranslation=null;let e=this.uiManager.votOverlayView;e&&(e.videoVolumeSlider&&(e.videoVolumeSlider.hidden=!0),e.translationVolumeSlider&&(e.translationVolumeSlider.hidden=!0),e.downloadTranslationButton&&(e.downloadTranslationButton.hidden=!0)),this.downloadTranslationUrl=null,this.longWaitingResCount=0,this.hadAsyncWait=!1,this.transformBtn(`none`,V.get(`translateVideo`)),L.log(`Volume on start: ${this.volumeOnStart}`);let t=typeof this.smartVolumeDuckingBaseline==`number`?this.smartVolumeDuckingBaseline:this.volumeOnStart;Th(this,{restoreVolume:t}),this.volumeOnStart=void 0,this.autoRetry!==void 0&&(clearTimeout(this.autoRetry),this.autoRetry=void 0),this.resetActionsAbortController(`stopTranslate`)})().finally(()=>{this.stopTranslatePromise===e&&(this.stopTranslatePromise=null)});return this.stopTranslatePromise=e,e}waitForPendingStopTranslate(){return this.stopTranslatePromise??Tv}async updateTranslationErrorMsg(e,t){if(t?.aborted)return;let n=V.get(`translationTake`),r=V.lang;this.longWaitingResCount=e===V.get(`translationTakeAboutMinute`)?this.longWaitingResCount+1:0,L.log(`longWaitingResCount`,this.longWaitingResCount),this.longWaitingResCount>5&&(e=new U(`TranslationDelayed`)),L.log(`updateTranslationErrorMsg message`,e);let i=await this.resolveTranslationErrorDisplayMessage(e,n,r,t);t?.aborted||i===null||(this.transformBtn(`error`,i),!t?.aborted&&[`Подготавливаем перевод`,`Видео передано в обработку`,`Ожидаем перевод видео`,`Загружаем переведенное аудио`].includes(e)&&this.uiManager.votOverlayView?.votButton&&(this.uiManager.votOverlayView.votButton.loading=!0))}async resolveTranslationErrorDisplayMessage(e,t,n,r){return e?.name===`VOTLocalizedError`?e.localizedMessage:e instanceof Error?e.message:this.shouldTranslateErrorMessage(e,t,n)?await this.getTranslatedErrorMessage(e,n,r):this.stringifyTranslationError(e)}shouldTranslateErrorMessage(e,t,n){return!!this.data?.translateAPIErrors&&n!==`ru`&&!e?.includes(t)}stringifyTranslationError(e){return Array.isArray(e)?e.join(` `):String(e??``)}async getTranslatedErrorMessage(e,t,n){let r=this.uiManager.votOverlayView;if(!r?.votButton)return null;let i=Array.isArray(e)?e.join(` `):String(e),a=`${t}:${i}`,o=this.errorTranslationCache.get(a);if(o)return o;r.votButton.loading=!0;let s=await yc(i,`ru`,t);if(n?.aborted)return null;let c=Array.isArray(s)?s.join(` `):String(s);return this.errorTranslationCache.set(a,c),this.trimErrorTranslationCache(),c}trimErrorTranslationCache(){if(this.errorTranslationCache.size<=50)return;let e=this.errorTranslationCache.keys().next().value;e&&this.errorTranslationCache.delete(e)}afterUpdateTranslation(e){let t=this.uiManager.votOverlayView;if(!t?.votButton)return;let n=t.votButton.container.dataset.status===`success`;t.videoVolumeSlider&&(t.videoVolumeSlider.hidden=!this.data?.showVideoSlider||!n),t.translationVolumeSlider&&(t.translationVolumeSlider.hidden=!n),t.videoVolumeSlider&&t.translationVolumeSlider?(this.volumeLinkState.lastVideoPercent=Number(t.videoVolumeSlider.value),this.volumeLinkState.lastTranslationPercent=Number(t.translationVolumeSlider.value),this.volumeLinkState.initialized=!0):this.volumeLinkState.initialized=!1,this.videoData&&!this.videoData.isStream&&(t.downloadTranslationButton&&(t.downloadTranslationButton.hidden=!1),this.downloadTranslationUrl=e),L.log(`afterUpdateTranslation downloadTranslationUrl`,this.downloadTranslationUrl),this.data?.sendNotifyOnComplete&&this.hadAsyncWait&&n&&(this.notifier.translationCompleted(globalThis.location.hostname),this.hadAsyncWait=!1)}validateAudioUrl(e,t){return this.callModuleAsync(hg,e,t)}scheduleTranslationRefresh(){this.callModule(gg)}refreshTranslationAudio=yg;proxifyAudio(e){return this.callModule(bg,e)}unproxifyAudio(e){return this.callModule(xg,e)}handleProxySettingsChanged=Sg;isMultiMethodS3(e){return this.callModule(Cg,e)}updateTranslation=Eg;translateFunc(e,t,n,r,i){return Ag.call(this,e,t,n,r,i)}isYouTubeHosts(){return this.callModule(jg)}setupAudioSettings(){return this.callModule(Ah)}applyManualVideoVolumeOverride(e){return this.callModule(jh,e)}stopTranslation=async()=>{this.translationOrchestrator?.reset(),this.overlayVisibility?.cancel(),await this.stopTranslate(),this.syncVideoVolumeSlider()};handleSrcChanged(){return this.lifecycleController.handleSrcChanged()}async release(){L.log(`[VideoHandler] release`),this.initialized=!1;try{await this.stopTranslation()}catch(e){L.log(`[VideoHandler] stopTranslation failed during release`,e)}this.lifecycleController?.teardown(),this.abortController?.abort(),this.abortController=new AbortController,this.overlayVisibility?.release(),this.releaseExtraEvents(),this.hasSubtitlesWidget()&&(this.subtitlesWidget?.release(),this.subtitlesWidget=void 0),this.interactionChecker?.destroy(),this.uiManager.release()}collectReportInfo(){let e=tm(),t=this.videoData?.detectedLanguage??`unknown`,n=this.videoData?.responseLanguage??`unknown`,r=`
+======= +`,zp=G` + + `;function Bp(e,t,n){e[t].addListener(n)}function Vp(e,t,n){e[t].removeListener(n)}function X(e,t){e.hidden=t}function Z(e){return e.hidden}var Hp=class{button;loaderMain;loaderCircle;onClick=new H;events={click:this.onClick};_progress=0;constructor(){let e=this.createElements();this.button=e.button,this.loaderMain=e.loaderMain,this.loaderCircle=e.loaderCircle,this.progress=0}createElements(){let e=J.createIconButton(Ap,{ariaLabel:`Download translation`}),t=e.querySelector(`.vot-loader-main`);if(!t)throw Error(`[VOT] DownloadButton loader main element not found`);let n=e.querySelector(`.vot-loader-progress`);if(!n)throw Error(`[VOT] DownloadButton loader circle element not found`);return e.addEventListener(`click`,()=>{this.onClick.dispatch()}),{button:e,loaderMain:t,loaderCircle:n}}addEventListener(e,t){return Bp(this.events,`click`,t),this}removeEventListener(e,t){return Vp(this.events,`click`,t),this}get progress(){return this._progress}set progress(e){let t=Up(e);this._progress=t;let n=this.getCircleCircumference();this.loaderCircle.style.strokeDasharray=`${n}`;let r=n*(1-t/100);this.loaderCircle.style.strokeDashoffset=`${r}`,this.loaderMain.style.opacity=t===0?`1`:`0`,this.loaderCircle.style.opacity=t===0?`0`:`1`}getCircleCircumference(){let e=this.loaderCircle.r?.baseVal?.value??0;return 2*Math.PI*e}set hidden(e){X(this.button,e)}get hidden(){return Z(this.button)}};function Up(e){if(!Number.isFinite(e))return 0;let t=e<1?e*100:e;return Math.max(0,Math.min(100,Math.round(t)))}var Wp=class{container;icon;text;_labelText;_icon;constructor({labelText:e,icon:t}){this._labelText=e,this._icon=t;let n=this.createElements();this.container=n.container,this.icon=n.icon,this.text=n.text}createElements(){let e=J.createEl(`vot-block`,[`vot-label`]),t=J.createEl(`span`,[`vot-label-text`]);t.textContent=this._labelText;let n=J.createEl(`span`,[`vot-label-icon`]);return this._icon?q(this._icon,n):n.hidden=!0,e.append(t,n),{container:e,icon:n,text:t}}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},Gp=class{container;backdrop;box;contentWrapper;headerContainer;titleContainer;title;closeButton;bodyContainer;footerContainer;onClose=new H;events={close:this.onClose};previouslyFocused=null;keydownListener;adaptiveAlignObserver;adaptiveAlignRaf=null;handleViewportChange=()=>{this.scheduleAdaptiveVerticalAlign()};titleId=typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`vot-dialog-title-${Math.random().toString(36).slice(2)}`;_titleHtml;_isTemp;constructor({titleHtml:e,isTemp:t=!1}){this._titleHtml=e,this._isTemp=t;let n=this.createElements();this.container=n.container,this.backdrop=n.backdrop,this.box=n.box,this.contentWrapper=n.contentWrapper,this.headerContainer=n.headerContainer,this.titleContainer=n.titleContainer,this.title=n.title,this.closeButton=n.closeButton,this.bodyContainer=n.bodyContainer,this.footerContainer=n.footerContainer}createElements(){let e=J.createEl(`vot-block`,[`vot-dialog-container`]);this._isTemp&&e.classList.add(`vot-dialog-temp`),e.hidden=!this._isTemp,e.setAttribute(`aria-hidden`,e.hidden?`true`:`false`),e.toggleAttribute(`inert`,e.hidden);let t=J.createEl(`vot-block`,[`vot-dialog-backdrop`]),n=J.createEl(`vot-block`,[`vot-dialog`]);n.dataset.verticalAlign=`center`,n.setAttribute(`role`,`dialog`),n.setAttribute(`aria-modal`,`true`),n.tabIndex=-1;let r=J.createEl(`vot-block`,[`vot-dialog-content-wrapper`]),i=J.createEl(`vot-block`,[`vot-dialog-header-container`]),a=J.createEl(`vot-block`,[`vot-dialog-title-container`]),o=J.createEl(`vot-block`,[`vot-dialog-title`]);o.id=this.titleId,o.append(this._titleHtml),a.appendChild(o),n.setAttribute(`aria-labelledby`,this.titleId);let s=J.createIconButton(Fp,{ariaLabel:`Close`});s.classList.add(`vot-dialog-close-button`),t.addEventListener(`click`,()=>{this.close()}),s.addEventListener(`click`,()=>{this.close()}),i.append(a,s);let c=J.createEl(`vot-block`,[`vot-dialog-body-container`]),l=J.createEl(`vot-block`,[`vot-dialog-footer-container`]);return r.append(i,c,l),n.appendChild(r),e.append(t,n),n.addEventListener(`click`,e=>{e.stopPropagation()}),{container:e,backdrop:t,box:n,contentWrapper:r,headerContainer:i,titleContainer:a,title:o,closeButton:s,bodyContainer:c,footerContainer:l}}addEventListener(e,t){return Bp(this.events,`close`,t),this}removeEventListener(e,t){return Vp(this.events,`close`,t),this}open(){return this.previouslyFocused??=Fo(document),this.hidden=!1,this.attachKeydownTrap(),this.attachAdaptiveVerticalAlign(),queueMicrotask(()=>this.focusFirst()),this}remove(){return this.detachAdaptiveVerticalAlign(),this.detachKeydownTrap(),this.container.remove(),this.restoreFocus(),this.onClose.dispatch(),this}close(){return this._isTemp?this.remove():(this.detachAdaptiveVerticalAlign(),this.detachKeydownTrap(),this.hidden=!0,this.restoreFocus(),this.onClose.dispatch(),this)}attachAdaptiveVerticalAlign(){if(this.adaptiveAlignObserver){this.scheduleAdaptiveVerticalAlign();return}typeof ResizeObserver<`u`&&(this.adaptiveAlignObserver=new ResizeObserver(()=>{this.scheduleAdaptiveVerticalAlign()}),this.adaptiveAlignObserver.observe(this.contentWrapper)),globalThis.addEventListener(`resize`,this.handleViewportChange,{passive:!0}),globalThis.visualViewport&&(globalThis.visualViewport.addEventListener(`resize`,this.handleViewportChange,{passive:!0}),globalThis.visualViewport.addEventListener(`scroll`,this.handleViewportChange,{passive:!0})),this.scheduleAdaptiveVerticalAlign()}detachAdaptiveVerticalAlign(){this.adaptiveAlignObserver&&=(this.adaptiveAlignObserver.disconnect(),void 0),globalThis.removeEventListener(`resize`,this.handleViewportChange),globalThis.visualViewport?.removeEventListener(`resize`,this.handleViewportChange),globalThis.visualViewport?.removeEventListener(`scroll`,this.handleViewportChange),this.adaptiveAlignRaf!==null&&(cancelAnimationFrame(this.adaptiveAlignRaf),this.adaptiveAlignRaf=null)}scheduleAdaptiveVerticalAlign(){this.adaptiveAlignRaf!==null&&cancelAnimationFrame(this.adaptiveAlignRaf),this.adaptiveAlignRaf=requestAnimationFrame(()=>{this.adaptiveAlignRaf=null,this.updateAdaptiveVerticalAlign()})}updateAdaptiveVerticalAlign(){let e=globalThis.visualViewport?.height??globalThis.innerHeight;if(!e||e<=0)return;let t=Math.max(160,Math.round(e*.75)),n=Math.max(160,Math.round(e-32)),r=this.contentWrapper.scrollHeight,i=this.box.dataset.verticalAlign===`top`,a=t-8,o=Math.round(e*.6);(i?r>o:r>=a)?(this.box.dataset.verticalAlign=`top`,this.box.style.setProperty(`--vot-dialog-max-height`,`${n}px`)):(this.box.dataset.verticalAlign=`center`,this.box.style.setProperty(`--vot-dialog-max-height`,`${t}px`))}restoreFocus(){let e=this.previouslyFocused;this.previouslyFocused=null,e&&e instanceof HTMLElement&&document.contains(e)&&e.focus()}getFocusableElements(){return Array.from(this.container.querySelectorAll([`button:not([disabled])`,`[href]`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex='-1'])`,`[role='button']:not([aria-disabled='true'])`].join(`,`))).filter(e=>!e.hidden&&e.getClientRects().length>0)}focusFirst(){(this.getFocusableElements()[0]??this.closeButton??this.box).focus?.()}attachKeydownTrap(){this.keydownListener||(this.keydownListener=e=>{if(e.key===`Escape`){e.preventDefault(),this.close();return}if(e.key!==`Tab`)return;let t=this.getFocusableElements();if(!t.length){e.preventDefault(),this.box.focus();return}let n=t[0],r=t.at(-1)??n,i=Fo(this.container.getRootNode());e.shiftKey?(i===n||i===this.box)&&(e.preventDefault(),r.focus()):i===r&&(e.preventDefault(),n.focus())},this.container.addEventListener(`keydown`,this.keydownListener))}detachKeydownTrap(){this.keydownListener&&=(this.container.removeEventListener(`keydown`,this.keydownListener),void 0)}set hidden(e){X(this.container,e),this.container.setAttribute(`aria-hidden`,e?`true`:`false`),this.container.toggleAttribute(`inert`,e)}get hidden(){return Z(this.container)}get isDialogOpen(){return!this.container.hidden}},Kp=class{container;input;label;onInput=new H;onChange=new H;events={input:this.onInput,change:this.onChange};_labelHtml;_multiline;_placeholder;_value;constructor({labelHtml:e=``,placeholder:t=``,value:n=``,multiline:r=!1}){this._labelHtml=e,this._multiline=r,this._placeholder=t,this._value=n;let i=this.createElements();this.container=i.container,this.input=i.input,this.label=i.label}createElements(){let e=J.createEl(`vot-block`,[`vot-textfield`]),t=document.createElement(this._multiline?`textarea`:`input`);this._labelHtml||t.classList.add(`vot-show-placeholer`,`vot-show-placeholder`),t.placeholder=this._placeholder,t.value=this._value;let n=J.createEl(`span`);return n.append(this._labelHtml),e.append(t,n),t.addEventListener(`input`,()=>{this._value=this.input.value,this.onInput.dispatch(this._value)}),t.addEventListener(`change`,()=>{this._value=this.input.value,this.onChange.dispatch(this._value)}),{container:e,label:n,input:t}}addEventListener(e,t){return Bp(this.events,e,t),this}removeEventListener(e,t){return Vp(this.events,e,t),this}get value(){return this._value}set value(e){this._value!==e&&(this.input.value=this._value=e,this.onChange.dispatch(this._value))}get placeholder(){return this._placeholder}set placeholder(e){this.input.placeholder=this._placeholder=e}get disabled(){return this.input.disabled}set disabled(e){this.input.disabled=e}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},Q=class{container;outer;arrowIcon;title;dialogParent;labelElement;_selectTitle;_dialogTitle;multiSelect;baseItems;_items;searchItemsProvider;isLoading=!1;isDialogOpen=!1;searchRequestId=0;onSelectItem=new H;onBeforeOpen=new H;events={selectItem:this.onSelectItem,beforeOpen:this.onBeforeOpen};contentList;contentItemSearchDatasetKey=`votSearchLabel`;contentItemIndexDatasetKey=`votIndex`;selectedItems=[];selectedValues;constructor({selectTitle:e,dialogTitle:t,items:n,searchItemsProvider:r,labelElement:i,dialogParent:a=document.documentElement,multiSelect:o}){this._selectTitle=e,this._dialogTitle=t,this.baseItems=this.cloneItems(n),this._items=this.cloneItems(n),this.searchItemsProvider=r,this.multiSelect=o??!1,this.labelElement=i,this.dialogParent=a,this.selectedValues=this.calcSelectedValues();let s=this.createElements();this.container=s.container,this.outer=s.outer,this.arrowIcon=s.arrowIcon,this.title=s.title}cloneItems(e){return e.map(e=>({...e}))}static genLanguageItems(e,t){return e.map(e=>{let n=`langs.${e}`,r=V.get(n);return{label:r===n?e.toUpperCase():r,value:e,selected:t===e}})}multiSelectItemHandle=e=>{let t=e.value;this.selectedValues.has(t)&&this.selectedValues.size>1?this.selectedValues.delete(t):this.selectedValues.add(t),this.syncItemsSelectionState(),this.syncItemsSelectionState(this.baseItems),this.updateSelectedState(),this.onSelectItem.dispatch(Array.from(this.selectedValues))};singleSelectItemHandle=e=>{let t=e.value;this.selectedValues=new Set([t]),this.syncItemsSelectionState(),this.syncItemsSelectionState(this.baseItems),this.updateSelectedState(),this.onSelectItem.dispatch(t)};onContentItemClick=e=>{if(!(e.target instanceof HTMLElement))return;let t=e.target.closest(`.vot-select-content-item`);if(!t||t.inert||!this.contentList?.contains(t))return;let n=t.dataset[this.contentItemIndexDatasetKey];if(!n)return;let r=this._items[Number(n)];if(r){if(this.multiSelect){this.multiSelectItemHandle(r);return}this.singleSelectItemHandle(r)}};syncItemsSelectionState(e=this._items){for(let t of e)t.selected=this.selectedValues.has(t.value)}restoreBaseItems(){this._items=this.cloneItems(this.baseItems),this.syncItemsSelectionState(),this.updateSelectedState()}createDialogContentList(){let e=J.createEl(`vot-block`,[`vot-select-content-list`]);for(let[t,n]of this._items.entries()){let r=J.createEl(`vot-block`,[`vot-select-content-item`]);r.textContent=n.label,r.dataset.votSelected=n.selected===!0?`true`:`false`,r.dataset.votValue=n.value,r.dataset[this.contentItemSearchDatasetKey]=n.label.toLowerCase(),r.dataset[this.contentItemIndexDatasetKey]=String(t),n.disabled&&(r.inert=!0),e.appendChild(r)}return e.addEventListener(`click`,this.onContentItemClick),this.selectedItems=Array.from(e.children),e}createElements(){let e=J.createEl(`vot-block`,[`vot-select`]);this.labelElement?(e.classList.add(`vot-select--labeled`),e.append(this.labelElement)):e.classList.add(`vot-select--control-only`);let t=J.createEl(`vot-block`,[`vot-select-outer`]);J.makeButtonLike(t),t.setAttribute(`aria-haspopup`,`dialog`),t.setAttribute(`aria-expanded`,`false`);let n=J.createEl(`vot-block`,[`vot-select-title`]);n.textContent=this.visibleText;let r=J.createEl(`vot-block`,[`vot-select-arrow-icon`]);return q(Np,r),t.append(n,r),t.addEventListener(`click`,()=>{if(!this.disabled&&!(this.isLoading||this.isDialogOpen))try{this.isLoading=!0;let e=new Gp({titleHtml:this._dialogTitle,isTemp:!0});this.onBeforeOpen.dispatch(e),this.dialogParent.appendChild(e.container),this.isDialogOpen=!0,t.setAttribute(`aria-expanded`,`true`);let n=new Kp({labelHtml:V.get(`searchField`)});n.addEventListener(`input`,async e=>{let t=++this.searchRequestId;if(this.searchItemsProvider){let n=await this.searchItemsProvider(e);if(t!==this.searchRequestId)return;this.updateItems(n,{persist:!1})}let n=e.toLowerCase();for(let e of this.selectedItems)e.hidden=!(e.dataset[this.contentItemSearchDatasetKey]??``).includes(n)}),this.contentList=this.createDialogContentList(),e.bodyContainer.append(n.container,this.contentList),e.addEventListener(`close`,()=>{this.isDialogOpen=!1,this.restoreBaseItems(),this.selectedItems=[],this.contentList=void 0,t.setAttribute(`aria-expanded`,`false`)}),e.open()}finally{this.isLoading=!1}}),e.appendChild(t),{container:e,outer:t,arrowIcon:r,title:n}}calcSelectedValues(){return new Set(this._items.filter(e=>e.selected).map(e=>e.value))}addEventListener(e,t){return Bp(this.events,e,t),this}removeEventListener(e,t){return Vp(this.events,e,t),this}updateTitle(){return this.title.textContent=this.visibleText,this}updateSelectedState(){if(this.selectedItems.length>0)for(let e of this.selectedItems){let t=e.dataset.votValue;t!==void 0&&(e.dataset.votSelected=this.selectedValues.has(t).toString())}return this.updateTitle(),this}setSelectedValue(e){let t=Array.isArray(e)?e:[e],n;return n=this.multiSelect?t:t.length>0?[t[0]]:[],this.selectedValues=new Set(n),this.syncItemsSelectionState(),this.syncItemsSelectionState(this.baseItems),this.updateSelectedState(),this}updateItems(e,t={}){let{persist:n=!0}=t,r=this.cloneItems(e);n&&(this.baseItems=this.cloneItems(r)),this._items=r,this.selectedValues=this.calcSelectedValues(),this.updateSelectedState();let i=this.contentList?.parentElement;if(!this.contentList||!i)return this;let a=this.contentList;return this.contentList=this.createDialogContentList(),i.replaceChild(this.contentList,a),this}get visibleText(){return this.multiSelect?this._items.filter(e=>this.selectedValues.has(e.value)).map(e=>e.label).join(`, `)||this._selectTitle:this._items.find(e=>e.selected)?.label??this._selectTitle}set selectTitle(e){this._selectTitle=e,this.updateTitle()}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get disabled(){return this.outer.getAttribute(`disabled`)===`true`||this.outer.getAttribute(`aria-disabled`)===`true`}set disabled(e){if(e){this.outer.setAttribute(`disabled`,`true`);return}this.outer.removeAttribute(`disabled`)}},qp=class{container;fromSelect;directionIcon;toSelect;dialogParent;_fromSelectTitle;_fromDialogTitle;_fromItems;_toSelectTitle;_toDialogTitle;_toItems;constructor({from:{selectTitle:e=V.get(`videoLanguage`),dialogTitle:t=V.get(`videoLanguage`),items:n},to:{selectTitle:r=V.get(`translationLanguage`),dialogTitle:i=V.get(`translationLanguage`),items:a},dialogParent:o=document.documentElement}){this._fromSelectTitle=e,this._fromDialogTitle=t,this._fromItems=n,this._toSelectTitle=r,this._toDialogTitle=i,this._toItems=a,this.dialogParent=o;let s=this.createElements();this.container=s.container,this.fromSelect=s.fromSelect,this.directionIcon=s.directionIcon,this.toSelect=s.toSelect}createElements(){let e=J.createEl(`vot-block`,[`vot-lang-select`]),t=new Q({selectTitle:this._fromSelectTitle,dialogTitle:this._fromDialogTitle,items:this._fromItems,dialogParent:this.dialogParent}),n=J.createEl(`vot-block`,[`vot-lang-select-icon`]);q(Pp,n);let r=new Q({selectTitle:this._toSelectTitle,dialogTitle:this._toDialogTitle,items:this._toItems,dialogParent:this.dialogParent});return e.append(t.container,n,r.container),{container:e,fromSelect:t,directionIcon:n,toSelect:r}}setSelectedValues(e,t){return this.fromSelect.setSelectedValue(e),this.toSelect.setSelectedValue(t),this}updateItems(e,t){return this._fromItems=e,this._toItems=t,this.fromSelect=this.fromSelect.updateItems(e),this.toSelect=this.toSelect.updateItems(t),this}},Jp=class{container;input;label;onInput=new H;_labelHtml;_value;_min;_max;_step;constructor({labelHtml:e,value:t=50,min:n=0,max:r=100,step:i=1}){this._labelHtml=e,this._value=t,this._min=n,this._max=r,this._step=i;let a=this.createElements();this.container=a.container,this.input=a.input,this.label=a.label,this.update()}updateProgress(){let e=this._max-this._min,t=e<=0?0:(this._value-this._min)/e,n=Math.max(0,Math.min(1,t));return this.container.style.setProperty(`--vot-progress`,n.toString()),this}update(){return this._value=this.input.valueAsNumber,this._min=+this.input.min,this._max=+this.input.max,this.updateProgress(),this}createElements(){let e=J.createEl(`vot-block`,[`vot-slider`]),t=document.createElement(`input`);t.type=`range`,t.min=this._min.toString(),t.max=this._max.toString(),t.step=this._step.toString(),t.value=this._value.toString();let n=J.createEl(`span`);return q(this._labelHtml,n),e.append(t,n),t.addEventListener(`input`,()=>{this.update(),this.onInput.dispatch(this._value,!1)}),{container:e,label:n,input:t}}addEventListener(e,t){return this.onInput.addListener(t),this}removeEventListener(e,t){return this.onInput.removeListener(t),this}get value(){return this._value}set value(e){this._value=Yp(e,this._min,this._max),this.input.value=this._value.toString(),this.updateProgress(),this.onInput.dispatch(this._value,!0)}get min(){return this._min}set min(e){this._min=e,this.input.min=this._min.toString(),this._value=Yp(this._value,this._min,this._max),this.input.value=this._value.toString(),this.updateProgress()}get max(){return this._max}set max(e){this._max=e,this.input.max=this._max.toString(),this._value=Yp(this._value,this._min,this._max),this.input.value=this._value.toString(),this.updateProgress()}get step(){return this._step}set step(e){this._step=e,this.input.step=this._step.toString()}get disabled(){return this.input.disabled}set disabled(e){this.input.disabled=e}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}};function Yp(e,t,n){return!Number.isFinite(e)||n=66?`right`:`default`:`default`}static calcDirection(e){return[`default`,`top`].includes(e)?`row`:`column`}createElements(){let e=J.createEl(`vot-block`,[`vot-segmented-button`]);e.dataset.position=this._position,e.dataset.direction=this._direction,e.dataset.status=this._status;let t=J.createEl(`vot-block`,[`vot-segment`,`vot-translate-button`]);t.setAttribute(`role`,`button`),t.tabIndex=0,t.setAttribute(`aria-label`,this._labelText||`Translate`),q(Dp,t);let n=J.createEl(`span`,[`vot-segment-label`]);n.textContent=this._labelText,t.appendChild(n);let r=J.createEl(`vot-block`,[`vot-separator`]),i=J.createEl(`vot-block`,[`vot-segment-only-icon`]);i.setAttribute(`role`,`button`),i.tabIndex=0,i.setAttribute(`aria-label`,`Picture in picture`),q(Op,i);let a=J.createEl(`vot-block`,[`vot-separator`]),o=J.createEl(`vot-block`,[`vot-segment-only-icon`]);return o.setAttribute(`role`,`button`),o.tabIndex=0,o.setAttribute(`aria-label`,`Menu`),o.setAttribute(`aria-haspopup`,`dialog`),o.setAttribute(`aria-expanded`,`false`),q(kp,o),e.append(t,r,i,a,o),{container:e,translateButton:t,separator:r,pipButton:i,separator2:a,menuButton:o,label:n}}showPiPButton(e){return this.separator2.hidden=this.pipButton.hidden=!e,this}setText(e){return this._labelText=e,this.label.textContent=e,this.translateButton.setAttribute(`aria-label`,e||`Translate`),this}remove(){return this.container.remove(),this}get tooltipPos(){switch(this.position){case`left`:return`right`;case`right`:return`left`;default:return`bottom`}}set status(e){this._status=this.container.dataset.status=e}get status(){return this._status}set loading(e){this.container.dataset.loading=e.toString()}get loading(){return this.container.dataset.loading===`true`}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get position(){return this._position}set position(e){this._position=this.container.dataset.position=e}get direction(){return this._direction}set direction(e){this._direction=this.container.dataset.direction=e}set opacity(e){let t=Number.isFinite(e)?e:1;this._opacity=t;let n=t<=.01;this.container.classList.toggle(`vot-segmented-button--hidden`,n)}get opacity(){return this._opacity}},Qp=class{container;contentWrapper;headerContainer;bodyContainer;footerContainer;titleContainer;title;_position;_titleHtml;menuId=typeof crypto<`u`&&`randomUUID`in crypto?`vot-menu-${crypto.randomUUID()}`:`vot-menu-${Math.random().toString(36).slice(2)}`;titleId=typeof crypto<`u`&&`randomUUID`in crypto?`vot-menu-title-${crypto.randomUUID()}`:`vot-menu-title-${Math.random().toString(36).slice(2)}`;constructor({position:e=`default`,titleHtml:t=``}){this._position=e,this._titleHtml=t;let n=this.createElements();this.container=n.container,this.contentWrapper=n.contentWrapper,this.headerContainer=n.headerContainer,this.bodyContainer=n.bodyContainer,this.footerContainer=n.footerContainer,this.titleContainer=n.titleContainer,this.title=n.title}createElements(){let e=J.createEl(`vot-block`,[`vot-menu`]);e.hidden=!0,e.id=this.menuId,e.dataset.position=this._position,e.setAttribute(`role`,`dialog`),e.setAttribute(`aria-modal`,`false`),e.setAttribute(`aria-hidden`,`true`),e.toggleAttribute(`inert`,!0);let t=J.createEl(`vot-block`,[`vot-menu-content-wrapper`]);e.appendChild(t);let n=J.createEl(`vot-block`,[`vot-menu-header-container`]),r=J.createEl(`vot-block`,[`vot-menu-title-container`]);n.appendChild(r);let i=J.createEl(`vot-block`,[`vot-menu-title`]);i.id=this.titleId,i.append(this._titleHtml),r.appendChild(i),e.setAttribute(`aria-labelledby`,this.titleId);let a=J.createEl(`vot-block`,[`vot-menu-body-container`]),o=J.createEl(`vot-block`,[`vot-menu-footer-container`]);return t.append(n,a,o),{container:e,contentWrapper:t,headerContainer:n,bodyContainer:a,footerContainer:o,titleContainer:r,title:i}}setText(e){return this._titleHtml=this.title.textContent=e,this}remove(){return this.container.remove(),this}set hidden(e){X(this.container,e),this.container.setAttribute(`aria-hidden`,e?`true`:`false`),this.container.toggleAttribute(`inert`,e)}get hidden(){return Z(this.container)}get position(){return this._position}set position(e){this._position=this.container.dataset.position=e}},$p=class e{static BIG_CONTAINER_WIDTH_PX=550;mount;globalPortal;abortController=null;defaultVolumePersistTimer;defaultVolumePersistDelayMs=250;dragging=!1;dragCandidate=!1;dragDirty=!1;dragStartX=0;dragStartY=0;currentClientX=0;activePointerId=null;dragThresholdPx=6;containerRect=null;dragIsBigContainer=null;checkerUnsubscribe=null;initialized=!1;data;videoHandler;intervalIdleChecker;overlayMount;events={"click:settings":new H,"click:pip":new H,"click:downloadTranslation":new H,"click:downloadSubtitles":new H,"click:translate":new H,"input:videoVolume":new H,"input:translationVolume":new H,"select:fromLanguage":new H,"select:toLanguage":new H,"select:subtitles":new H};votButton;votButtonTooltip;votMenu;downloadTranslationButton;downloadSubtitlesButton;openSettingsButton;languagePairSelect;subtitlesSelectLabel;subtitlesSelect;videoVolumeSliderLabel;videoVolumeSlider;translationVolumeSliderLabel;translationVolumeSlider;constructor({mount:e,globalPortal:t,data:n={},videoHandler:r,intervalIdleChecker:i}){this.mount=e,this.globalPortal=t,this.data=n,this.videoHandler=r,this.intervalIdleChecker=i}get root(){return this.overlayMount?.root??this.mount.root}get portalContainer(){return this.mount.portalContainer}updateMount(e){let t=this.mount.root,n=e.root;return this.mount=e,this.isInitialized()?(t!==n&&(this.overlayMount?Xl(this.overlayMount,n):(this.votButton&&n.appendChild(this.votButton.container),this.votMenu&&n.appendChild(this.votMenu.container))),this.votButtonTooltip&&t!==n&&this.votButtonTooltip.updateMount({parentElement:this.root,layoutRoot:this.overlayMount?.host}),this):this}isInitialized(){return this.initialized}calcButtonLayout(e){return this.isBigContainer&&em(e)?{direction:`column`,position:e}:{direction:`row`,position:`default`}}addEventListener(e,t){return this.events[e].addListener(t),this}removeEventListener(e,t){return this.events[e].removeListener(t),this}scheduleDefaultVolumePersist(){this.defaultVolumePersistTimer!==void 0&&globalThis.clearTimeout(this.defaultVolumePersistTimer),this.defaultVolumePersistTimer=globalThis.setTimeout(()=>{this.defaultVolumePersistTimer=void 0,this.flushDefaultVolumePersist()},this.defaultVolumePersistDelayMs)}flushDefaultVolumePersist(){this.defaultVolumePersistTimer!==void 0&&(globalThis.clearTimeout(this.defaultVolumePersistTimer),this.defaultVolumePersistTimer=void 0),typeof this.data.defaultVolume==`number`&&B.set(`defaultVolume`,this.data.defaultVolume)}initUI(e=`default`){if(this.isInitialized())throw Error(`[VOT] OverlayView is already initialized`);this.initialized=!0,this.overlayMount=Yl({parent:this.mount.root,rootClasses:[`vot-overlay-root`],hostStyles:{position:`absolute`,inset:`0`,display:`block`,"pointer-events":`none`},rootStyles:{position:`relative`,display:`block`,width:`100%`,height:`100%`,"pointer-events":`none`}});let{position:t,direction:n}=this.calcButtonLayout(e);this.votButton=new Zp({position:t,direction:n,status:`none`,labelHtml:V.get(`translateVideo`)}),this.votButton.opacity=0,this.pipButtonVisible||this.votButton.showPiPButton(!1),this.root.appendChild(this.votButton.container),this.votButtonTooltip=new Y({target:this.votButton.translateButton,content:V.get(`translateVideo`),position:this.votButton.tooltipPos,autoLayout:!1,hidden:n===`row`,bordered:!1,parentElement:this.root,layoutRoot:this.overlayMount.host}),this.votMenu=new Qp({titleHtml:V.get(`VOTSettings`),position:t}),this.root.appendChild(this.votMenu.container),this.votButton.menuButton.setAttribute(`aria-controls`,this.votMenu.container.id),this.downloadTranslationButton=new Hp,this.downloadTranslationButton.hidden=!0,this.downloadSubtitlesButton=J.createIconButton(jp,{ariaLabel:`Download subtitles`}),this.downloadSubtitlesButton.hidden=!0,this.openSettingsButton=J.createIconButton(Mp,{ariaLabel:V.get(`VOTSettings`)}),this.votMenu.headerContainer.append(this.downloadTranslationButton.button,this.downloadSubtitlesButton,this.openSettingsButton);let r=this.videoHandler?.videoData?.detectedLanguage??`en`,i=this.data.responseLanguage??`ru`;this.languagePairSelect=new qp({from:{selectTitle:V.get(`langs.${r}`),items:Q.genLanguageItems(yn,r)},to:{selectTitle:V.get(`langs.${i}`),items:Q.genLanguageItems(bn,i)},dialogParent:this.globalPortal}),this.subtitlesSelectLabel=new Wp({labelText:V.get(`VOTSubtitles`)}),this.subtitlesSelect=new Q({selectTitle:V.get(`VOTSubtitlesDisabled`),dialogTitle:V.get(`VOTSubtitles`),labelElement:this.subtitlesSelectLabel.container,dialogParent:this.globalPortal,items:[{label:V.get(`VOTSubtitlesDisabled`),value:`disabled`,selected:!0}]});let a=this.videoHandler?this.videoHandler.getVideoVolume()*100:100;this.videoVolumeSliderLabel=new Xp({labelText:V.get(`VOTVolume`),value:a}),this.videoVolumeSlider=new Jp({labelHtml:this.videoVolumeSliderLabel.container,value:a}),this.videoVolumeSlider.hidden=!this.data.showVideoSlider||this.votButton.status!==`success`;let o=this.data.defaultVolume??100;return this.translationVolumeSliderLabel=new Xp({labelText:V.get(`VOTVolumeTranslation`),value:o}),this.translationVolumeSlider=new Jp({labelHtml:this.translationVolumeSliderLabel.container,value:o,max:this.data.audioBooster&&!this.data.syncVolume?900:100}),this.translationVolumeSlider.hidden=this.votButton.status!==`success`,this.votMenu.bodyContainer.append(this.languagePairSelect.container,this.subtitlesSelect.container,this.videoVolumeSlider.container,this.translationVolumeSlider.container),this}initUIEvents(){if(!this.isInitialized())throw Error(`[VOT] OverlayView isn't initialized`);this.abortController=new AbortController;let e=this.abortController.signal;this.checkerUnsubscribe?.(),this.checkerUnsubscribe=this.intervalIdleChecker.subscribe(()=>{this.onCheckerTick()}),this.votButton.container.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation()},{signal:e});let t=e=>t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),e())},n=e=>e.isPrimary&&e.button===0,r=(e,{returnFocusToToggle:t=!1}={})=>{this.isInitialized()&&(this.votMenu.hidden=!e,this.votButton.menuButton.setAttribute(`aria-expanded`,e.toString()),this.votButtonTooltip&&(this.votButtonTooltip.hidden=e||this.votButton.direction===`row`),e?queueMicrotask(()=>this.openSettingsButton?.focus?.()):t?queueMicrotask(()=>this.votButton.menuButton.focus?.()):this.votButton.menuButton.blur())},i=()=>r(this.votMenu.hidden),a=(e=!1)=>r(!1,{returnFocusToToggle:e});this.votButton.translateButton.addEventListener(`pointerdown`,e=>{n(e)&&(a(),this.events[`click:translate`].dispatch())},{signal:e}),this.votButton.translateButton.addEventListener(`keydown`,t(()=>{a(),this.events[`click:translate`].dispatch()}),{signal:e}),this.votButton.pipButton.addEventListener(`pointerdown`,e=>{n(e)&&(a(),this.events[`click:pip`].dispatch())},{signal:e}),this.votButton.pipButton.addEventListener(`keydown`,t(()=>{a(),this.events[`click:pip`].dispatch()}),{signal:e}),this.votButton.menuButton.addEventListener(`pointerdown`,e=>{n(e)&&(e.preventDefault(),i())},{signal:e}),this.votButton.menuButton.addEventListener(`keydown`,t(i),{signal:e});let o=`none`;this.votButton.container.style.touchAction=o,this.votButton.translateButton.style.touchAction=o,this.votButton.pipButton.style.touchAction=o,this.votButton.menuButton.style.touchAction=o,this.votButton.container.addEventListener(`pointerdown`,this.onDragStart,{signal:e}),this.votButton.container.addEventListener(`pointermove`,this.onPointerMove,{signal:e}),this.votButton.container.addEventListener(`pointerup`,this.onDragEnd,{signal:e}),this.votButton.container.addEventListener(`pointercancel`,this.onDragEnd,{signal:e}),this.votButton.container.addEventListener(`lostpointercapture`,this.onDragEnd,{signal:e}),this.votMenu.container.addEventListener(`click`,e=>{e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation()},{signal:e});for(let t of[`pointerdown`,`mousedown`])this.votMenu.container.addEventListener(t,e=>{e.stopImmediatePropagation()},{signal:e});return document.addEventListener(`pointerdown`,e=>{if(this.votMenu.hidden)return;let t=e.target,n=typeof e.composedPath==`function`?e.composedPath():[],r=t&&this.votMenu.container.contains(t)||n.includes(this.votMenu.container),i=t&&this.votButton.menuButton.contains(t)||n.includes(this.votButton.menuButton),o=t&&this.votButton.container.contains(t)||n.includes(this.votButton.container),s=n.some(e=>e instanceof HTMLElement&&e.classList.contains(`vot-dialog-container`));r||i||o||s||a(!1)},{signal:e,capture:!0,passive:!0}),this.votMenu.container.addEventListener(`keydown`,e=>{if(e.key!==`Escape`)return;let t=document.documentElement.classList.contains(`vot-keyboard-nav`);e.preventDefault(),e.stopPropagation(),a(t),this.votButton.container.matches(`:hover`)||this.votMenu.container.matches(`:hover`)||this.videoHandler?.overlayVisibility?.queueAutoHide?.()},{signal:e}),this.downloadTranslationButton.addEventListener(`click`,()=>{this.events[`click:downloadTranslation`].dispatch()}),this.downloadSubtitlesButton.addEventListener(`click`,()=>{this.events[`click:downloadSubtitles`].dispatch()},{signal:e}),this.openSettingsButton.addEventListener(`click`,()=>{a(),this.events[`click:settings`].dispatch()},{signal:e}),this.languagePairSelect.fromSelect.addEventListener(`selectItem`,e=>{this.videoHandler?.videoData&&(this.videoHandler.videoData.detectedLanguage=e,this.videoHandler.videoManager.rememberUserLanguageSelection(this.videoHandler.videoData.videoId,e)),this.events[`select:fromLanguage`].dispatch(e)}),this.languagePairSelect.toSelect.addEventListener(`selectItem`,async e=>{this.videoHandler?.videoData&&(this.videoHandler.translateToLang=this.videoHandler.videoData.responseLanguage=e);let t=this.data.responseLanguage;t!==e&&(this.data.responseLanguage=e,await B.set(`responseLanguage`,this.data.responseLanguage)),this.data.enabledDontTranslateLanguages&&Array.isArray(this.data.dontTranslateLanguages)&&this.data.dontTranslateLanguages.length===1&&t!==e&&typeof t==`string`&&this.data.dontTranslateLanguages[0]===t&&(this.data.dontTranslateLanguages=[e],await B.set(`dontTranslateLanguages`,this.data.dontTranslateLanguages)),this.events[`select:toLanguage`].dispatch(e)}),this.subtitlesSelect.addEventListener(`beforeOpen`,async e=>{if(!this.videoHandler?.videoData)return;let t=this.videoHandler.getPreferredSubtitlesLanguage(this.videoHandler.videoData.detectedLanguage,this.videoHandler.videoData.responseLanguage);if(!t)return;let n=this.videoHandler.getSubtitlesCacheKey(this.videoHandler.videoData.videoId,this.videoHandler.videoData.detectedLanguage,t);if(this.videoHandler.subtitlesCacheKey===n)return;if(this.videoHandler.cacheManager.getSubtitles(n)!==void 0){await this.videoHandler.ensureSubtitlesForCurrentLangPair();return}let r=this.votButton?.loading??!1;this.votButton&&(this.votButton.loading=!0);let i=J.createInlineLoader();i.style.margin=`0 auto`,e.footerContainer.appendChild(i);try{await this.videoHandler.ensureSubtitlesForCurrentLangPair()}finally{i.remove(),this.votButton&&(this.votButton.loading=r)}}),this.subtitlesSelect.addEventListener(`selectItem`,e=>{this.events[`select:subtitles`].dispatch(e)}),this.videoVolumeSlider.addEventListener(`input`,(e,t)=>{this.videoVolumeSliderLabel&&(this.videoVolumeSliderLabel.value=e),!t&&this.events[`input:videoVolume`].dispatch(e)}),this.translationVolumeSlider.addEventListener(`input`,(e,t)=>{this.translationVolumeSliderLabel&&(this.translationVolumeSliderLabel.value=e),this.data.defaultVolume!==e&&(this.data.defaultVolume=e,this.scheduleDefaultVolumePersist()),!t&&this.events[`input:translationVolume`].dispatch(e)}),this}updateButtonLayout(e,t){return this.isInitialized()?(this.votMenu.position=e,this.votButton.position=e,this.votButton.direction=t,this.votButtonTooltip.hidden=t===`row`,this.votButtonTooltip.setPosition(this.votButton.tooltipPos),this):this}moveButton(e){if(!this.isInitialized())return this;let t=this.dragIsBigContainer??this.isBigContainer,n=Zp.calcPosition(e,t);if(n===this.votButton.position)return this;let r=Zp.calcDirection(n);return this.data.buttonPos=n,this.updateButtonLayout(n,r),this}startDragSession(e,t,n){this.dragCandidate=!0,this.dragging=!1,this.dragStartX=e,this.dragStartY=t,this.currentClientX=e,this.containerRect=this.root.getBoundingClientRect(),this.dragIsBigContainer=this.isBigContainer,this.dragDirty=!1,this.intervalIdleChecker.markActivity(n),this.intervalIdleChecker.requestImmediateTick()}queueDragTick(e){this.dragDirty||(this.dragDirty=!0,this.intervalIdleChecker.markActivity(e),this.intervalIdleChecker.requestImmediateTick())}updateDragFromMove(e,t,n){this.currentClientX=e,this.dragCandidate&&(this.dragging||Math.abs(this.currentClientX-this.dragStartX)+Math.abs(t-this.dragStartY)>=this.dragThresholdPx&&(this.dragging=!0),this.dragging&&this.queueDragTick(n))}onDragStart=e=>{!e.isPrimary||e.button!==0||(e.preventDefault(),this.activePointerId=e.pointerId,this.startDragSession(e.clientX,e.clientY,`overlay-pointer-down`))};onPointerMove=e=>{if(this.activePointerId!==e.pointerId)return;let t=this.dragging;if(this.updateDragFromMove(e.clientX,e.clientY,`overlay-pointer-move`),!t&&this.dragging)try{this.votButton?.container.setPointerCapture(e.pointerId)}catch{}this.dragging&&e.preventDefault()};applyDragFromState=()=>{if(!this.dragging||!this.dragDirty||!this.containerRect)return;let e=this.containerRect.width;if(!(e>0&&Number.isFinite(e)))return;this.dragDirty=!1;let t=this.currentClientX-this.containerRect.left,n=Math.max(0,Math.min(t,e))/e*100;this.moveButton(n)};onCheckerTick=()=>{this.applyDragFromState()};onDragEnd=e=>{if(e&&this.activePointerId!==null&&e.pointerId!==this.activePointerId)return;let t=this.activePointerId;if(t!==null)try{this.votButton?.container.hasPointerCapture(t)&&this.votButton.container.releasePointerCapture(t)}catch{}this.applyDragFromState();let n=this.dragIsBigContainer??this.isBigContainer;this.dragging&&n&&this.data.buttonPos&&B.set(`buttonPos`,this.data.buttonPos),this.dragging=!1,this.dragCandidate=!1,this.dragDirty=!1,this.containerRect=null,this.dragIsBigContainer=null,this.activePointerId=null};updateButtonOpacity(e){return!this.isInitialized()||!this.votMenu.hidden||Math.abs(this.votButton.opacity-e)>.01&&(this.votButton.opacity=e),this}doReleaseUI(){this.votButton?.remove(),this.votMenu?.remove(),this.votButtonTooltip?.release(),Zl(this.overlayMount),this.overlayMount=void 0}doReleaseUIEvents(){this.abortController?.abort(),this.abortController=null,this.checkerUnsubscribe?.(),this.checkerUnsubscribe=null,this.onDragEnd(),this.flushDefaultVolumePersist();for(let e of Object.values(this.events))e.clear()}release(){return this.isInitialized()?(this.doReleaseUIEvents(),this.doReleaseUI(),this.initialized=!1,this):this}get isBigContainer(){let t=this.videoHandler?.video?.getBoundingClientRect?.().width;if(typeof t==`number`&&Number.isFinite(t))return t>e.BIG_CONTAINER_WIDTH_PX;let n=this.videoHandler?.container?.getBoundingClientRect?.().width;return typeof n==`number`&&Number.isFinite(n)?n>e.BIG_CONTAINER_WIDTH_PX:this.root.clientWidth>e.BIG_CONTAINER_WIDTH_PX}get pipButtonVisible(){return Wi()&&!!this.data.showPiPButton}};function em(e){return e===`left`||e===`right`}var tm=[`default`,`top`,`left`,`right`],nm=`unknown`,rm=(...e)=>e.filter(Boolean).join(` `).trim()||nm;function im(){return typeof document<`u`&&document.hidden}function am(){return{os:rm(Ea.os?.name,Ea.os?.version),browser:rm(Ea.browser?.name,Ea.browser?.version),loader:(()=>{let e=GM_info?.scriptHandler,t=GM_info?.version;return e&&t?`${e} v${t}`:e||t||nm})(),scriptVersion:GM_info?.script?.version??nm,scriptName:GM_info?.script?.name??nm,url:globalThis?.location?.href??nm}}var om=class{container;accountWrapper;buttons;usernameEl;avatarEl;avatarImg;actionButton;refreshButton;tokenButton;onClick=new H;onRefresh=new H;onClickSecret=new H;events={click:this.onClick,"click:secret":this.onClickSecret,refresh:this.onRefresh};_loggedIn;_username;_avatarId;constructor({loggedIn:e=!1,username:t=`unnamed`,avatarId:n=`0/0-0`}={}){this._loggedIn=e,this._username=t,this._avatarId=n;let r=this.createElements();this.container=r.container,this.accountWrapper=r.accountWrapper,this.buttons=r.buttons,this.usernameEl=r.usernameEl,this.avatarEl=r.avatarEl,this.avatarImg=r.avatarImg,this.actionButton=r.actionButton,this.refreshButton=r.refreshButton,this.tokenButton=r.tokenButton}createElements(){let e=J.createEl(`vot-block`,[`vot-account`]),t=J.createEl(`vot-block`,[`vot-account-wrapper`]);t.hidden=!this._loggedIn;let n=J.createEl(`img`,[`vot-account-avatar-img`]);n.src=`${vi}/${this._avatarId}/islands-retina-middle`,n.loading=`lazy`,n.alt=`user avatar`;let r=J.createEl(`vot-block`,[`vot-account-avatar`],n),i=J.createEl(`vot-block`,[`vot-account-username`]);i.textContent=this._username,t.append(r,i);let a=J.createEl(`vot-block`,[`vot-account-buttons`]),o=J.createOutlinedButton(this.buttonText);o.addEventListener(`click`,()=>{this.onClick.dispatch()});let s=J.createIconButton(zp,{ariaLabel:V.get(`VOTLoginViaToken`)});s.hidden=this._loggedIn,s.addEventListener(`click`,()=>{this.onClickSecret.dispatch()});let c=J.createIconButton(Rp,{ariaLabel:V.get(`VOTRefresh`)});return c.addEventListener(`click`,()=>{this.onRefresh.dispatch()}),a.append(o,s,c),e.append(t,a),{container:e,accountWrapper:t,buttons:a,usernameEl:i,avatarImg:n,avatarEl:r,actionButton:o,refreshButton:c,tokenButton:s}}addEventListener(e,t){return Bp(this.events,e,t),this}removeEventListener(e,t){return Vp(this.events,e,t),this}get buttonText(){return this._loggedIn?V.get(`VOTLogout`):V.get(`VOTLogin`)}get loggedIn(){return this._loggedIn}set loggedIn(e){this._loggedIn=e,this.accountWrapper.hidden=!this._loggedIn,this.actionButton.textContent=this.buttonText,this.tokenButton.hidden=this._loggedIn}get avatarId(){return this._avatarId}set avatarId(e){this._avatarId=e??`0/0-0`,this.avatarImg.src=`${vi}/${this._avatarId}/islands-retina-middle`}get username(){return this._username}set username(e){this._username=e??`unnamed`,this.usernameEl.textContent=this._username}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},$=class{container;input;label;onChange=new H;events={change:this.onChange};_labelHtml;_checked;_isSubCheckbox;constructor({labelHtml:e,checked:t=!1,isSubCheckbox:n=!1}){this._labelHtml=e,this._checked=t,this._isSubCheckbox=n;let r=this.createElements();this.container=r.container,this.input=r.input,this.label=r.label}createElements(){let e=J.createEl(`label`,[`vot-checkbox`]);this._isSubCheckbox&&e.classList.add(`vot-checkbox-sub`);let t=document.createElement(`input`);t.type=`checkbox`,t.checked=this._checked,t.addEventListener(`change`,()=>{this._checked=t.checked,this.onChange.dispatch(this._checked)});let n=J.createEl(`span`);return q(this._labelHtml,n),e.append(t,n),{container:e,input:t,label:n}}addEventListener(e,t){return Bp(this.events,`change`,t),this}removeEventListener(e,t){return Vp(this.events,`change`,t),this}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get disabled(){return this.input.disabled}set disabled(e){this.input.disabled=e}get checked(){return this._checked}set checked(e){this._checked!==e&&(this._checked=this.input.checked=e,this.onChange.dispatch(this._checked))}},sm=class{container;header;arrowIcon;onClick=new H;events={click:this.onClick};_titleHtml;constructor({titleHtml:e}){this._titleHtml=e;let t=this.createElements();this.container=t.container,this.header=t.header,this.arrowIcon=t.arrowIcon}createElements(){let e=J.createEl(`vot-block`,[`vot-details`]);J.makeButtonLike(e);let t=J.createEl(`vot-block`);t.append(this._titleHtml);let n=J.createEl(`vot-block`,[`vot-details-arrow-icon`]);return q(Np,n),e.append(t,n),e.addEventListener(`click`,()=>{this.onClick.dispatch()}),{container:e,header:t,arrowIcon:n}}addEventListener(e,t){return Bp(this.events,`click`,t),this}removeEventListener(e,t){return Vp(this.events,`click`,t),this}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}},cm=class{container;button;onChange=new H;events={change:this.onChange};_labelHtml;_key;pressedKeys;comboKeys;recording=!1;constructor({labelHtml:e,key:t=null}){this._labelHtml=e,this._key=t,this.pressedKeys=new Set,this.comboKeys=new Set;let n=this.createElements();this.container=n.container,this.button=n.button}stopRecordingKeys(){this.recording=!1,document.removeEventListener(`keydown`,this.keydownHandle),document.removeEventListener(`keyup`,this.keyupOrBlurHandle),globalThis.removeEventListener(`blur`,this.blurHandle),delete this.button.dataset.status,this.pressedKeys.clear(),this.comboKeys.clear()}keydownHandle=e=>{if(!(!this.recording||e.repeat)){if(e.preventDefault(),e.code===`Escape`){this.key=null,this.button.textContent=this.keyText,this.stopRecordingKeys();return}this.pressedKeys.add(e.code),this.comboKeys.add(e.code),this.button.textContent=um(this.pressedKeys)}};keyupOrBlurHandle=e=>{this.recording&&(e&&(this.pressedKeys.delete(e.code),this.button.textContent=this.pressedKeys.size?um(this.pressedKeys):um(this.comboKeys),this.pressedKeys.size)||(this.key=this.comboKeys.size?lm(this.comboKeys):null,this.stopRecordingKeys()))};blurHandle=()=>{this.keyupOrBlurHandle()};createElements(){let e=J.createEl(`vot-block`,[`vot-hotkey`]),t=J.createEl(`vot-block`,[`vot-hotkey-label`]);t.textContent=this._labelHtml;let n=J.createEl(`vot-block`,[`vot-hotkey-button`]);return J.makeButtonLike(n),n.textContent=this.keyText,n.addEventListener(`click`,()=>{if(this.recording){this.stopRecordingKeys(),this.button.textContent=this.keyText;return}n.dataset.status=`active`,this.recording=!0,this.pressedKeys.clear(),this.comboKeys.clear(),this.button.textContent=V.get(`PressTheKeyCombination`),document.addEventListener(`keydown`,this.keydownHandle),document.addEventListener(`keyup`,this.keyupOrBlurHandle),globalThis.addEventListener(`blur`,this.blurHandle)}),e.append(t,n),{container:e,button:n,label:t}}addEventListener(e,t){return Bp(this.events,`change`,t),this}removeEventListener(e,t){return Vp(this.events,`change`,t),this}set hidden(e){X(this.container,e)}get hidden(){return Z(this.container)}get key(){return this._key}get keyText(){return this._key?um(this._key):V.get(`None`)}set key(e){this._key!==e&&(this._key=e,this.button.textContent=this.keyText,this.onChange.dispatch(this._key))}};function lm(e){return(Array.isArray(e)?e:Array.from(e)).map(e=>e.replace(`Key`,``).replace(`Digit`,``)).join(`+`)}function um(e){let t;t=typeof e==`string`?e.split(`+`).filter(Boolean):Array.isArray(e)?e:Array.from(e);let n=e=>{switch(e){case`ControlLeft`:case`ControlRight`:case`Control`:return`Ctrl`;case`ShiftLeft`:case`ShiftRight`:case`Shift`:return`Shift`;case`AltLeft`:case`AltRight`:case`Alt`:return`Alt`;case`MetaLeft`:case`MetaRight`:case`Meta`:return`Meta`;case`Space`:return`Space`;case`ArrowUp`:return`↑`;case`ArrowDown`:return`↓`;case`ArrowLeft`:return`←`;case`ArrowRight`:return`→`;default:return e.replace(`Key`,``).replace(`Digit`,``)}},r=e=>{let t=n(e);return t===`Ctrl`?0:t===`Alt`?1:t===`Shift`?2:t===`Meta`?3:10};return t.slice().sort((e,t)=>r(e)-r(t)).map(n).join(`+`)}var dm=[`click:bugReport`,`click:resetSettings`,`update:account`,`change:autoTranslate`,`change:autoSubtitles`,`change:showVideoVolume`,`change:audioBooster`,`change:syncVolume`,`change:useLivelyVoice`,`change:subtitlesHighlightWords`,`change:subtitlesSmartLayout`,`select:responseLanguageSubtitles`,`select:subtitlesFontFamily`,`change:proxyWorkerHost`,`change:useNewAudioPlayer`,`change:onlyBypassMediaCSP`,`change:showPiPButton`,`input:subtitlesMaxLength`,`input:subtitlesFontSize`,`input:subtitlesBackgroundOpacity`,`input:autoHideButtonDelay`,`select:proxyTranslationStatus`,`select:translationTextService`,`select:buttonPosition`,`select:menuLanguage`];function fm(){let e={};for(let t of dm)e[t]=new H;return e}var pm=30,[mm,hm]=Di,gm={"default-sans":`Default Sans`,arial:`Arial`,helvetica:`Helvetica`,roboto:`Roboto`,verdana:`Verdana`,"open-sans":`Open Sans`,poppins:`Poppins`,lato:`Lato`,montserrat:`Montserrat`,barlow:`Barlow`};function _m(e){return pu(e)?gm[e]:Su(e)??`Default Sans`}function vm(){return Object.keys(V.defaultLocale).filter(e=>e.startsWith(`langs.`)&&e!==`langs.auto`).map(e=>e.slice(6)).sort((e,t)=>V.getLangLabel(e).localeCompare(V.getLangLabel(t)))}function ym(e){return e===hm?V.get(`VOTOriginalVideoLanguage`):V.getLangLabel(e)}function bm(e){return[{label:ym(mm),value:mm,selected:e===mm},{label:ym(hm),value:hm,selected:e===hm},...vm().map(t=>({label:ym(t),value:t,selected:e===t}))]}var xm=class e{static PERSIST_DELAY_MS=250;globalPortal;initialized=!1;data;videoHandler;suppressSubtitlesSmartLayoutCheckboxChange=!1;events=fm();persistTimerIds={};onAuthRefreshMessage=e=>{uo(e.data)&&this.refreshAccountFromStorage()};dialog;accountButton;accountButtonRefreshTooltip;accountButtonTokenTooltip;accountStorageListenerCleanup;autoTranslateCheckbox;autoSubtitlesCheckbox;dontTranslateLanguagesCheckbox;dontTranslateLanguagesSelect;autoSetVolumeSliderLabel;autoSetVolumeCheckbox;smartDuckingCheckbox;autoSetVolumeSlider;showVideoVolumeSliderCheckbox;audioBoosterCheckbox;audioBoosterTooltip;syncVolumeCheckbox;downloadWithNameCheckbox;sendNotifyOnCompleteCheckbox;useLivelyVoiceCheckbox;useLivelyVoiceTooltip;useAudioDownloadCheckbox;useAudioDownloadCheckboxLabel;useAudioDownloadCheckboxTooltip;responseLanguageSubtitlesSelectLabel;responseLanguageSubtitlesSelect;subtitlesDownloadFormatSelectLabel;subtitlesDownloadFormatSelect;subtitlesHighlightWordsCheckbox;subtitlesSmartLayoutCheckbox;subtitlesMaxLengthSliderLabel;subtitlesMaxLengthSlider;subtitlesFontSizeSliderLabel;subtitlesFontSizeSlider;subtitlesFontFamilySelectLabel;subtitlesFontFamilySelect;subtitlesBackgroundOpacitySliderLabel;subtitlesBackgroundOpacitySlider;translateHotkeyButton;subtitlesHotkeyButton;proxyWorkerHostTextfield;proxyTranslationStatusSelectLabel;proxyTranslationStatusSelectTooltip;proxyTranslationStatusSelect;translateAPIErrorsCheckbox;useNewAudioPlayerCheckbox;useNewAudioPlayerTooltip;onlyBypassMediaCSPCheckbox;onlyBypassMediaCSPTooltip;translationTextServiceLabel;translationTextServiceSelect;translationTextServiceTooltip;detectServiceLabel;detectServiceSelect;showPiPButtonCheckbox;autoHideButtonDelaySliderLabel;autoHideButtonDelaySlider;buttonPositionSelectLabel;buttonPositionSelect;buttonPositionTooltip;menuLanguageSelectLabel;menuLanguageSelect;bugReportButton;resetSettingsButton;constructor({globalPortal:e,data:t={},videoHandler:n}){this.globalPortal=e,this.data=t,this.videoHandler=n}isInitialized(){return this.initialized}createAccordionSection(e,t={}){let n=J.createEl(`vot-block`,[`vot-settings-section`]),r=new sm({titleHtml:e});r.container.classList.add(`vot-settings-section-header`);let i=typeof crypto<`u`&&`randomUUID`in crypto?crypto.randomUUID():`${Date.now()}-${Math.random().toString(16).slice(2)}`,a=`vot-settings-section-header-${i}`,o=`vot-settings-section-content-${i}`;r.container.id=a;let s=J.createEl(`vot-block`,[`vot-settings-section-content`]);s.id=o,s.setAttribute(`role`,`region`),s.setAttribute(`aria-labelledby`,a),r.container.setAttribute(`aria-controls`,o);let c=e=>{r.container.dataset.open=e?`true`:`false`,r.container.setAttribute(`aria-expanded`,e?`true`:`false`),s.hidden=!e};return c(!!t.open),r.addEventListener(`click`,()=>{c(r.container.dataset.open!==`true`)}),n.append(r.container,s),{title:e,container:n,header:r.container,content:s,setOpen:c,getOpen:()=>r.container.dataset.open===`true`}}setSubtitlesSmartLayout(e){this.data.subtitlesSmartLayout=e,B.set(`subtitlesSmartLayout`,e),L.log(`subtitlesSmartLayout value changed. New value:`,e),this.subtitlesSmartLayoutCheckbox?.checked!==e&&(this.suppressSubtitlesSmartLayoutCheckboxChange=!0,this.subtitlesSmartLayoutCheckbox.checked=e,this.suppressSubtitlesSmartLayoutCheckboxChange=!1),this.events[`change:subtitlesSmartLayout`].dispatch(e)}scheduleStoragePersist(t,n){let r=this.persistTimerIds[t];r!==void 0&&globalThis.clearTimeout(r),this.persistTimerIds[t]=globalThis.setTimeout(()=>{this.persistTimerIds[t]=void 0,B.set(t,n)},e.PERSIST_DELAY_MS)}flushStoragePersists(){for(let e of Object.keys(this.persistTimerIds)){let t=this.persistTimerIds[e];if(t===void 0)continue;globalThis.clearTimeout(t),this.persistTimerIds[e]=void 0;let n=this.data[e];typeof n==`number`&&B.set(e,n)}}bindPersistedSetting({control:e,event:t,apply:n,storageKey:r,readPersistedValue:i,logLabel:a,dispatch:o,afterPersist:s}){e.addEventListener(t,async e=>{n(e),await B.set(r,i()),L.log(`${a} value changed. New value:`,e),s&&await s(e),o?.(e)})}createSettingsSections(){let e=[this.createAccordionSection(V.get(`VOTMyAccount`),{open:!0}),this.createAccordionSection(V.get(`translationSettings`),{open:!0}),this.createAccordionSection(V.get(`subtitlesSettings`)),this.createAccordionSection(V.get(`hotkeysSettings`)),this.createAccordionSection(V.get(`proxySettings`)),this.createAccordionSection(V.get(`miscSettings`)),this.createAccordionSection(V.get(`appearance`)),this.createAccordionSection(V.get(`aboutExtension`))];return{accountSection:e[0],translationSection:e[1],subtitlesSection:e[2],hotkeysSection:e[3],proxySection:e[4],miscSection:e[5],appearanceSection:e[6],aboutSection:e[7],sections:e}}initAccountControls(){this.accountButton=new om({avatarId:this.data.account?.avatarId,username:this.data.account?.username,loggedIn:!!this.data.account?.token}),B.isSupportOnlyLS?(this.accountButton.refreshButton.setAttribute(`disabled`,`true`),this.accountButton.actionButton.setAttribute(`disabled`,`true`)):this.accountButtonRefreshTooltip=new Y({target:this.accountButton.refreshButton,content:V.get(`VOTRefresh`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),this.accountButtonTokenTooltip=new Y({target:this.accountButton.tokenButton,content:V.get(`VOTLoginViaToken`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})}bindAccountStorageListener(){this.accountStorageListenerCleanup?.(),this.accountStorageListenerCleanup=B.addValueChangeListener(`account`,(e,t,n)=>{this.data.account=n??{},!(!this.isInitialized()||!this.accountButton)&&this.updateAccountInfo()})}async refreshAccountFromStorage(){B.isSupportOnlyLS||(this.data.account=await B.get(`account`,{}),!(!this.isInitialized()||!this.accountButton)&&this.updateAccountInfo())}buildSubtitleFontItems(e,t=[]){let n=su.map(t=>({label:gm[t],value:t,selected:t===e})),r=t.filter(e=>{let t=e.toLowerCase();return!n.some(e=>e.label.toLowerCase()===t)}).map(t=>{let n=xu(t);return{label:t,value:n,selected:n===e}});if(!pu(e)&&!r.some(t=>t.value===e)){let t=Su(e);t&&r.unshift({label:t,value:e,selected:!0})}return[...n,...r]}async searchSubtitleFontItems(e,t){let n=Array.from(this.subtitlesFontFamilySelect?.selectedValues??[])[0]??t,r=e.trim().toLowerCase();if(!r)return this.buildSubtitleFontItems(n);let i=(await Du()).filter(e=>e.toLowerCase().includes(r)).slice(0,pm);return this.buildSubtitleFontItems(n,i)}initUI(){if(this.isInitialized())throw Error(`[VOT] SettingsView is already initialized`);this.dialog=new Gp({titleHtml:V.get(`VOTSettings`)}),this.globalPortal.appendChild(this.dialog.container);let{accountSection:e,translationSection:t,subtitlesSection:n,hotkeysSection:r,proxySection:i,miscSection:a,appearanceSection:o,aboutSection:s,sections:c}=this.createSettingsSections();this.dialog.bodyContainer.append(...c.map(e=>e.container)),this.initAccountControls(),this.autoTranslateCheckbox=new $({labelHtml:V.get(`VOTAutoTranslate`),checked:this.data.autoTranslate}),this.autoSubtitlesCheckbox=new $({labelHtml:V.get(`VOTAutoSubtitles`),checked:this.data.autoSubtitles});let l=this.data.dontTranslateLanguages??[];this.dontTranslateLanguagesCheckbox=new $({labelHtml:V.get(`DontTranslateSelectedLanguages`),checked:this.data.enabledDontTranslateLanguages}),this.dontTranslateLanguagesSelect=new Q({dialogParent:this.globalPortal,dialogTitle:V.get(`DontTranslateSelectedLanguages`),selectTitle:l.map(e=>V.get(`langs.${e}`)).join(`, `)||V.get(`DontTranslateSelectedLanguages`),items:Q.genLanguageItems(yn).map(e=>({...e,selected:l.includes(e.value)})),multiSelect:!0,labelElement:this.dontTranslateLanguagesCheckbox.container}),this.dontTranslateLanguagesSelect.disabled=!this.dontTranslateLanguagesCheckbox.checked;let u=this.data.autoVolume??15;this.autoSetVolumeSliderLabel=new Xp({labelText:V.get(`VOTAutoSetVolume`),value:u}),this.autoSetVolumeCheckbox=new $({labelHtml:this.autoSetVolumeSliderLabel.container,checked:this.data.enabledAutoVolume??!0}),this.autoSetVolumeSlider=new Jp({labelHtml:this.autoSetVolumeCheckbox.container,value:u,min:0});let d=!!this.data.syncVolume;this.autoSetVolumeSlider.disabled=!this.autoSetVolumeCheckbox.checked,this.smartDuckingCheckbox=new $({labelHtml:V.get(`smartDucking`),checked:this.data.enabledSmartDucking??!0}),this.smartDuckingCheckbox.disabled=d||!this.autoSetVolumeCheckbox.checked,this.showVideoVolumeSliderCheckbox=new $({labelHtml:V.get(`showVideoVolumeSlider`),checked:this.data.showVideoSlider}),this.audioBoosterCheckbox=new $({labelHtml:V.get(`VOTAudioBooster`),checked:this.data.audioBooster}),this.videoHandler?.isAudioContextSupported||(this.audioBoosterCheckbox.disabled=!0,this.audioBoosterTooltip=new Y({target:this.audioBoosterCheckbox.container,content:V.get(`VOTNeedWebAudioAPI`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.syncVolumeCheckbox=new $({labelHtml:V.get(`VOTSyncVolume`),checked:this.data.syncVolume}),this.downloadWithNameCheckbox=new $({labelHtml:V.get(`VOTDownloadWithName`),checked:this.data.downloadWithName}),this.downloadWithNameCheckbox.disabled=!La,this.sendNotifyOnCompleteCheckbox=new $({labelHtml:V.get(`VOTSendNotifyOnComplete`),checked:this.data.sendNotifyOnComplete}),this.useLivelyVoiceCheckbox=new $({labelHtml:V.get(`VOTUseLivelyVoice`),checked:this.data.useLivelyVoice}),this.useLivelyVoiceTooltip=new Y({target:this.useLivelyVoiceCheckbox.container,content:V.get(`VOTAccountRequired`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal,hidden:!!this.data.account?.token}),this.data.account?.token||(this.useLivelyVoiceCheckbox.disabled=!0),this.useAudioDownloadCheckboxLabel=new Wp({labelText:V.get(`VOTUseAudioDownload`),icon:Ip}),this.useAudioDownloadCheckbox=new $({labelHtml:this.useAudioDownloadCheckboxLabel.container,checked:this.data.useAudioDownload}),La||(this.useAudioDownloadCheckbox.disabled=!0),this.useAudioDownloadCheckboxTooltip=new Y({target:this.useAudioDownloadCheckboxLabel.container,content:V.get(`VOTUseAudioDownloadWarning`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),e.content.append(this.accountButton.container),t.content.append(this.autoTranslateCheckbox.container,this.autoSubtitlesCheckbox.container,this.dontTranslateLanguagesSelect.container,this.autoSetVolumeSlider.container,this.smartDuckingCheckbox.container,this.showVideoVolumeSliderCheckbox.container,this.audioBoosterCheckbox.container,this.syncVolumeCheckbox.container,this.downloadWithNameCheckbox.container,this.sendNotifyOnCompleteCheckbox.container,this.useLivelyVoiceCheckbox.container,this.useAudioDownloadCheckbox.container),this.subtitlesDownloadFormatSelectLabel=new Wp({labelText:V.get(`VOTSubtitlesDownloadFormat`)}),this.subtitlesDownloadFormatSelect=new Q({selectTitle:this.data.subtitlesDownloadFormat??V.get(`VOTSubtitlesDownloadFormat`),dialogTitle:V.get(`VOTSubtitlesDownloadFormat`),dialogParent:this.globalPortal,labelElement:this.subtitlesDownloadFormatSelectLabel.container,items:ou.map(e=>({label:e.toUpperCase(),value:e,selected:e===this.data.subtitlesDownloadFormat}))});let f=this.data.responseLanguageSubtitles??mm;this.responseLanguageSubtitlesSelectLabel=new Wp({labelText:V.get(`VOTDefaultSubtitlesLanguage`)}),this.responseLanguageSubtitlesSelect=new Q({selectTitle:ym(f),dialogTitle:V.get(`VOTDefaultSubtitlesLanguage`),dialogParent:this.globalPortal,labelElement:this.responseLanguageSubtitlesSelectLabel.container,items:bm(f)}),this.subtitlesHighlightWordsCheckbox=new $({labelHtml:V.get(`VOTHighlightWords`),checked:this.data.highlightWords});let p=this.data.subtitlesSmartLayout??!0;this.subtitlesSmartLayoutCheckbox=new $({labelHtml:V.get(`subtitlesSmartLayout`),checked:p});let m=this.data.subtitlesMaxLength??300;this.subtitlesMaxLengthSliderLabel=new Xp({labelText:V.get(`VOTSubtitlesMaxLength`),labelEOL:`:`,value:m,symbol:``}),this.subtitlesMaxLengthSlider=new Jp({labelHtml:this.subtitlesMaxLengthSliderLabel.container,value:m,min:50,max:300});let h=this.data.subtitlesFontSize??20;this.subtitlesFontSizeSliderLabel=new Xp({labelText:V.get(`VOTSubtitlesFontSize`),labelEOL:`:`,value:h,symbol:`px`}),this.subtitlesFontSizeSlider=new Jp({labelHtml:this.subtitlesFontSizeSliderLabel.container,value:h,min:8,max:50});let g=typeof this.data.subtitlesFontFamily==`string`?this.data.subtitlesFontFamily:void 0,_=g&&(pu(g)||Su(g))?g:`default-sans`;this.subtitlesFontFamilySelectLabel=new Wp({labelText:V.get(`VOTSubtitlesFont`)}),this.subtitlesFontFamilySelect=new Q({selectTitle:_m(_),dialogTitle:V.get(`VOTSubtitlesFont`),dialogParent:this.globalPortal,labelElement:this.subtitlesFontFamilySelectLabel.container,items:this.buildSubtitleFontItems(_),searchItemsProvider:e=>this.searchSubtitleFontItems(e,_)}),this.subtitlesFontFamilySelect.addEventListener(`selectItem`,e=>{this.subtitlesFontFamilySelect&&(this.subtitlesFontFamilySelect.updateItems(this.buildSubtitleFontItems(e)),this.subtitlesFontFamilySelect.selectTitle=_m(e))});let v=this.data.subtitlesOpacity??20;this.subtitlesBackgroundOpacitySliderLabel=new Xp({labelText:V.get(`VOTSubtitlesOpacity`),labelEOL:`:`,value:v,symbol:`%`}),this.subtitlesBackgroundOpacitySlider=new Jp({labelHtml:this.subtitlesBackgroundOpacitySliderLabel.container,value:v,min:0,max:100}),n.content.append(this.responseLanguageSubtitlesSelect.container,this.subtitlesDownloadFormatSelect.container,this.subtitlesFontFamilySelect.container,this.subtitlesHighlightWordsCheckbox.container,this.subtitlesSmartLayoutCheckbox.container,this.subtitlesMaxLengthSlider.container,this.subtitlesFontSizeSlider.container,this.subtitlesBackgroundOpacitySlider.container),this.translateHotkeyButton=new cm({labelHtml:V.get(`translateVideo`),key:this.data.translationHotkey}),this.subtitlesHotkeyButton=new cm({labelHtml:V.get(`VOTSubtitles`),key:this.data.subtitlesHotkey}),r.content.append(this.translateHotkeyButton.container,this.subtitlesHotkeyButton.container),this.proxyWorkerHostTextfield=new Kp({labelHtml:V.get(`VOTProxyWorkerHost`),value:this.data.proxyWorkerHost,placeholder:pi});let ee=[V.get(`VOTTranslateProxyDisabled`),V.get(`VOTTranslateProxyEnabled`),V.get(`VOTTranslateProxyEverything`)],te=this.data.translateProxyEnabled??0,ne=r_&&wi.includes(r_);this.proxyTranslationStatusSelectLabel=new Wp({icon:ne?Ip:void 0,labelText:V.get(`VOTTranslateProxyStatus`)}),ne&&(this.proxyTranslationStatusSelectTooltip=new Y({target:this.proxyTranslationStatusSelectLabel.icon,content:V.get(`VOTTranslateProxyStatusDefault`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.proxyTranslationStatusSelect=new Q({selectTitle:ee[te],dialogTitle:V.get(`VOTTranslateProxyStatus`),dialogParent:this.globalPortal,labelElement:this.proxyTranslationStatusSelectLabel.container,items:ee.map((e,t)=>({label:e,value:t.toString(),selected:t===te,disabled:t===0&&Fa}))}),i.content.append(this.proxyWorkerHostTextfield.container,this.proxyTranslationStatusSelect.container),this.translateAPIErrorsCheckbox=new $({labelHtml:V.get(`VOTTranslateAPIErrors`),checked:this.data.translateAPIErrors??!0}),this.translateAPIErrorsCheckbox.hidden=V.lang===`ru`,this.useNewAudioPlayerCheckbox=new $({labelHtml:V.get(`VOTNewAudioPlayer`),checked:this.data.newAudioPlayer}),this.videoHandler?.isAudioContextSupported||(this.useNewAudioPlayerCheckbox.disabled=!0,this.useNewAudioPlayerTooltip=new Y({target:this.useNewAudioPlayerCheckbox.container,content:V.get(`VOTNeedWebAudioAPI`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.onlyBypassMediaCSPCheckbox=new $({labelHtml:this.videoHandler?.site.needBypassCSP?`${V.get(`VOTOnlyBypassMediaCSP`)} (${V.get(`VOTMediaCSPEnabledOnSite`)})`:V.get(`VOTOnlyBypassMediaCSP`),checked:this.data.onlyBypassMediaCSP,isSubCheckbox:!0}),this.videoHandler?.isAudioContextSupported||(this.onlyBypassMediaCSPTooltip=new Y({target:this.onlyBypassMediaCSPCheckbox.container,content:V.get(`VOTNeedWebAudioAPI`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal})),this.onlyBypassMediaCSPCheckbox.disabled=!this.data.newAudioPlayer&&!!this.videoHandler?.isAudioContextSupported,this.data.newAudioPlayer||(this.onlyBypassMediaCSPCheckbox.hidden=!0),this.translationTextServiceLabel=new Wp({labelText:V.get(`VOTTranslationTextService`),icon:Lp});let re=this.data.translationService??`yandexbrowser`;this.translationTextServiceSelect=new Q({selectTitle:V.get(`services.${re}`),dialogTitle:V.get(`VOTTranslationTextService`),dialogParent:this.globalPortal,labelElement:this.translationTextServiceLabel.container,items:hc.map(e=>({label:V.get(`services.${e}`),value:e,selected:e===re}))}),this.translationTextServiceTooltip=new Y({target:this.translationTextServiceLabel.icon,content:V.get(`VOTNotAffectToVoice`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),this.detectServiceLabel=new Wp({labelText:V.get(`VOTDetectService`)});let ie=this.data.detectService??`yandexbrowser`;this.detectServiceSelect=new Q({selectTitle:V.get(`services.${ie}`),dialogTitle:V.get(`VOTDetectService`),dialogParent:this.globalPortal,labelElement:this.detectServiceLabel.container,items:bc.map(e=>({label:V.get(`services.${e}`),value:e,selected:e===ie}))}),this.showPiPButtonCheckbox=new $({labelHtml:V.get(`VOTShowPiPButton`),checked:this.data.showPiPButton}),this.showPiPButtonCheckbox.hidden=!Wi();let ae=Math.round((this.data.autoHideButtonDelay??1e3)/1e3*10)/10;this.autoHideButtonDelaySliderLabel=new Xp({labelText:V.get(`autoHideButtonDelay`),labelEOL:`:`,value:ae,symbol:` ${V.get(`secs`)}`}),this.autoHideButtonDelaySlider=new Jp({labelHtml:this.autoHideButtonDelaySliderLabel.container,value:ae,min:.1,max:3,step:.1}),this.buttonPositionSelectLabel=new Wp({labelText:V.get(`buttonPosition`),icon:Lp});let y=this.data.buttonPos??`default`;this.buttonPositionSelect=new Q({selectTitle:V.get(`position.${y}`),dialogTitle:V.get(`buttonPosition`),labelElement:this.buttonPositionSelectLabel.container,dialogParent:this.globalPortal,items:tm.map(e=>({label:V.get(`position.${e}`),value:e,selected:e===y}))}),this.buttonPositionTooltip=new Y({target:this.buttonPositionSelectLabel.icon,content:V.get(`minButtonPositionContainer`),position:`bottom`,backgroundColor:`var(--vot-helper-ondialog)`,parentElement:this.globalPortal}),this.menuLanguageSelectLabel=new Wp({labelText:V.get(`VOTMenuLanguage`)}),this.menuLanguageSelect=new Q({selectTitle:V.get(`langs.${V.langOverride}`),dialogTitle:V.get(`VOTMenuLanguage`),labelElement:this.menuLanguageSelectLabel.container,dialogParent:this.globalPortal,items:Q.genLanguageItems(V.getAvailableLangs(),V.langOverride)}),this.bugReportButton=J.createOutlinedButton(V.get(`VOTBugReport`)),this.resetSettingsButton=J.createButton(V.get(`resetSettings`)),a.content.append(this.translateAPIErrorsCheckbox.container,this.useNewAudioPlayerCheckbox.container,this.onlyBypassMediaCSPCheckbox.container),t.content.append(this.translationTextServiceSelect.container,this.detectServiceSelect.container),o.content.append(this.showPiPButtonCheckbox.container,this.autoHideButtonDelaySlider.container,this.buttonPositionSelect.container,this.menuLanguageSelect.container);let oe=am(),se=J.createInformation(`${V.get(`VOTVersion`)}:`,oe.scriptVersion||GM_info.script.version||V.get(`notFound`)),ce=J.createInformation(`${V.get(`VOTAuthors`)}:`,GM_info.script.author||`Toil, SashaXser, MrSoczekXD, mynovelhost, sodapng`),le=J.createInformation(`${V.get(`VOTLoader`)}:`,oe.loader),ue=J.createInformation(`${V.get(`VOTBrowser`)}:`,`${oe.browser} (${oe.os})`),de=new Date((this.data.localeUpdatedAt??0)*1e3).toLocaleString(),b=wl`${this.data.localeHash??V.get(`notFound`)}
(${V.get(`VOTUpdatedAt`)} + ${de})`,x=J.createInformation(`${V.get(`VOTLocaleHash`)}:`,b),fe=J.createOutlinedButton(V.get(`VOTUpdateLocaleFiles`));return fe.addEventListener(`click`,async()=>{await B.set(`localeHash`,``),await V.update(!0),globalThis.location.reload()}),s.content.append(se.container,ce.container,le.container,ue.container,x.container,fe),this.dialog.footerContainer.append(this.bugReportButton,this.resetSettingsButton),this.initialized=!0,this}initUIEvents(){if(!this.isInitialized())throw Error(`[VOT] SettingsView isn't initialized`);return globalThis.addEventListener(`message`,this.onAuthRefreshMessage),this.accountButton.addEventListener(`click`,async()=>{if(!B.isSupportOnlyLS){if(this.accountButton.loggedIn)return await B.delete(`account`),this.data.account={},this.updateAccountInfo();globalThis.open(_i,`_blank`)?.focus()}}),this.accountButton.addEventListener(`click:secret`,async()=>{let e=new Gp({titleHtml:V.get(`VOTLoginViaToken`),isTemp:!0});this.globalPortal.appendChild(e.container);let t=J.createEl(`vot-block`,void 0,V.get(`VOTYandexTokenInfo`)),n=new Kp({labelHtml:V.get(`VOTYandexToken`),value:this.data.account?.token});n.addEventListener(`change`,async e=>{this.data.account=e?{expires:Date.now()+3153418e4,token:e}:{},await B.set(`account`,this.data.account),this.updateAccountInfo()}),e.bodyContainer.append(t,n.container),e.open()}),this.accountButton.addEventListener(`refresh`,async()=>{await this.refreshAccountFromStorage()}),this.bindAccountStorageListener(),this.bindPersistedSetting({control:this.autoTranslateCheckbox,event:`change`,apply:e=>{this.data.autoTranslate=e},storageKey:`autoTranslate`,readPersistedValue:()=>this.data.autoTranslate,logLabel:`autoTranslate`,dispatch:e=>this.events[`change:autoTranslate`].dispatch(e)}),this.bindPersistedSetting({control:this.autoSubtitlesCheckbox,event:`change`,apply:e=>{this.data.autoSubtitles=e},storageKey:`autoSubtitles`,readPersistedValue:()=>this.data.autoSubtitles,logLabel:`autoSubtitles`,dispatch:e=>this.events[`change:autoSubtitles`].dispatch(e)}),this.dontTranslateLanguagesCheckbox.addEventListener(`change`,async e=>{this.data.enabledDontTranslateLanguages=e,this.dontTranslateLanguagesSelect.disabled=!e,await B.set(`enabledDontTranslateLanguages`,this.data.enabledDontTranslateLanguages),L.log(`enabledDontTranslateLanguages value changed. New value:`,e)}),this.dontTranslateLanguagesSelect.addEventListener(`selectItem`,async e=>{this.data.dontTranslateLanguages=e,await B.set(`dontTranslateLanguages`,this.data.dontTranslateLanguages),L.log(`dontTranslateLanguages value changed. New value:`,e)}),this.bindPersistedSetting({control:this.autoSetVolumeCheckbox,event:`change`,apply:e=>{this.data.enabledAutoVolume=e,this.autoSetVolumeSlider.disabled=!e,this.smartDuckingCheckbox.disabled=!e||!!this.syncVolumeCheckbox?.checked},storageKey:`enabledAutoVolume`,readPersistedValue:()=>this.data.enabledAutoVolume,logLabel:`enabledAutoVolume`,afterPersist:async()=>this.videoHandler?.setupAudioSettings?.()}),this.bindPersistedSetting({control:this.smartDuckingCheckbox,event:`change`,apply:e=>{this.data.enabledSmartDucking=e},storageKey:`enabledSmartDucking`,readPersistedValue:()=>this.data.enabledSmartDucking,logLabel:`enabledSmartDucking`,afterPersist:async()=>this.videoHandler?.setupAudioSettings?.()}),this.bindPersistedSetting({control:this.autoSetVolumeSlider,event:`input`,apply:e=>{this.data.autoVolume=this.autoSetVolumeSliderLabel.value=e},storageKey:`autoVolume`,readPersistedValue:()=>this.data.autoVolume,logLabel:`autoVolume`}),this.bindPersistedSetting({control:this.showVideoVolumeSliderCheckbox,event:`change`,apply:e=>{this.data.showVideoSlider=e},storageKey:`showVideoSlider`,readPersistedValue:()=>this.data.showVideoSlider,logLabel:`showVideoVolumeSlider`,dispatch:e=>this.events[`change:showVideoVolume`].dispatch(e)}),this.bindPersistedSetting({control:this.audioBoosterCheckbox,event:`change`,apply:e=>{this.data.audioBooster=e},storageKey:`audioBooster`,readPersistedValue:()=>this.data.audioBooster,logLabel:`audioBooster`,dispatch:e=>this.events[`change:audioBooster`].dispatch(e)}),this.bindPersistedSetting({control:this.syncVolumeCheckbox,event:`change`,apply:e=>{this.data.syncVolume=e,this.autoSetVolumeSlider.disabled=!this.autoSetVolumeCheckbox?.checked,this.smartDuckingCheckbox.disabled=e||!this.autoSetVolumeCheckbox?.checked,e&&this.smartDuckingCheckbox?.checked&&(this.smartDuckingCheckbox.checked=!1)},storageKey:`syncVolume`,readPersistedValue:()=>this.data.syncVolume,logLabel:`syncVolume`,dispatch:e=>this.events[`change:syncVolume`].dispatch(e)}),this.bindPersistedSetting({control:this.downloadWithNameCheckbox,event:`change`,apply:e=>{this.data.downloadWithName=e},storageKey:`downloadWithName`,readPersistedValue:()=>this.data.downloadWithName,logLabel:`downloadWithName`}),this.bindPersistedSetting({control:this.sendNotifyOnCompleteCheckbox,event:`change`,apply:e=>{this.data.sendNotifyOnComplete=e},storageKey:`sendNotifyOnComplete`,readPersistedValue:()=>this.data.sendNotifyOnComplete,logLabel:`sendNotifyOnComplete`}),this.bindPersistedSetting({control:this.useLivelyVoiceCheckbox,event:`change`,apply:e=>{this.data.useLivelyVoice=e},storageKey:`useLivelyVoice`,readPersistedValue:()=>this.data.useLivelyVoice,logLabel:`useLivelyVoice`,dispatch:e=>this.events[`change:useLivelyVoice`].dispatch(e)}),this.bindPersistedSetting({control:this.useAudioDownloadCheckbox,event:`change`,apply:e=>{this.data.useAudioDownload=e},storageKey:`useAudioDownload`,readPersistedValue:()=>this.data.useAudioDownload,logLabel:`useAudioDownload`}),this.bindPersistedSetting({control:this.responseLanguageSubtitlesSelect,event:`selectItem`,apply:e=>{this.data.responseLanguageSubtitles=e,this.responseLanguageSubtitlesSelect?.updateItems(bm(e)),this.responseLanguageSubtitlesSelect&&(this.responseLanguageSubtitlesSelect.selectTitle=ym(e))},storageKey:`responseLanguageSubtitles`,readPersistedValue:()=>this.data.responseLanguageSubtitles,logLabel:`responseLanguageSubtitles`,dispatch:e=>this.events[`select:responseLanguageSubtitles`].dispatch(e)}),this.bindPersistedSetting({control:this.subtitlesDownloadFormatSelect,event:`selectItem`,apply:e=>{this.data.subtitlesDownloadFormat=e},storageKey:`subtitlesDownloadFormat`,readPersistedValue:()=>this.data.subtitlesDownloadFormat,logLabel:`subtitlesDownloadFormat`}),this.bindPersistedSetting({control:this.subtitlesHighlightWordsCheckbox,event:`change`,apply:e=>{this.data.highlightWords=e},storageKey:`highlightWords`,readPersistedValue:()=>this.data.highlightWords,logLabel:`highlightWords`,dispatch:e=>this.events[`change:subtitlesHighlightWords`].dispatch(e)}),this.subtitlesSmartLayoutCheckbox?.addEventListener(`change`,e=>{this.suppressSubtitlesSmartLayoutCheckboxChange||this.setSubtitlesSmartLayout(e)}),this.subtitlesMaxLengthSlider.addEventListener(`input`,e=>{this.subtitlesMaxLengthSliderLabel.value=e,(this.data.subtitlesSmartLayout??!0)===!0&&this.setSubtitlesSmartLayout(!1),this.data.subtitlesMaxLength=e,this.scheduleStoragePersist(`subtitlesMaxLength`,this.data.subtitlesMaxLength),L.log(`subtitlesMaxLength value changed. New value:`,e),this.events[`input:subtitlesMaxLength`].dispatch(e)}),this.subtitlesFontSizeSlider.addEventListener(`input`,e=>{this.subtitlesFontSizeSliderLabel.value=e,(this.data.subtitlesSmartLayout??!0)===!0&&this.setSubtitlesSmartLayout(!1),this.data.subtitlesFontSize=e,this.scheduleStoragePersist(`subtitlesFontSize`,this.data.subtitlesFontSize),L.log(`subtitlesFontSize value changed. New value:`,e),this.events[`input:subtitlesFontSize`].dispatch(e)}),this.subtitlesBackgroundOpacitySlider.addEventListener(`input`,e=>{this.subtitlesBackgroundOpacitySliderLabel.value=e,this.data.subtitlesOpacity=e,this.scheduleStoragePersist(`subtitlesOpacity`,this.data.subtitlesOpacity),L.log(`subtitlesOpacity value changed. New value:`,e),this.events[`input:subtitlesBackgroundOpacity`].dispatch(e)}),this.bindPersistedSetting({control:this.subtitlesFontFamilySelect,event:`selectItem`,apply:e=>{this.data.subtitlesFontFamily=e},storageKey:`subtitlesFontFamily`,readPersistedValue:()=>this.data.subtitlesFontFamily,logLabel:`subtitlesFontFamily`,dispatch:e=>this.events[`select:subtitlesFontFamily`].dispatch(e)}),this.bindPersistedSetting({control:this.translateHotkeyButton,event:`change`,apply:e=>{this.data.translationHotkey=e},storageKey:`translationHotkey`,readPersistedValue:()=>this.data.translationHotkey,logLabel:`translationHotkey`}),this.bindPersistedSetting({control:this.subtitlesHotkeyButton,event:`change`,apply:e=>{this.data.subtitlesHotkey=e},storageKey:`subtitlesHotkey`,readPersistedValue:()=>this.data.subtitlesHotkey,logLabel:`subtitlesHotkey`}),this.proxyWorkerHostTextfield.addEventListener(`change`,async e=>{this.data.proxyWorkerHost=e||`vot-worker.kload.workers.dev`,await B.set(`proxyWorkerHost`,this.data.proxyWorkerHost),L.log(`proxyWorkerHost value changed. New value:`,this.data.proxyWorkerHost),this.events[`change:proxyWorkerHost`].dispatch(e)}),this.proxyTranslationStatusSelect.addEventListener(`selectItem`,async e=>{this.data.translateProxyEnabled=Number.parseInt(e,10),await B.set(`translateProxyEnabled`,this.data.translateProxyEnabled),await B.set(`translateProxyEnabledDefault`,!1),L.log(`translateProxyEnabled value changed. New value:`,this.data.translateProxyEnabled),this.events[`select:proxyTranslationStatus`].dispatch(e)}),this.bindPersistedSetting({control:this.translateAPIErrorsCheckbox,event:`change`,apply:e=>{this.data.translateAPIErrors=e},storageKey:`translateAPIErrors`,readPersistedValue:()=>this.data.translateAPIErrors,logLabel:`translateAPIErrors`}),this.bindPersistedSetting({control:this.useNewAudioPlayerCheckbox,event:`change`,apply:e=>{this.data.newAudioPlayer=e,this.onlyBypassMediaCSPCheckbox.disabled=this.onlyBypassMediaCSPCheckbox.hidden=!e},storageKey:`newAudioPlayer`,readPersistedValue:()=>this.data.newAudioPlayer,logLabel:`newAudioPlayer`,dispatch:e=>this.events[`change:useNewAudioPlayer`].dispatch(e)}),this.bindPersistedSetting({control:this.onlyBypassMediaCSPCheckbox,event:`change`,apply:e=>{this.data.onlyBypassMediaCSP=e},storageKey:`onlyBypassMediaCSP`,readPersistedValue:()=>this.data.onlyBypassMediaCSP,logLabel:`onlyBypassMediaCSP`,dispatch:e=>this.events[`change:onlyBypassMediaCSP`].dispatch(e)}),this.bindPersistedSetting({control:this.translationTextServiceSelect,event:`selectItem`,apply:e=>{this.data.translationService=e},storageKey:`translationService`,readPersistedValue:()=>this.data.translationService,logLabel:`translationService`,dispatch:e=>this.events[`select:translationTextService`].dispatch(e)}),this.bindPersistedSetting({control:this.detectServiceSelect,event:`selectItem`,apply:e=>{this.data.detectService=e},storageKey:`detectService`,readPersistedValue:()=>this.data.detectService,logLabel:`detectService`}),this.bindPersistedSetting({control:this.showPiPButtonCheckbox,event:`change`,apply:e=>{this.data.showPiPButton=e},storageKey:`showPiPButton`,readPersistedValue:()=>this.data.showPiPButton,logLabel:`showPiPButton`,dispatch:e=>this.events[`change:showPiPButton`].dispatch(e)}),this.autoHideButtonDelaySlider.addEventListener(`input`,e=>{this.autoHideButtonDelaySliderLabel.value=e;let t=Math.round(e*1e3);L.log(`autoHideButtonDelay value changed. New value:`,t),this.data.autoHideButtonDelay=t,this.scheduleStoragePersist(`autoHideButtonDelay`,this.data.autoHideButtonDelay),this.events[`input:autoHideButtonDelay`].dispatch(e)}),this.bindPersistedSetting({control:this.buttonPositionSelect,event:`selectItem`,apply:e=>{this.data.buttonPos=e},storageKey:`buttonPos`,readPersistedValue:()=>this.data.buttonPos,logLabel:`buttonPos`,dispatch:e=>this.events[`select:buttonPosition`].dispatch(e)}),this.menuLanguageSelect.addEventListener(`selectItem`,async e=>{await V.changeLang(e)&&(this.data.localeUpdatedAt=await B.get(`localeUpdatedAt`,0),this.events[`select:menuLanguage`].dispatch(e))}),this.bugReportButton.addEventListener(`click`,()=>this.events[`click:bugReport`].dispatch()),this.resetSettingsButton.addEventListener(`click`,()=>this.events[`click:resetSettings`].dispatch()),this}addEventListener(e,t){return this.events[e].addListener(t),this}removeEventListener(e,t){return this.events[e].removeListener(t),this}doReleaseUI(){this.dialog?.remove();for(let e of[this.accountButtonRefreshTooltip,this.accountButtonTokenTooltip,this.audioBoosterTooltip,this.useLivelyVoiceTooltip,this.useAudioDownloadCheckboxTooltip,this.useNewAudioPlayerTooltip,this.onlyBypassMediaCSPTooltip,this.translationTextServiceTooltip,this.proxyTranslationStatusSelectTooltip,this.buttonPositionTooltip])e?.release()}doReleaseUIEvents(){this.accountStorageListenerCleanup?.(),this.accountStorageListenerCleanup=void 0,globalThis.removeEventListener(`message`,this.onAuthRefreshMessage),this.flushStoragePersists();for(let e of Object.values(this.events))e.clear()}release(){return this.isInitialized()?(this.doReleaseUIEvents(),this.doReleaseUI(),this.initialized=!1,this):this}updateAccountInfo(){if(!this.isInitialized())throw Error(`[VOT] SettingsView isn't initialized`);let e=!!this.data.account?.token;return this.accountButton.avatarId=this.data.account?.avatarId,this.useLivelyVoiceTooltip.hidden=this.accountButton.loggedIn=e,this.accountButton.username=this.data.account?.username,this.useLivelyVoiceCheckbox.disabled=!e,this.events[`update:account`].dispatch(this.data.account),this}open(){if(!this.isInitialized())throw Error(`[VOT] SettingsView isn't initialized`);return this.dialog.open()}close(){if(!this.isInitialized())throw Error(`[VOT] SettingsView isn't initialized`);return this.dialog.close()}},Sm=class{mount;initialized=!1;videoHandler;intervalIdleChecker;data;votGlobalPortal;globalPortalMount;votOverlayView;votSettingsView;constructor({mount:e,data:t={},videoHandler:n,intervalIdleChecker:r}){this.mount=e,this.videoHandler=n,this.data=t,this.intervalIdleChecker=r}get root(){return this.mount.root}get portalContainer(){return this.mount.portalContainer}getSubtitlesMountContainer(){return this.votOverlayView?.root??this.mount.subtitlesMountContainer}isInitialized(){return this.initialized}initUI(){if(this.isInitialized())throw Error(`[VOT] UIManager is already initialized`);return this.initialized=!0,this.globalPortalMount=Yl({parent:this.getGlobalPortalHost(this.mount),rootClasses:[`vot-portal`]}),this.votGlobalPortal=this.globalPortalMount.root,this.votOverlayView=new $p({mount:this.mount,globalPortal:this.votGlobalPortal,data:this.data,videoHandler:this.videoHandler,intervalIdleChecker:this.intervalIdleChecker}),this.votOverlayView.initUI(this.data.buttonPos??`default`),this.votSettingsView=new xm({globalPortal:this.votGlobalPortal,data:this.data,videoHandler:this.videoHandler}),this.votSettingsView.initUI(),this.videoHandler?.subtitlesWidget?.updateMount({container:this.getSubtitlesMountContainer()}),this}updateMount(e){return Xl(this.globalPortalMount,this.getGlobalPortalHost(e)),this.mount=Sp(this.mount,e,e=>{this.votOverlayView?.updateMount(e)}),this.videoHandler?.subtitlesWidget?.updateMount({container:this.getSubtitlesMountContainer()}),this}getGlobalPortalHost(e){let t=document,n=t.fullscreenElement??t.webkitFullscreenElement;return n instanceof HTMLElement&&(n===e.root||n.contains(e.root)||e.root.contains(n))?e.root:document.documentElement}initUIEvents(){if(!this.isInitialized())throw Error(`[VOT] UIManager isn't initialized`);this.votOverlayView.initUIEvents(),this.bindOverlayViewEvents(),this.votSettingsView.initUIEvents(),this.bindSettingsViewEvents()}bindOverlayViewEvents(){let e=this.votOverlayView;e&&e.addEventListener(`click:translate`,async()=>{await this.handleTranslationBtnClick()}).addEventListener(`click:pip`,async()=>{if(this.videoHandler)try{document.pictureInPictureElement==null?await this.videoHandler.video.requestPictureInPicture():await document.exitPictureInPicture()}catch(e){L.warn(`[VOT] Failed to toggle Picture-in-Picture`,e)}}).addEventListener(`click:settings`,async()=>{this.videoHandler?.subtitlesWidget?.releaseTooltip(),this.videoHandler?.overlayVisibility?.cancel(),this.videoHandler?.overlayVisibility?.show(),this.votSettingsView.open()}).addEventListener(`click:downloadTranslation`,async()=>{await this.handleDownloadTranslationClick()}).addEventListener(`click:downloadSubtitles`,async()=>{await this.handleDownloadSubtitlesClick()}).addEventListener(`input:videoVolume`,e=>{if(!this.videoHandler)return;let t=e/100;if(this.videoHandler.setVideoVolume(t),this.videoHandler.applyManualVideoVolumeOverride(t),!this.data.syncVolume){this.videoHandler.onVideoVolumeSliderSynced(e);return}this.videoHandler.syncVolumeWrapper(`video`,e)}).addEventListener(`input:translationVolume`,e=>{if(!this.videoHandler)return;let t=e??this.data.defaultVolume??100;if(this.videoHandler.audioPlayer.player.volume=t/100,!this.data.syncVolume){this.videoHandler.onTranslationVolumeSliderSynced(t);return}this.videoHandler.syncVolumeWrapper(`translation`,t)}).addEventListener(`select:fromLanguage`,async()=>{this.videoHandler&&await this.videoHandler.refreshAutoSubtitlesForCurrentLangPair()}).addEventListener(`select:subtitles`,e=>{this.videoHandler&&this.runDetached(this.videoHandler.changeSubtitlesLang(e),`Failed to change subtitles language`)})}bindSettingsViewEvents(){let e=this.votSettingsView;e&&e.addEventListener(`update:account`,async e=>{this.videoHandler&&(this.videoHandler.votClient.apiToken=e?.token)}).addEventListener(`change:autoTranslate`,async e=>{let t=this.videoHandler;e&&t&&!t.hasActiveSource()&&await this.handleTranslationBtnClick()}).addEventListener(`change:autoSubtitles`,async e=>{!e||!this.videoHandler?.videoData?.videoId||await this.videoHandler.refreshAutoSubtitlesForCurrentLangPair()}).addEventListener(`select:responseLanguageSubtitles`,async()=>{!this.videoHandler?.data.autoSubtitles||!this.videoHandler.videoData||await this.videoHandler.refreshAutoSubtitlesForCurrentLangPair()}).addEventListener(`change:showVideoVolume`,()=>{this.withInitializedOverlayView(e=>{!e.videoVolumeSlider||!e.votButton||(e.videoVolumeSlider.container.hidden=!this.data.showVideoSlider||e.votButton.status!==`success`)})}).addEventListener(`change:audioBooster`,async()=>{this.withInitializedOverlayView(e=>{if(!e.translationVolumeSlider)return;let t=e.translationVolumeSlider.value,n=this.data.audioBooster&&!this.data.syncVolume?900:100;e.translationVolumeSlider.max=n;let r=R(t,0,n);e.translationVolumeSlider.value=r,this.videoHandler?.onTranslationVolumeSliderSynced(r)})}).addEventListener(`change:syncVolume`,e=>{this.videoHandler&&(this.videoHandler.setupAudioSettings(),this.withInitializedOverlayView(t=>{let n=t.videoVolumeSlider,r=t.translationVolumeSlider;if(!n||!r)return;let i=this.data.audioBooster&&!e?900:100;r.max=i;let a=R(r.value,0,i);r.value=a,this.videoHandler.onTranslationVolumeSliderSynced(a),e&&this.videoHandler.resetVolumeLinkState(Number(n.value),a)}))}).addEventListener(`change:useLivelyVoice`,()=>{this.videoHandler&&this.runDetached(this.videoHandler.stopTranslate(),`Failed to stop translation after voice mode change`)}).addEventListener(`change:subtitlesHighlightWords`,e=>{this.updateSubtitlesWidgetSetting(e,this.data.highlightWords,(e,t)=>{e.setHighlightWords(t)})}).addEventListener(`change:subtitlesSmartLayout`,e=>{this.updateSubtitlesWidgetSetting(e,this.data.subtitlesSmartLayout,(e,t)=>{e.setSmartLayout(t)})}).addEventListener(`input:subtitlesMaxLength`,e=>{this.updateSubtitlesWidgetSetting(e,this.data.subtitlesMaxLength,(e,t)=>{e.setMaxLength(t)})}).addEventListener(`input:subtitlesFontSize`,e=>{this.updateSubtitlesWidgetSetting(e,this.data.subtitlesFontSize,(e,t)=>{e.setFontSize(t)})}).addEventListener(`select:subtitlesFontFamily`,e=>{this.updateSubtitlesWidgetSetting(e,this.data.subtitlesFontFamily,(e,t)=>{e.setFontFamily(t)})}).addEventListener(`input:subtitlesBackgroundOpacity`,e=>{this.updateSubtitlesWidgetSetting(e,this.data.subtitlesOpacity,(e,t)=>{e.setOpacity(t)})}).addEventListener(`change:proxyWorkerHost`,e=>{this.videoHandler&&this.runDetached(this.videoHandler.handleProxySettingsChanged(`proxyWorkerHost`),`Failed to apply proxyWorkerHost change`)}).addEventListener(`select:proxyTranslationStatus`,()=>{this.videoHandler&&this.runDetached(this.videoHandler.handleProxySettingsChanged(`proxyTranslationStatus`),`Failed to apply proxyTranslationStatus change`)}).addEventListener(`change:useNewAudioPlayer`,()=>{this.restartAudioPlayer()}).addEventListener(`change:onlyBypassMediaCSP`,()=>{this.restartAudioPlayer()}).addEventListener(`select:translationTextService`,()=>{this.withSubtitlesWidget(e=>{e.resetTranslationContext(!0)})}).addEventListener(`change:showPiPButton`,()=>{this.withInitializedOverlayView(e=>{e.votButton&&(e.votButton.pipButton.hidden=e.votButton.separator2.hidden=!e.pipButtonVisible)})}).addEventListener(`select:buttonPosition`,e=>{this.withInitializedOverlayView(t=>{let n=this.data.buttonPos??e,{position:r,direction:i}=t.calcButtonLayout(n);t.updateButtonLayout(r,i)})}).addEventListener(`select:menuLanguage`,async()=>{await this.reloadMenu()}).addEventListener(`click:bugReport`,()=>{if(!this.videoHandler)return;let e=new URLSearchParams(this.videoHandler.collectReportInfo()).toString();globalThis.open(`${xi}/issues/new?${e}`,`_blank`)?.focus()}).addEventListener(`click:resetSettings`,async()=>{let e=await B.list();await Promise.all(e.map(e=>B.delete(e))),await B.set(`compatVersion`,Ei),globalThis.location.reload()})}async handleDownloadTranslationClick(){let e=this.votOverlayView,t=this.videoHandler;if(!e?.isInitialized()||!t?.downloadTranslationUrl||!t.videoData)return;let n=e.downloadTranslationButton,r=t.downloadTranslationUrl,i=this.data.downloadWithName?Xi(t.videoData.downloadTitle):`translation_${t.videoData.videoId}`,a={preferShare:this.isLikelyMobileDownloadContext()},o=e=>{n&&(n.progress=e)};o(0);try{await this.downloadTranslationAudio(r,i,o,a)}catch(e){console.error(`[VOT] Download translation failed:`,e),this.triggerUrlDownload(r,`${i}.mp3`)||globalThis.open(r,`_blank`)?.focus()}finally{o(0)}}async downloadTranslationAudio(e,t,n,r){let i=await z(e,{timeout:0});if(!i.ok)throw Error(`HTTP ${i.status}`);await yp(i,t,n,r)}async handleDownloadSubtitlesClick(){let e=this.videoHandler;if(!e?.yandexSubtitles||!e.videoData)return;let t=this.data.subtitlesDownloadFormat??`json`,n=fp(e.yandexSubtitles,t,{assTitle:e.videoData.localizedTitle??e.videoData.title??e.videoData.downloadTitle});await Ji(new Blob([t===`json`?JSON.stringify(n):n],{type:`text/plain`}),`${this.data.downloadWithName?Xi(e.videoData.downloadTitle):`subtitles_${e.videoData.videoId}`}.${t}`,{preferShare:this.isLikelyMobileDownloadContext()})}async reloadMenu(){if(!this.votOverlayView?.isInitialized())throw Error(`[VOT] OverlayView isn't initialized`);let e=this.votOverlayView.votButton.opacity,t=this.votOverlayView.votButton.container.hidden,n=this.votOverlayView.votMenu.hidden,r=this.data.buttonPos??`default`,i=this.votSettingsView?.dialog?.container?.hidden===!1;if(await this.videoHandler?.stopTranslation(),this.release(),this.initUI(),this.initUIEvents(),!this.videoHandler)return this;try{let{position:i,direction:a}=this.votOverlayView.calcButtonLayout(r);this.votOverlayView.updateButtonLayout(i,a),this.votOverlayView.votMenu.hidden=n,this.votOverlayView.votButton.container.hidden=t,this.votOverlayView.votButton.opacity=e}catch(e){L.warn(`[VOT] Failed to restore overlay state after menu reload`,e)}try{this.videoHandler.rebindOverlayVisibilityTargets()}catch(e){L.warn(`[VOT] Failed to rebind overlay visibility targets`,e)}if(i)try{this.votSettingsView?.open()}catch(e){L.warn(`[VOT] Failed to reopen settings after menu reload`,e)}await this.videoHandler.updateSubtitlesLangSelect();let a=this.videoHandler.subtitlesWidget;return a&&a.resetTranslationContext(!0),this}async handleTranslationBtnClick(){if(!this.votOverlayView?.isInitialized())throw Error(`[VOT] OverlayView isn't initialized`);return await Ep({videoHandler:this.videoHandler,currentStatus:this.votOverlayView.votButton.status,currentLoading:this.votOverlayView.votButton.loading,transformBtn:(e,t)=>{this.transformBtn(e,t)}}),this}isLoadingText(e){let t=V.get(`TranslationDelayed`);return typeof e==`string`&&(e.includes(V.get(`translationTake`))||(t?e.includes(t):!1))}transformBtn(e,t){if(!this.votOverlayView?.isInitialized())throw Error(`[VOT] OverlayView isn't initialized`);return this.votOverlayView.votButton.status=e,this.votOverlayView.votButton.loading=e===`error`&&this.isLoadingText(t),this.votOverlayView.votButton.setText(t),this.votOverlayView.votButtonTooltip.setContent(t),this}release(){return this.isInitialized()?(this.votOverlayView.release(),this.votSettingsView.release(),Zl(this.globalPortalMount),this.globalPortalMount=void 0,this.votGlobalPortal=void 0,this.initialized=!1,this):this}withInitializedOverlayView(e){this.votOverlayView?.isInitialized()&&e(this.votOverlayView)}withSubtitlesWidget(e){let t=this.videoHandler?.subtitlesWidget;t&&e(t)}updateSubtitlesWidgetSetting(e,t,n){this.withSubtitlesWidget(r=>{n(r,t??e)})}runDetached(e,t){e.catch(e=>{L.warn(`[VOT] ${t}`,e)})}triggerUrlDownload(e,t){try{let n=document.createElement(`a`);return n.href=e,n.download=t,n.target=`_blank`,n.rel=`noopener noreferrer`,n.style.display=`none`,document.body.appendChild(n),n.click(),n.remove(),!0}catch{return!1}}isLikelyMobileDownloadContext(){return this.videoHandler?.site.additionalData===`mobile`?!0:typeof matchMedia==`function`&&matchMedia(`(pointer: coarse)`).matches}restartAudioPlayer(){this.restartAudioPlayerSafely()}async restartAudioPlayerSafely(){let e=this.videoHandler;if(e)try{await e.stopTranslate(),e.createPlayer()}catch(e){L.warn(`[VOT] Failed to restart audio player`,e)}}},Cm=class{deps;hideDeadlineMs=0;hideArmed=!1;unsubscribeChecker;constructor(e){this.deps=e,this.unsubscribeChecker=this.deps.checker.subscribe(()=>{this.onCheckerTick()})}show(){let e=this.getView();return e?(e.updateButtonOpacity(1),e):null}cancel(){this.hideDeadlineMs=0,this.hideArmed=!1}release(){this.cancel(),this.unsubscribeChecker()}queueAutoHide(){if(!this.show())return;let e=this.deps.getAutoHideDelay();this.hideDeadlineMs=this.nowMs()+Math.max(0,e),this.hideArmed=!0,this.deps.checker.markActivity(`overlay-queue-hide`),this.deps.checker.requestImmediateTick()}handleOverlayInteraction(e){let t=e?.type;if(t){if(t===`focusin`){this.handleFocusIn();return}if(t.startsWith(`pointer`)){this.cancel(),this.show(),this.deps.checker.markActivity(`overlay-interaction`),e.stopPropagation?.();return}this.handleHostInteraction(e)}}handleHostInteraction(e){let t=e?.type;if(t){if(t===`focusin`){this.handleFocusIn();return}if(t.startsWith(`pointer`)){let t=e.target;this.deps.isInteractiveNode(t)&&e.stopPropagation?.(),this.deps.checker.markActivity(`overlay-host-pointer`)}this.queueAutoHide()}}scheduleHide(e){if(!this.getView())return;let t=e?.currentTarget,n=e?.relatedTarget??null;!n&&typeof e?.composedPath==`function`&&(n=e.composedPath()[1]??null);let r=n instanceof Node?n:null,i=t instanceof Node?t:null;r&&(i&&Io(i,r)||this.deps.isInteractiveNode(r))||this.queueAutoHide()}onCheckerTick(){if(!this.hideArmed||this.hideDeadlineMs<=0||this.nowMs()+2typeof performance<`u`&&typeof performance.now==`function`?performance.now():Date.now(),setInterval:globalThis.setInterval.bind(globalThis),clearInterval:globalThis.clearInterval.bind(globalThis),queueMicrotask:e=>{if(typeof globalThis.queueMicrotask==`function`){globalThis.queueMicrotask(e);return}Promise.resolve().then(e)},onVisibilityChange:e=>typeof document>`u`||typeof document.addEventListener!=`function`?()=>void 0:(document.addEventListener(`visibilitychange`,e),()=>{typeof document.removeEventListener==`function`&&document.removeEventListener(`visibilitychange`,e)})}}var km=class{profile;runtime;subscribers=new Set;intervalId=null;unsubscribeVisibilityChange=null;running=!1;destroyed=!1;immediateQueued=!1;currentMode=`active`;lastActivityAt;onVisibilityChangeHandler=()=>{this.destroyed||!this.running||(im()?this.clearIntervalTimer():this.armInterval(),this.requestImmediateTick())};constructor(e={}){this.profile=Dm(e.profile),this.runtime={...Om(),...e.runtime},this.lastActivityAt=this.runtime.nowMs()}start(){this.destroyed||this.running||(this.running=!0,this.lastActivityAt=this.runtime.nowMs(),this.subscribeVisibilityChange(),this.armInterval(),this.runTick(`start`))}stop(){this.running&&(this.running=!1,this.clearIntervalTimer(),this.immediateQueued=!1,this.unsubscribeFromVisibilityChange())}destroy(){this.destroyed||=(this.stop(),this.subscribers.clear(),!0)}subscribe(e){return this.destroyed?()=>void 0:(this.subscribers.add(e),()=>{this.subscribers.delete(e)})}markActivity(e){if(this.destroyed||(this.lastActivityAt=this.runtime.nowMs(),!this.running))return;let t=this.resolveMode(this.lastActivityAt);t!==this.currentMode&&(this.currentMode=t)}requestImmediateTick(){this.destroyed||!this.running||this.immediateQueued||(this.immediateQueued=!0,this.runtime.queueMicrotask(()=>{this.immediateQueued=!1,!(this.destroyed||!this.running)&&this.runTick(`immediate`)}))}resolveMode(e){return im()?`hidden`:e-this.lastActivityAt>=this.profile.idleAfterMs?`idle`:`active`}clearIntervalTimer(){this.intervalId!==null&&(this.runtime.clearInterval(this.intervalId),this.intervalId=null)}armInterval(){this.intervalId===null&&(this.intervalId=this.runtime.setInterval(()=>{this.runTick(`interval`)},this.profile.checkIntervalMs))}runTick(e){if(this.destroyed||!this.running||this.subscribers.size===0)return;let t=this.runtime.nowMs(),n=this.resolveMode(t);n!==this.currentMode&&(this.currentMode=n);let r={nowMs:t,mode:n,source:e};for(let e of this.subscribers)try{e(r)}catch{}}subscribeVisibilityChange(){this.unsubscribeVisibilityChange===null&&(this.unsubscribeVisibilityChange=this.runtime.onVisibilityChange(this.onVisibilityChangeHandler))}unsubscribeFromVisibilityChange(){this.unsubscribeVisibilityChange!==null&&(this.unsubscribeVisibilityChange(),this.unsubscribeVisibilityChange=null)}};function Am(e){return new km({profile:e})}var jm=()=>Date.now();function Mm(){return GM_info?.script?.name||`VOT`}function Nm(e,t){try{return V?.get?.(e)||t}catch{return t}}function Pm(e,t,n){if(!n)return!0;let r=e.get(t)??0;return jm()-r>=n}function Fm(e,t){e.set(t,jm())}function Im(e){let t=e.trim();if(!t)return null;try{let e=V.get(t),n=V.getDefault(t);return e!==t||n!==t?e||n||t:null}catch{return null}}function Lm(e){if(!e||typeof e!=`object`)return null;let t=e;return t.name===`VOTLocalizedError`?typeof t.localizedMessage==`string`&&t.localizedMessage.trim()?t.localizedMessage:typeof t.unlocalizedMessage==`string`?Im(t.unlocalizedMessage):null:null}function Rm(e){let t=ba(e);return t?Im(t)||t:null}function zm(e){let t=Lm(e);if(t)return t;if(typeof e==`string`){let t=Im(e);if(t)return t}return Rm(e)||Nm(`requestTranslationFailed`,`Translation failed`)}function Bm(e){try{if(typeof GM_notification==`function`)return GM_notification(e),!0;let t=globalThis.GM;if(t!==void 0&&typeof t.notification==`function`){let n={text:e.text,title:e.title,image:e.image,onclick:e.onclick,ondone:e.ondone};return t.notification(n),!0}}catch(e){L.log(`[notify] userscript api error`,e)}return!1}var Vm=class{lastSentAt=new Map;send(e,t={}){try{let n=t.key||e.tag||`${e.title??``}|${e.text??``}`,r=t.cooldownMs??0;if(!Pm(this.lastSentAt,n,r))return;let i={...e,title:e.title??Mm()};Bm(i)?Fm(this.lastSentAt,n):L.log(`[notify] unavailable`,i)}catch(e){L.log(`[notify] send error`,e)}}translationCompleted(e){let t=Nm(`VOTTranslationCompletedNotify`,`The translation on the {0} has been completed!`).replace(`{0}`,e);this.send({text:t,title:Mm(),timeout:5e3,silent:!0,tag:`VOTTranslationCompleted`,onclick:()=>{try{globalThis.focus()}catch{}}},{key:`translation_completed_${e}`,cooldownMs:1e4})}translationFailed(e){let{videoId:t,message:n}=e;if(xa(n))return;let r=zm(n),i=Mm();this.send({text:r,title:i,timeout:8e3,silent:!0,tag:`VOTtranslationFailed_${t||`unknown`}`,onclick:()=>{try{globalThis.focus()}catch{}}},{key:`translation_failed_${t||`unknown`}`,cooldownMs:3e4})}},Hm=[`class`,`id`,`title`],Um=new RegExp([`advertise`,`advertisement`,`promo`,`sponsor`,`banner`,`commercial`,`preroll`,`midroll`,`postroll`,`ad-container`,`sponsored`].map(e=>e.replaceAll(/[.*+?^${}()|[\]\\]/g,String.raw`\$&`)).join(`|`)),Wm=Symbol.for(`vot.attachShadowHook`);function Gm(){let e=Object.getOwnPropertyDescriptor(Element.prototype,`attachShadow`);return!e||typeof e.value!=`function`?null:e}function Km(){let e=globalThis,t=e[Wm];if(t?.descriptor&&t.subscribers instanceof Set)return t;let n=Gm();if(!n)return null;let r=n.value,i={descriptor:n,subscribers:new Set},a=function(e){let t=r.call(this,e);for(let e of i.subscribers)try{e(t)}catch(e){L.error(`attachShadow subscriber failed`,e)}return t};try{Object.defineProperty(Element.prototype,`attachShadow`,{...n,value:a})}catch{return null}return e[Wm]=i,i}function qm(e){let t=globalThis,n=t[Wm];if(n&&(n.subscribers.delete(e),!(n.subscribers.size>0))){try{Object.defineProperty(Element.prototype,`attachShadow`,n.descriptor)}catch{let e=n.descriptor.value;typeof e==`function`&&(Element.prototype.attachShadow=e)}delete t[Wm]}}var Jm=class e{seenVideos=new WeakSet;activeVideos=new WeakSet;observedRoots=new WeakSet;videoListenerControllers=new Map;pendingAdded=new Set;pendingRemoved=new Set;flushPending=!1;static MAX_FLUSH_BUDGET_MS=6;static MAX_NODES_PER_SLICE=120;onVideoAdded=new H;onVideoRemoved=new H;observer=new MutationObserver(e=>this.onMutations(e));intervalIdleChecker;checkerUnsubscribe=null;enabled=!1;attachShadowSubscriber=null;onDocumentReady=null;onPageShow=()=>{let e=document.documentElement;e&&(this.pendingAdded.add(e),this.scheduleFlush())};constructor(e=Am()){this.intervalIdleChecker=e}static containsAdKeyword(e){return e.length>0&&Um.test(e)}isAdRelated(t){for(let n of Hm){let r=t.getAttribute(n);if(r&&e.containsAdKeyword(r.toLowerCase()))return!0}return!1}isInsideAd(e){for(let t=e.parentElement;t;t=t.parentElement)if(this.isAdRelated(t))return!0;return!1}getCapturedAudioTrackCount(e){let t=e,n=t.captureStream??t.mozCaptureStream;if(typeof n!=`function`)return null;try{return n.call(e).getAudioTracks().length}catch{return null}}isLikelySilentDecorativeVideo(e){if(!(e.muted||e.defaultMuted)||!e.autoplay||!e.loop||e.controls)return!1;let t=e;if(typeof t.mozHasAudio==`boolean`)return!t.mozHasAudio;if(`audioTracks`in t&&typeof t.audioTracks?.length==`number`){if(t.audioTracks.length>0)return!1;let n=this.getCapturedAudioTrackCount(e);return n===null?!0:n===0}let n=this.getCapturedAudioTrackCount(e);return n===null?!1:n===0}hasAudio(e){let t=e;return e.srcObject instanceof MediaStream?e.srcObject.getAudioTracks().length>0:typeof t.mozHasAudio==`boolean`?t.mozHasAudio:typeof t.webkitAudioDecodedByteCount==`number`&&t.webkitAudioDecodedByteCount>0||`audioTracks`in t&&typeof t.audioTracks?.length==`number`&&t.audioTracks.length>0?!0:!this.isLikelySilentDecorativeVideo(e)}isValidVideo(e){return this.isAdRelated(e)||this.isInsideAd(e)?!1:this.hasAudio(e)?!0:(L.log(`Ignoring video without audio:`,e),!1)}observeRoot(e){this.observedRoots.has(e)||(this.observedRoots.add(e),this.observer.observe(e,{childList:!0,subtree:!0}))}scan(e){if(e instanceof HTMLVideoElement){this.trackVideo(e);return}if(e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_FRAGMENT_NODE&&e.nodeType!==Node.DOCUMENT_NODE)return;let t=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode:e=>{let t=e,n=t.tagName===`VIDEO`,r=!!t.shadowRoot;return n||r?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}});for(;t.nextNode();){let e=t.currentNode;if(e instanceof HTMLVideoElement){this.trackVideo(e);continue}let n=e.shadowRoot;n&&(this.observeRoot(n),this.scan(n))}}getVideoListenerSignal(e){let t=this.videoListenerControllers.get(e);t&&t.abort();let n=new AbortController;return this.videoListenerControllers.set(e,n),n.signal}cleanupVideoListeners(e){let t=this.videoListenerControllers.get(e);t&&(t.abort(),this.videoListenerControllers.delete(e))}cleanupAllVideoListeners(){for(let e of this.videoListenerControllers.values())e.abort();this.videoListenerControllers.clear()}trackVideo(e){if(this.seenVideos.has(e))return;this.seenVideos.add(e);let t=this.getVideoListenerSignal(e),n=()=>{this.isValidVideo(e)&&(this.activeVideos.has(e)||(this.activeVideos.add(e),this.onVideoAdded.dispatch(e)))};e.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?n():(e.addEventListener(`loadeddata`,n,{once:!0,signal:t}),e.addEventListener(`play`,()=>{e.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&n()},{once:!0,passive:!0,signal:t})),e.addEventListener(`emptied`,()=>{e.isConnected||this.untrackVideo(e)},{passive:!0,signal:t})}untrackVideo(e){this.cleanupVideoListeners(e),this.activeVideos.has(e)&&(this.onVideoRemoved.dispatch(e),this.activeVideos.delete(e)),this.seenVideos.delete(e)}collectVideos(e){let t=new Set,n=e=>{for(let n of e)t.add(n)};if(e instanceof HTMLVideoElement&&t.add(e),(e instanceof Document||e instanceof DocumentFragment||e instanceof Element)&&n(e.querySelectorAll(`video`)),e instanceof Element){let t=e.shadowRoot;t&&n(t.querySelectorAll(`video`))}return Array.from(t)}getNowMs(){return typeof performance<`u`&&typeof performance.now==`function`?performance.now():Date.now()}isSliceBudgetReached(t,n){return n>=e.MAX_NODES_PER_SLICE?!0:this.getNowMs()-t>=e.MAX_FLUSH_BUDGET_MS}processPendingAdded(e){let t=0;for(;this.pendingAdded.size>0;){let n=this.pendingAdded.values().next();if(n.done||(this.pendingAdded.delete(n.value),this.scan(n.value),t+=1,this.isSliceBudgetReached(e,t)))break}return t}processPendingRemoved(e,t){let n=t;for(;this.pendingRemoved.size>0&&!this.isSliceBudgetReached(e,n);){let e=this.pendingRemoved.values().next();if(e.done)break;this.pendingRemoved.delete(e.value);for(let t of this.collectVideos(e.value))t.isConnected||this.untrackVideo(t);n+=1}return n}flushSlice=()=>{if(!this.enabled){this.pendingAdded.clear(),this.pendingRemoved.clear(),this.flushPending=!1;return}let e=this.getNowMs(),t=this.processPendingAdded(e);this.processPendingRemoved(e,t),this.flushPending=this.pendingAdded.size>0||this.pendingRemoved.size>0,this.flushPending&&this.intervalIdleChecker.requestImmediateTick()};onCheckerTick=()=>{this.flushPending&&this.flushSlice()};scheduleFlush=()=>{this.enabled&&(this.flushPending=!0,this.intervalIdleChecker.requestImmediateTick())};installAttachShadowHook(){if(this.attachShadowSubscriber)return;let e=Km();if(!e)return;let t=e=>{this.enabled&&(this.observeRoot(e),this.pendingAdded.add(e),this.scheduleFlush())};e.subscribers.add(t),this.attachShadowSubscriber=t}uninstallAttachShadowHook(){this.attachShadowSubscriber&&=(qm(this.attachShadowSubscriber),null)}enqueueAddedNode(e){if(e.nodeType===Node.ELEMENT_NODE){let t=e.shadowRoot;t&&this.observeRoot(t)}this.pendingAdded.add(e)}enqueueMutation(e){for(let t of e.addedNodes)this.enqueueAddedNode(t);for(let t of e.removedNodes)this.pendingRemoved.add(t)}onMutations(e){for(let t of e)t.type===`childList`&&this.enqueueMutation(t);(this.pendingAdded.size>0||this.pendingRemoved.size>0)&&this.scheduleFlush()}enable(){if(this.enabled)return;this.enabled=!0,this.checkerUnsubscribe?.(),this.checkerUnsubscribe=this.intervalIdleChecker.subscribe(this.onCheckerTick),this.intervalIdleChecker.start(),this.intervalIdleChecker.markActivity(`video-observer-enable`),this.installAttachShadowHook(),globalThis.addEventListener(`pageshow`,this.onPageShow,{passive:!0});let e=document.documentElement;if(e){this.observeRoot(e),this.scan(e);return}let t=()=>{let e=document.documentElement;e&&(document.removeEventListener(`readystatechange`,t),this.onDocumentReady=null,this.enabled&&(this.observeRoot(e),this.scan(e)))};this.onDocumentReady=t,document.addEventListener(`readystatechange`,t),typeof queueMicrotask==`function`?queueMicrotask(t):Promise.resolve().then(t)}disable(){this.enabled&&(this.enabled=!1,globalThis.removeEventListener(`pageshow`,this.onPageShow),this.onDocumentReady&&=(document.removeEventListener(`readystatechange`,this.onDocumentReady),null),this.uninstallAttachShadowHook(),this.observer.disconnect(),this.cleanupAllVideoListeners(),this.flushPending=!1,this.checkerUnsubscribe?.(),this.checkerUnsubscribe=null,this.intervalIdleChecker.stop(),this.pendingAdded.clear(),this.pendingRemoved.clear(),this.seenVideos=new WeakSet,this.activeVideos=new WeakSet,this.observedRoots=new WeakSet)}};function Ym(e,t){e.lastVideoPercent=W(t)}function Xm(e,t){e.lastTranslationPercent=W(t)}function Zm(e,t){let n=W(e);return{min:n,max:W(Math.min(100,t),n,100)}}function Qm({state:e,fromType:t,newVolume:n,currentVideo:r,currentTranslation:i,translationMin:a,translationMax:o}){let s=Zm(a,o);if(e.initialized||=(e.lastVideoPercent=W(r),e.lastTranslationPercent=Ec(Number(i),s.min,s.max),!0),t===`video`){let t=W(n),r=t-W(e.lastVideoPercent);e.lastVideoPercent=t;let i=Ec(e.lastTranslationPercent+r,s.min,s.max);return e.lastTranslationPercent=i,{nextTranslation:i}}let c=Ec(Number.isFinite(n)?n:i,s.min,s.max),l=c-e.lastTranslationPercent;e.lastTranslationPercent=c;let u=W(e.lastVideoPercent+l);return e.lastVideoPercent=u,{nextVideo:u}}var $m={allowTouchMoveHandler:!0,disableContainerDrag:!1},eh={xvideos:{allowTouchMoveHandler:!1},youtube:{disableContainerDrag:!0}};function th(e){if(!e)return $m;let t=eh[e]??{};return{...$m,...t}}var nh=0,rh=1,ih=Object.freeze({tickMs:50,thresholdOnRms:.012,thresholdOffRms:.009,rmsAttackTauMs:60,rmsReleaseTauMs:240,holdMs:520,attackTauMs:110,releaseTauMs:600,maxDownPerSec:3.5,maxUpPerSec:.9,rmsMissingGraceMs:200,maxDtMs:250,externalBaselineDelta01:.02,unduckTolerance01:.01,volumeStep01:Cc,applyDeltaThreshold01:Cc/2});function ah(e){return{isDucked:!1,speechGateOpen:!1,rmsEnvelope:0,baseline:mh(e),lastApplied:void 0,lastTickAt:0,lastSoundAt:0,rmsMissingSinceAt:null}}function oh(){return ah()}function sh(e,t,n,r,i){let a=t.speechGateOpen;return e.smartEnabled?e.audioIsPlaying&&!i?(t.rmsMissingSinceAt??=r,a&&(t.lastSoundAt=r),t.rmsMissingSinceAt!==null&&r-t.rmsMissingSinceAt>=n.rmsMissingGraceMs?(t.lastSoundAt=r,!0):a):(t.rmsMissingSinceAt=null,e.audioIsPlaying&&(!a&&t.rmsEnvelope>=n.thresholdOnRms||a&&t.rmsEnvelope>=n.thresholdOffRms)?(t.lastSoundAt=r,!0):a&&r-t.lastSoundAt<=n.holdMs):(t.lastSoundAt=r,t.rmsMissingSinceAt=null,!0)}function ch(e,t,n,r){e.isDucked&&hh(e.lastApplied)&&Math.abs(t-e.lastApplied)>r.externalBaselineDelta01&&(e.baseline=t),e.isDucked||(e.baseline=t);let i=e.baseline??n??t;return e.baseline=i,i}function lh(e,t,n,r,i,a){let o=Math.min(r,i);return t?(e.isDucked=!0,o):(e.isDucked&&Math.abs(r-n)0?-Math.expm1(-n/a):1,s=t+(e-t)*o,c=(e0&&(s=R(s,t-c,t+c)),R(s,nh,rh)}function dh(e,t,n,r){return Math.abs(n-t)=r?(e.lastApplied=n,{kind:`apply`,runtime:e,volume01:n}):{kind:`noop`,runtime:e}}function fh(e,t,n=ih){let r=ph(t),i=mh(e.volumeOnStart);if(!e.translationActive||!e.enabledAutoVolume)return{kind:`stop`,runtime:r,restoreVolume:r.baseline??i};let a=Number.isFinite(e.nowMs)?e.nowMs:Date.now(),o=R(a-(r.lastTickAt||a),0,n.maxDtMs),s=o/1e3;r.lastTickAt=a;let c=hh(e.rms),l=c?R(e.rms,nh,rh):0,u=r.rmsEnvelope,d=l>u?n.rmsAttackTauMs:n.rmsReleaseTauMs,f=d>0?-Math.expm1(-o/d):1;r.rmsEnvelope=R(u+(l-u)*f,nh,rh);let p=sh(e,r,n,a,c);r.speechGateOpen=p;let m=mh(e.currentVideoVolume);if(!hh(m))return{kind:`noop`,runtime:r};let h=ch(r,m,i,n);if(!e.hostVideoActive)return r.lastApplied=m,{kind:`noop`,runtime:r};let g=lh(r,p,m,h,mh(e.duckingTarget01)??h,n),_=jc(uh(g,m,o,s,n),m,g,n.volumeStep01),v=n.applyDeltaThreshold01;return dh(r,m,_,v)}function ph(e){return{isDucked:!!e.isDucked,speechGateOpen:!!e.speechGateOpen,rmsEnvelope:mh(e.rmsEnvelope)??0,baseline:mh(e.baseline),lastApplied:mh(e.lastApplied),lastTickAt:hh(e.lastTickAt)?e.lastTickAt:0,lastSoundAt:hh(e.lastSoundAt)?e.lastSoundAt:0,rmsMissingSinceAt:hh(e.rmsMissingSinceAt)?e.rmsMissingSinceAt:null}}function mh(e){if(hh(e))return R(e,nh,rh)}function hh(e){return typeof e==`number`&&Number.isFinite(e)}var gh=ih.tickMs,_h=new WeakMap;function vh(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.connect==`function`&&typeof t.disconnect==`function`}function yh(e){return e?.audio??e?.audioElement}function bh(){return typeof performance<`u`&&typeof performance.now==`function`?performance.now():Date.now()}function xh(e){return e.data?.enabledAutoVolume?e.data?.syncVolume?`classic`:e.data?.enabledSmartDucking??!0?`smart`:`classic`:`off`}function Sh(e){return e.audioPlayer?.audioContext??e.audioContext}function Ch(e){if(e.connectedInputNode&&e.analyser)try{e.connectedInputNode.disconnect(e.analyser)}catch{}if(e.connectedInputNode=void 0,e.createdMediaSource)try{e.createdMediaSource.disconnect()}catch{}if(e.createdMediaSource=void 0,e.analyser)try{e.analyser.disconnect()}catch{}e.analyser=void 0,e.analyserFloatData=void 0,e.analyserData=void 0,e.mediaElement=void 0,e.audioContext=void 0,e.mediaSourceCreationFailed=!1}function wh(e){let t=_h.get(e);t&&(Ch(t),_h.delete(e))}function Th(e,t,n,r){if(vh(e?.gainNode))return e.gainNode;if(vh(e?.audioSource))return e.audioSource;if(vh(e?.mediaElementSource))return e.mediaElementSource;if(!(r.mediaSourceCreationFailed&&r.mediaElement===t&&r.audioContext===n)){if(r.createdMediaSource&&r.mediaElement===t&&r.audioContext===n)return r.createdMediaSource;try{let e=n.createMediaElementSource(t);return r.createdMediaSource=e,r.mediaSourceCreationFailed=!1,e}catch(e){r.mediaSourceCreationFailed=!0,L.log(`[SmartDucking] failed to create media source`,e);return}}}function Eh(e,t,n){let r=Sh(e);if(!r)return;let i=_h.get(e);if(i||(i={},_h.set(e,i)),(i.mediaElement&&i.mediaElement!==n||i.audioContext&&i.audioContext!==r)&&Ch(i),i.mediaElement=n,i.audioContext=r,!i.analyser){let e=r.createAnalyser();e.fftSize=512,i.analyser=e}let a=Th(t,n,r,i),o=i.analyser;if(!(!a||!o)){if(i.connectedInputNode!==a){if(i.connectedInputNode)try{i.connectedInputNode.disconnect(o)}catch{}try{a.connect(o),i.connectedInputNode=a}catch(e){L.log(`[SmartDucking] failed to connect analyser`,e);return}}return{analyser:o,state:i}}}function Dh(e){return{isDucked:e.smartVolumeIsDucked,speechGateOpen:e.smartVolumeSpeechGateOpen,rmsEnvelope:e.smartVolumeRmsEnvelope,baseline:e.smartVolumeDuckingBaseline,lastApplied:e.smartVolumeLastApplied,lastTickAt:e.smartVolumeLastTickAt,lastSoundAt:e.smartVolumeLastSoundAt,rmsMissingSinceAt:e.smartVolumeRmsMissingSinceAt}}function Oh(e,t){e.smartVolumeIsDucked=t.isDucked,e.smartVolumeSpeechGateOpen=t.speechGateOpen,e.smartVolumeRmsEnvelope=t.rmsEnvelope,e.smartVolumeDuckingBaseline=t.baseline,e.smartVolumeLastApplied=t.lastApplied,e.smartVolumeLastTickAt=t.lastTickAt,e.smartVolumeLastSoundAt=t.lastSoundAt,e.smartVolumeRmsMissingSinceAt=t.rmsMissingSinceAt}function kh(e,t={}){let{restoreVolume:n}=t;e.smartVolumeDuckingInterval!==void 0&&(clearTimeout(e.smartVolumeDuckingInterval),e.smartVolumeDuckingInterval=void 0);let r=typeof n==`number`?n:e.smartVolumeDuckingBaseline??e.volumeOnStart;if(typeof r==`number`&&(typeof n==`number`||e.smartVolumeIsDucked))try{e.setVideoVolume(r)}catch{}wh(e),Oh(e,oh())}function Ah(e){typeof globalThis>`u`||e.smartVolumeDuckingInterval!==void 0&&(e.smartVolumeDuckingInterval=globalThis.setTimeout(()=>{if(e.smartVolumeDuckingInterval!==void 0){try{Nh(e)}catch(t){L.log(`[SmartDucking] tick failed, stopping smart ducking`,t),kh(e);return}e.smartVolumeDuckingInterval!==void 0&&Ah(e)}},gh))}function jh(e){if(typeof globalThis>`u`||e.smartVolumeDuckingInterval!==void 0||xh(e)!==`smart`)return;let t=e.getVideoVolume(),n=typeof e.smartVolumeDuckingBaseline==`number`?e.smartVolumeDuckingBaseline:t,r=ah(n);if(Number.isFinite(t)&&Number.isFinite(n)&&t{},0),clearTimeout(e.smartVolumeDuckingInterval),Ah(e)}function Mh(e,t){let n=e.audioPlayer?.player,r=Eh(e,n,t);if(!r)return;let{analyser:i,state:a}=r;try{if(typeof i.getFloatTimeDomainData==`function`){let e=a.analyserFloatData;e?.length!==i.fftSize&&(e=new Float32Array(i.fftSize),a.analyserFloatData=e),i.getFloatTimeDomainData(e);let t=0;for(let n of e)t+=n*n;return R(Math.sqrt(t/e.length),0,1)}let e=a.analyserData;e?.length!==i.fftSize&&(e=new Uint8Array(i.fftSize),a.analyserData=e),i.getByteTimeDomainData(e);let t=0;for(let n of e){let e=(n-128)/128;t+=e*e}return R(Math.sqrt(t/e.length),0,1)}catch{return}}function Nh(e){if(xh(e)!==`smart`){Ph.call(e);return}let t=e.audioPlayer?.player,n=yh(t),r=!!n&&!n.paused&&!n.muted&&(n.volume??1)>.001,i=bh(),a=e.getVideoVolume(),o=e.video,s=!(o&&(o.paused||o.ended)),c=R(e.data?.autoVolume??15,0,100)/100;e.smartVolumeDuckingTarget=c;let l=r&&n?Mh(e,n):0,u=fh({nowMs:i,translationActive:e.hasActiveSource(),enabledAutoVolume:!0,smartEnabled:!0,audioIsPlaying:r,rms:l,currentVideoVolume:a,hostVideoActive:s,duckingTarget01:c,volumeOnStart:e.volumeOnStart},Dh(e),ih);switch(u.kind){case`stop`:kh(e,{restoreVolume:u.restoreVolume});return;case`apply`:e.setVideoVolume(u.volume01),Oh(e,u.runtime);return;case`noop`:Oh(e,u.runtime);return;default:throw TypeError(`Unhandled smart ducking decision`)}}function Ph(){typeof this.data?.defaultVolume==`number`&&(this.audioPlayer.player.volume=this.data.defaultVolume/100);let e=xh(this);if(e===`off`){kh(this,{restoreVolume:this.smartVolumeDuckingBaseline??this.volumeOnStart});return}let t=R(this.data.autoVolume??15,0,100)/100;if(this.smartVolumeDuckingTarget=t,!this.hasActiveSource())return;if(e===`smart`){jh(this);return}this.smartVolumeDuckingInterval!==void 0&&(clearTimeout(this.smartVolumeDuckingInterval),this.smartVolumeDuckingInterval=void 0),typeof this.smartVolumeDuckingBaseline!=`number`&&(this.smartVolumeDuckingBaseline=this.getVideoVolume());let n=this.smartVolumeDuckingBaseline??this.getVideoVolume();this.setVideoVolume(Math.min(n,t)),Oh(this,ah(this.smartVolumeDuckingBaseline)),this.smartVolumeIsDucked=!0}function Fh(e){if(!this.data?.enabledAutoVolume||!this.hasActiveSource())return;let t=Ac(e);this.smartVolumeDuckingTarget=t,this.smartVolumeDuckingBaseline=t,this.smartVolumeLastApplied=t}var Ih=`https://vtrans.s3-private.mds.yandex.net/tts/prod/`,Lh=`/video-translation/audio-proxy/`,Rh=`https://brosubs.s3-private.mds.yandex.net/vtrans/`,zh=`/video-subtitles/subtitles-proxy/`;function Bh(e){return e??`vot-worker.kload.workers.dev`}function Vh(e){return!!e.translateProxyEnabled}function Hh(e){return e.translateProxyEnabled===2}function Uh(e){return!!(e.gmXhrSupported&&Vh(e))}function Wh(e,t){return!Hh(t)||!e.startsWith(Ih)?e:e.replace(Ih,`https://${Bh(t.proxyWorkerHost)}${Lh}`)}function Gh(e){let t=String(e||``);if(!t)return t;try{let e=new URL(t);return e.pathname.startsWith(Lh)?(e.host=`vtrans.s3-private.mds.yandex.net`,e.pathname=`/tts/prod/${e.pathname.slice(31).replace(/^\/+/,``)}`,e.protocol=`https:`,e.toString()):t}catch{return t}}function Kh(e,t){return e.startsWith(Ih)||e.startsWith(`https://${Bh(t.proxyWorkerHost)}${Lh}`)}function qh(e,t){if(!Hh(t)||!e.startsWith(Rh))return e;let n=e.slice(49);return`https://${Bh(t.proxyWorkerHost)}${zh}${n}`}var Jh=`disabled`,Yh=/^\d+$/u,[Xh,Zh]=Di;function Qh(e){let t=[];for(let n=0;n=e.length?null:fu(e[t])}function tg(){return{label:V.get(`VOTSubtitlesDisabled`),value:Jh,selected:!0,disabled:!1}}function ng(e){return`${V.getLangLabel(e.language)}${e.translatedFromLanguage?` ${V.get(`VOTTranslatedFrom`)} ${V.getLangLabel(e.translatedFromLanguage)}`:``}${e.source===`yandex`?``:`, ${globalThis.location.hostname}`}${e.isAutoGenerated?` (${V.get(`VOTAutogenerated`)})`:``}`}function rg(e){let t=[tg()];for(let{descriptor:n,index:r}of e)t.push({label:ng(n),value:String(r),selected:!1,disabled:!1});return t}function ig(e){let t=e[Symbol.iterator]().next();return t.done?void 0:t.value}function ag(e){return(e??``).toLowerCase()}function og(e){return ag(e).split(/[-_]/)[0]}function sg(e,t){if(!e||!t)return!1;let n=ag(e),r=ag(t);return n===r||og(n)===og(r)}function cg(e,t,n){if(e===Zh){let e=ag(t);return e&&e!==Xh?e:void 0}return typeof e==`string`&&e&&e!==Xh?ag(e):ag(n)||ag(t)}function lg(e,t,n){if(!e.length)return null;let r=ag(t),i=ag(n),a=r===`auto`||r===``,o=og(r),s=og(i),c=e=>e.source===`yandex`,l=e=>!!e.isAutoGenerated,u=(e,t,n)=>sg(e.language,n)?a?!0:sg(e.translatedFromLanguage,t):!1,d=(e,t)=>sg(e.language,t)?e.translatedFromLanguage?sg(e.translatedFromLanguage,t):!0:!1,f=t=>e.find(({descriptor:e})=>t(e))?.index??null,p=()=>f(e=>!c(e)&&sg(e.language,i)&&!l(e))??f(e=>!c(e)&&sg(e.language,i)&&l(e));if(!a&&o&&s&&o===s){let e=f(e=>d(e,i)&&!l(e));if(e!=null)return e;let t=f(e=>d(e,i)&&l(e));if(t!=null)return t;let n=p();if(n!=null)return n;let r=f(e=>c(e)&&sg(e.language,i));if(r!=null)return r}return f(e=>c(e)&&u(e,r,i))??f(e=>c(e)&&sg(e.language,i))??f(e=>!c(e)&&u(e,r,i))??p()??null}var ug=5e3,dg=150,fg=2;async function pg(e){let t=e.audioPlayer?.audioContext;if(!t||t.state!==`suspended`)return`not-needed`;let n=(async()=>{try{return await t.resume(),`resumed`}catch(e){return L.log(`[updateTranslation] Failed to resume AudioContext`,e),`failed`}})(),r,i=new Promise(e=>{r=setTimeout(()=>e(`timeout`),1500)}),a=await Promise.race([n,i]);return r!==void 0&&clearTimeout(r),a===`resumed`?L.log(`[updateTranslation] AudioContext resumed`):a===`timeout`&&L.log(`[updateTranslation] AudioContext resume timeout`),a}async function mg(e,t){if(!t||!e.audioPlayer)return;let n=e.audioPlayer.player,r=String(n.currentSrc||n.src||``);if(e.proxifyAudio(e.unproxifyAudio(r))===e.proxifyAudio(e.unproxifyAudio(t)))try{await n.clear(),n.src=``,L.log(`[updateTranslation] cleared stale partially-applied source`)}catch(e){L.log(`[updateTranslation] failed to clear stale source`,e)}}function hg(e,t){return e<=0||t.aborted?Promise.resolve():new Promise(n=>{let r=setTimeout(()=>{t.removeEventListener(`abort`,i),n()},e),i=()=>{clearTimeout(r),t.removeEventListener(`abort`,i),n()};t.addEventListener(`abort`,i,{once:!0})})}async function gg(e,t,n){let r=e.actionsAbortController.signal,i={headers:{range:`bytes=0-0`},signal:r,timeout:ug};for(let a=1;a<=fg;a++){if(_g(e,n,r))return!1;try{let o=await z(t,i);if(_g(e,n,r))return!1;if(L.log(`[validateAudioUrl] probe response`,{audioUrl:t,attempt:a,ok:o.ok,status:o.status}),o.ok)return!0}catch(i){if(_g(e,n,r))return!1;L.log(`[validateAudioUrl] probe error`,{audioUrl:t,attempt:a,err:i})}if(!await vg(a,e,n,r))return!1}return!1}function _g(e,t,n){return e.isActionStale(t)||n.aborted}async function vg(e,t,n,r){return e>=fg?!0:_g(t,n,r)?!1:(await hg(dg,r),!_g(t,n,r))}async function yg(e,t){if(this.isActionStale(t)||await gg(this,e,t))return e;let n=this.unproxifyAudio(e);return n!==e&&await gg(this,n,t)?(L.log(`[validateAudioUrl] switching to direct audio URL after probe`),n):e}function bg(){!this.videoData||this.videoData.isStream||this.hasActiveSource()&&this.refreshTranslationAudio().catch(e=>{L.log(`[scheduleTranslationRefresh] refresh failed`,e)})}async function xg(){if(!this.videoData||this.videoData.isStream||!this.hasActiveSource())return;let e=this.videoData.videoId;if(!e)return;let t=Is(this.videoData.translationHelp),n=this.getTranslationCacheKey(e,this.translateFromLang,this.translateToLang,t);this.cacheManager.getTranslation(n)?.url||(L.log(`[scheduleTranslationRefresh] translation cache expired after resume, refreshing now`),await this.refreshTranslationAudio())}async function Sg(e,t){let n=await Bs({requester:e.translationHandler,request:{videoData:t.videoData,requestLang:t.requestLang,responseLang:t.responseLang,translationHelp:t.translationHelp,useAudioDownload:!!e.data?.useAudioDownload,signal:e.actionsAbortController.signal},actionContext:t.actionContext,isActionStale:t=>e.isActionStale(t),updateTranslation:(t,n)=>e.updateTranslation(t,n)});return n?(t.onBeforeCache&&await t.onBeforeCache(n),Vs({cacheKey:t.cacheKey,setTranslation:(t,n)=>e.cacheManager.setTranslation(t,n),videoId:t.cacheVideoId,requestLang:t.cacheRequestLang,responseLang:t.cacheResponseLang,fallbackUrl:n.url,downloadTranslationUrl:e.downloadTranslationUrl,usedLivelyVoice:n.usedLivelyVoice}),n):null}async function Cg(){if(!this.videoData||this.videoData.isStream||!this.hasActiveSource()||this.isRefreshingTranslation)return;let e=this.videoData.videoId;if(!e)return;this.actionsAbortController?.signal?.aborted&&this.resetActionsAbortController(`refreshTranslationAudio`),this.isRefreshingTranslation=!0;let t={gen:this.actionsGeneration,videoId:e},n=Is(this.videoData.translationHelp);try{if(!await Sg(this,{videoData:this.videoData,requestLang:this.translateFromLang,responseLang:this.translateToLang,translationHelp:n,actionContext:t,cacheKey:this.getTranslationCacheKey(e,this.translateFromLang,this.translateToLang,n),cacheVideoId:e,cacheRequestLang:this.translateFromLang,cacheResponseLang:this.translateToLang}))return}finally{this.isRefreshingTranslation=!1}}function wg(e){let t=Wh(e,{translateProxyEnabled:this.data?.translateProxyEnabled,proxyWorkerHost:this.data?.proxyWorkerHost});return t!==e&&L.log(`[VOT] Audio proxied via ${t}`),t}function Tg(e){return Gh(e)}async function Eg(e=`proxySettingsChanged`){L.log(`[VOT] ${e}: clearing translation/subtitles cache`);try{this.cacheManager.clear(),this.activeTranslation=null}catch{}try{await this.stopTranslation()}catch{}await this.initVOTClient()}function Dg(e){return Kh(e,{proxyWorkerHost:this.data?.proxyWorkerHost})}function Og(e,t){return e.proxifyAudio(e.unproxifyAudio(t))}async function kg(e,t,n){let r=e.audioPlayer.player.src!==t,i=null;r&&(e.audioPlayer.player.src=t,i=t);try{if(r&&await e.audioPlayer.init(),e.isActionStale(n))return await mg(e,i),{status:`stale`,didSetSource:r,appliedSourceUrl:i};let t=await pg(e);return t===`timeout`?L.log(`[updateTranslation] continuing after AudioContext resume timeout`):t===`failed`&&L.log(`[updateTranslation] AudioContext resume failed, continue without deferred resume`),e.isActionStale(n)?(await mg(e,i),{status:`stale`,didSetSource:r,appliedSourceUrl:i}):(!e.video.paused&&e.audioPlayer.player.src&&e.audioPlayer.player.lipSync(`play`),{status:`success`,didSetSource:r,appliedSourceUrl:i})}catch(e){return{status:`error`,didSetSource:r,appliedSourceUrl:i,error:e}}}async function Ag(e,t){if(await this.waitForPendingStopTranslate(),this.isActionStale(t))return;this.audioPlayer||this.createPlayer(),this.audioPlayer.audioContext?.state===`closed`&&(L.log(`[updateTranslation] AudioContext is closed, recreating player`),this.createPlayer());let n=Og(this,e),r=this.audioPlayer.player.currentSrc||this.audioPlayer.player.src||``,i=n===Og(this,r)?n:await this.validateAudioUrl(n,t);if(this.isActionStale(t))return;let a=await jg(this,i,t),o=a.nextAudioUrl,s=a.applyResult,c=s.appliedSourceUrl;if(s.status!==`stale`){if(s.status===`error`){L.log(`this.audioPlayer.init() error`,s.error),await mg(this,c);let e=ya(s.error);this.transformBtn(`error`,e);return}this.clearVolumeLinkState(),this.setupAudioSettings(),this.transformBtn(`success`,V.get(`disableTranslate`)),this.afterUpdateTranslation(o)}}async function jg(e,t,n){let r=t,i=await kg(e,r,n);return Mg(e,i,n,r)&&await Ng(e,r,i.appliedSourceUrl,n)||{nextAudioUrl:r,applyResult:i}}function Mg(e,t,n,r){return t.status===`error`&&t.didSetSource&&!e.isActionStale(n)&&e.unproxifyAudio(r)!==r}async function Ng(e,t,n,r){let i=e.unproxifyAudio(t);L.log(`[updateTranslation] proxied audio init failed, retrying direct URL`);try{let t=await e.validateAudioUrl(i,r);return e.isActionStale(r)?(await mg(e,n),{nextAudioUrl:t,applyResult:{status:`stale`,didSetSource:!0,appliedSourceUrl:n}}):{nextAudioUrl:t,applyResult:await kg(e,t,r)}}catch(e){return{nextAudioUrl:t,applyResult:{status:`error`,didSetSource:!0,appliedSourceUrl:n,error:e}}}}async function Pg(e,t,n,r,i){await this.waitForPendingStopTranslate(),L.log(`Run videoValidator`),await this.videoValidator(),this.actionsAbortController?.signal?.aborted&&this.resetActionsAbortController(`translateFunc`);let a=this.uiManager.votOverlayView;if(!a?.votButton){L.log(`[translateFunc] Overlay view missing, skipping translation`);return}if(a.votButton.loading=!0,this.hadAsyncWait=!1,this.volumeOnStart=this.getVideoVolume(),!e){L.log(`Skip translation - no VIDEO_ID resolved yet`),await this.updateTranslationErrorMsg(new U(`VOTNoVideoIDFound`),this.actionsAbortController.signal);return}let o=this.videoData;if(!o){await this.updateTranslationErrorMsg(new U(`VOTNoVideoIDFound`),this.actionsAbortController.signal);return}let s=Is(i),c=this.getTranslationCacheKey(e,n,r,s),l=`video_${c}`;if(this.activeTranslation?.key===l){L.log(`[translateFunc] Reusing in-flight translation`),await this.activeTranslation.promise;return}let u={gen:this.actionsGeneration,videoId:e},d=(async()=>{if(this.isActionStale(u)){L.log(`[translateFunc] Stale translation task - skipping`);return}let t=n,i=r,a=async e=>await this.updateTranslation(e,u),l=this.cacheManager.getTranslation(c);if(l?.url){await a(l.url),L.log(`[translateFunc] Cached translation was received`);return}let d=await Sg(this,{videoData:o,requestLang:t,responseLang:i,translationHelp:s,actionContext:u,cacheKey:c,cacheVideoId:e,cacheRequestLang:n,cacheResponseLang:r,onBeforeCache:async()=>{let t=this.getPreferredSubtitlesLanguage(o.detectedLanguage,o.responseLanguage);if(!t)return;let n=this.videoData?this.getSubtitlesCacheKey(e,this.videoData.detectedLanguage,t):null,r=n?this.cacheManager.getSubtitles(n):null;Array.isArray(r)&&lg(Qh(r),o.detectedLanguage,t)!=null||(n&&this.cacheManager.deleteSubtitles(n),this.subtitles=[],this.subtitlesCacheKey=null)}});L.log(`[translateRes]`,d),d||L.log(`Skip translation`)})();this.activeTranslation={key:l,promise:d};try{return await d}catch(t){throw this.hadAsyncWait=Hs({aborted:this.actionsAbortController.signal.aborted,translateApiErrorsEnabled:!!this.data?.translateAPIErrors,hadAsyncWait:this.hadAsyncWait,videoId:e,error:t,notify:e=>this.notifier.translationFailed(e)}),t}finally{this.activeTranslation?.promise===d&&(this.activeTranslation=null);let e=this.uiManager.votOverlayView?.votButton;!this.activeTranslation&&e?.loading&&!this.hasActiveSource()&&(L.log(`[translateFunc] clearing stale loading state`),this.transformBtn(`none`,V.get(`translateVideo`)))}}function Fg(){return Bc(this.site.host)}function Ig(e,t){if(!t||t===e||e.aborted)return e;if(t.aborted)return t;if(typeof AbortSignal<`u`&&`any`in AbortSignal)return AbortSignal.any([e,t]);let n=new AbortController,r=()=>{e.removeEventListener(`abort`,i),t.removeEventListener(`abort`,a)},i=()=>{r(),n.abort(e.reason)},a=()=>{r(),n.abort(t.reason)};return e.addEventListener(`abort`,i,{once:!0}),t.addEventListener(`abort`,a,{once:!0}),n.signal}function Lg(e){let t=(t,n,r,i)=>{let a=Ig(e,i?.signal);if(!i){t.addEventListener(n,r,{signal:a});return}let{signal:o,...s}=i;t.addEventListener(n,r,{...s,signal:a})};return{add:t,addMany:(e,n,r,i)=>{for(let a of n)t(e,a,r,i)}}}function Rg(e,t,n){e(t,[`focusin`],e=>n.handleOverlayInteraction(e)),e(t,[`focusout`],e=>n.scheduleHide(e)),!(Eo()&&globalThis.window!==void 0)&&(e(t,[`pointerenter`],e=>n.handleOverlayInteraction(e)),e(t,[`pointermove`],e=>n.handleOverlayInteraction(e),{passive:!0}),e(t,[`pointerleave`],e=>n.scheduleHide(e)))}function zg(e,t=0){let n=typeof e==`number`?e:Number(e);return Number.isFinite(n)?W(n):t}function Bg(e,t,n={}){n.skipYouTubeLikeHosts&&Lc(e.site.host)||e.smartVolumeDuckingInterval===void 0&&(!e.data?.syncVolume||!e.audioPlayer?.player?.src||e.isLikelyInternalVideoVolumeChange(t)||e.syncVolumeWrapper(`video`,t))}function Vg(e,t,n){let r=t.votMenu?.container;if(r){let t=n??e.video.getBoundingClientRect().height;r.style.setProperty(`--vot-container-height`,`${t}px`)}let{position:i,direction:a}=t.calcButtonLayout(e.data?.buttonPos??`default`);t.updateButtonLayout(i,a)}function Hg(e){return e.replace(`Key`,``).replace(`Digit`,``)}function Ug(e){let t=new Set;for(let n of e)t.add(Hg(n));return t}function Wg(e,t){if(!e)return null;let n=t.get(e);if(n)return n;let r=e.split(`+`).filter(Boolean).map(Hg),i={parts:r,partsSet:new Set(r)};return t.set(e,i),i}function Gg(e,t){if(!t||e.size!==t.parts.length)return!1;for(let n of t.partsSet)if(!e.has(n))return!1;return!0}function Kg(e){let{self:t,overlayView:n,addMany:r}=e,i=()=>{t.refreshOverlayMount(),Vg(t,n)};t.resizeObserver=new ResizeObserver(e=>{for(let r of e)Vg(t,n,r.contentRect.height)}),t.resizeObserver.observe(t.video),i(),r(document,[`fullscreenchange`,`webkitfullscreenchange`],()=>i()),r(t.video,[`webkitbeginfullscreen`,`webkitendfullscreen`],()=>i())}function qg(e){let{self:t}=e;if(!zc(t.site))return;t.syncVolumeObserver=new MutationObserver(e=>{if(!t.audioPlayer?.player?.src)return;let n=!1;for(let t of e)t.type!==`attributes`||t.attributeName!==`aria-valuenow`||(n=!0);if(!n)return;t.syncVideoVolumeSlider();let r=t.uiManager.votOverlayView;r?.isInitialized()&&Bg(t,zg(r.videoVolumeSlider.value))});let n=document.querySelector(`.ytp-volume-panel`);n&&t.syncVolumeObserver.observe(n,{attributes:!0,subtree:!0,attributeFilter:[`aria-valuenow`]})}function Jg(e){let{self:t}=e;if(t.site.host!==`youtube`||t.site.additionalData===`mobile`)return;let n=async()=>{try{if(!t.videoData)return;let e=F.getPlayer(),n=e?.getAvailableAudioTracks?.()??null;if(!Array.isArray(n)||n.length<=1)return;let r=e?.getAudioTrack?.()?.getLanguageInfo?.()?.id,i=r&&r!==`und`?r.toLowerCase().split(/[-_.]/)[0]:void 0;if(!i||!yn.includes(i))return;let a=i;if(a===t.videoData.detectedLanguage)return;if(t.videoManager.rememberDetectedLanguage(t.videoData.videoId,a),t.setSelectMenuValues(a,t.videoData.responseLanguage),t.data?.autoTranslate&&a!==t.videoData.responseLanguage){L.log(`[VOT] Audio track language changed to ${a}, triggering auto-translation`);try{await t.uiManager.handleTranslationBtnClick()}catch(e){L.log(`[VOT] Failed to trigger auto-translation on audio track change:`,e)}}}catch(e){L.log(`[VOT] Failed to sync audio track language`,e)}},r=F.getPlayer(),i=[`onApiChange`,`onStateChange`];if(r?.addEventListener)for(let e of i)try{r.addEventListener(e,n)}catch(t){L.log(`[VOT] Failed to bind ${e}`,t)}n(),t.abortController.signal.addEventListener(`abort`,()=>{if(r?.removeEventListener)for(let e of i)try{r.removeEventListener(e,n)}catch(t){L.log(`[VOT] Failed to unbind ${e}`,t)}},{once:!0})}function Yg(e){let{self:t,overlayView:n,add:r,addMany:i,platformConfig:a}=e;r(document,`click`,e=>{let r=e.target,i=n.votButton?.container,a=n.votMenu?.container,o=t.uiManager.votSettingsView?.dialog?.container,s=r&&i?i.contains(r):!1,c=r&&a?a.contains(r):!1,l=r?t.container.contains(r):!1,u=r&&o?o.contains(r):!1,d=r instanceof Element&&r.closest(`.vot-dialog-temp`)instanceof Element;L.log(`[document click] ${s} ${c} ${l} ${u} ${d}`),!(s||c||u||d)&&(l||n.updateButtonOpacity(0),a&&!a.hidden&&(a.hidden=!0,t.overlayVisibility?.queueAutoHide()))});let o=new Set,s=new Map,c=()=>o.clear(),l=(e,t)=>{e().catch(e=>{L.log(`[VOT] ${t} hotkey action failed`,e)})};r(document,`keydown`,e=>{let n=e;if(n.repeat)return;o.add(n.code);let r=Fo(document),i=r?.tagName?.toLowerCase?.()??``;if([`input`,`textarea`].includes(i)||r?.isContentEditable)return;let a=Ug(o);if(Gg(a,Wg(t.data?.translationHotkey,s))){c(),l(()=>t.uiManager.handleTranslationBtnClick(),`Translation`);return}Gg(a,Wg(t.data?.subtitlesHotkey,s))&&(c(),l(()=>t.toggleSubtitlesForCurrentLangPair(),`Subtitles`))}),r(document,`keyup`,e=>o.delete(e.code)),r(document,`blur`,c),r(document,`visibilitychange`,()=>{document.hidden&&c()}),r(globalThis,`blur`,c);let u=t.getEventContainer();if(u){let e=Eo()&&globalThis.window!==void 0,n=e?globalThis.window:u;e?(i(n,[`pointermove`,`pointerdown`],e=>t.overlayVisibility.handleHostInteraction(e),{passive:!0}),r(n,`blur`,()=>t.overlayVisibility.scheduleHide())):(i(n,[`pointerenter`,`pointerdown`],e=>t.overlayVisibility.handleHostInteraction(e)),r(n,`pointermove`,e=>t.overlayVisibility.handleHostInteraction(e),{passive:!0}),r(n,`pointerleave`,e=>t.overlayVisibility.scheduleHide(e)))}t.rebindOverlayVisibilityTargets(),a.allowTouchMoveHandler&&r(document,`touchmove`,e=>t.overlayVisibility.handleHostInteraction(e),{passive:!0}),a.disableContainerDrag&&(t.container.draggable=!1)}function Xg(e){let{self:t,add:n}=e,r=!1,i=()=>{r=!1};n(t.video,`pause`,()=>{r=!0}),n(t.video,`playing`,()=>{r&&(r=!1,xg.call(t).catch(e=>{L.log(`[VOT] Failed to refresh translation after playback resumed`,e)}))}),n(t.video,`loadstart`,i),n(t.video,`emptied`,i)}function Zg(e){let{self:t,overlayView:n,add:r}=e,i=async()=>{try{await t.setCanPlay()}catch(e){L.log(`[VOT] setCanPlay() failed`,e)}},a=!1,o=()=>{a||(a=!0,queueMicrotask(async()=>{a=!1,await i()}))};r(t.video,`canplay`,()=>{t.site.host===`rutube`&&t.video.src||o()});let s=async()=>{let e;try{e=await Kr(t.site,{fetchFn:z,video:t.video})}catch(e){L.log(`[VOT] Failed to resolve video id on emptied`,e)}t.videoData&&e&&e===t.videoData.videoId||(L.log(`lipsync mode is emptied`),Zs(t,n,{clearVideoData:!0,hideMenu:!0}))};r(t.video,`emptied`,()=>{s().catch(e=>{L.log(`[VOT] Failed to handle emptied lifecycle event`,e)})}),Rc(t.site.host)||r(t.video,`volumechange`,()=>{t.syncVideoVolumeSlider();let e=t.uiManager.votOverlayView;e?.isInitialized()&&Bg(t,zg(e.videoVolumeSlider.value),{skipYouTubeLikeHosts:!0})}),t.site.host===`youtube`&&!t.site.additionalData&&r(document,`yt-page-data-updated`,()=>{L.log(`yt-page-data-updated`),globalThis.location.pathname.startsWith(`/shorts/`)&&o()})}function Qg(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return;let{add:t,addMany:n}=Lg(this.abortController.signal),r={self:this,overlayView:e,platformConfig:th(this.site.host),add:t,addMany:n};Xg(r),Kg(r),qg(r),Jg(r),Yg(r),Zg(r)}function $g(){this.overlayVisibilityTargetsAbortController?.abort(),this.overlayVisibilityTargetsAbortController=new AbortController;let{signal:e}=this.overlayVisibilityTargetsAbortController,t=this.uiManager?.votOverlayView?.votButton?.container,n=this.uiManager?.votOverlayView?.votMenu?.container;if(!t||!n||!this.overlayVisibility)return;let r=this.overlayVisibility,{addMany:i}=Lg(e);Rg(i,t,r),Rg(i,n,r)}function e_(e){if(!(e instanceof Node))return!1;let t=this.uiManager?.votOverlayView,n=t?.votButton?.container,r=t?.votMenu?.container;return n instanceof Node&&Io(n,e)||r instanceof Node&&Io(r,e)}function t_(){let e=this.data?.autoHideButtonDelay;return typeof e==`number`&&Number.isFinite(e)?e:Ti}function n_(){this.resizeObserver?.disconnect(),this.overlayVisibilityTargetsAbortController?.abort(),this.overlayVisibilityTargetsAbortController=void 0,zc(this.site)&&this.syncVolumeObserver?.disconnect()}var r_;function i_(e){r_=e}var a_=null;async function o_(){r_||(a_??=(async()=>{try{i_((await(await z(`https://cloudflare-dns.com/cdn-cgi/trace`,{timeout:7e3})).text()).split(` +`).find(e=>e.startsWith(`loc=`))?.slice(4,6).toUpperCase())}catch(e){console.error(`[VOT] Error getting country:`,e)}})().finally(()=>{a_=null}),await a_)}async function s_(){if(this.initialized)return;let e=this.isAudioContextSupported;this.data=await B.getValues({autoTranslate:!1,autoSubtitles:!1,dontTranslateLanguages:[Ni],enabledDontTranslateLanguages:!0,enabledAutoVolume:!0,enabledSmartDucking:!0,autoVolume:15,buttonPos:`default`,showVideoSlider:!0,syncVolume:!1,downloadWithName:La,sendNotifyOnComplete:!1,subtitlesMaxLength:300,subtitlesSmartLayout:!0,highlightWords:!1,subtitlesFontSize:20,subtitlesFontFamily:`default-sans`,subtitlesOpacity:20,subtitlesDownloadFormat:`srt`,responseLanguage:Ni,responseLanguageSubtitles:`auto`,defaultVolume:100,onlyBypassMediaCSP:e,newAudioPlayer:e,showPiPButton:!1,translateAPIErrors:!0,translationService:Si,detectService:Ci,translationHotkey:null,subtitlesHotkey:null,m3u8ProxyHost:di,proxyWorkerHost:pi,translateProxyEnabled:0,translateProxyEnabledDefault:!0,audioBooster:!1,useLivelyVoice:!1,autoHideButtonDelay:Ti,useAudioDownload:La,compatVersion:``,account:{},localeHash:``,localeUpdatedAt:0}),this.data.compatVersion!==`2025-05-09`&&(this.data=await io(this.data),await B.set(`compatVersion`,Ei));try{if(Ni===`en`&&this.data?.enabledDontTranslateLanguages&&Array.isArray(this.data?.dontTranslateLanguages)&&this.data.dontTranslateLanguages.length===1&&this.data.dontTranslateLanguages[0]===`en`&&typeof this.data.responseLanguage==`string`&&this.data.responseLanguage!==`en`){let e=this.data.responseLanguage;this.data.dontTranslateLanguages=[e],await B.set(`dontTranslateLanguages`,this.data.dontTranslateLanguages)}}catch{}this.uiManager.data=this.data,console.log(`[VOT] data from db:`,this.data),!this.data.translateProxyEnabled&&Fa&&(this.data.translateProxyEnabled=1),await o_(),r_&&wi.includes(r_)&&this.data.translateProxyEnabledDefault&&(this.data.translateProxyEnabled=2),L.log(`translateProxyEnabled`,this.data.translateProxyEnabled,this.data.translateProxyEnabledDefault),L.log(`Extension compatibility passed...`),await this.initVOTClient(),this.uiManager.initUI(),this.uiManager.initUIEvents(),this.uiManager.votOverlayView?.votButton?.container&&(this.uiManager.votOverlayView.votButton.container.hidden=!0),this.createPlayer(),this.translateToLang=this.data.responseLanguage??`ru`,this.initExtraEvents(),this.initialized=!0}var c_=`und`,l_=new Map,u_=new Map,d_=e=>{if(e)try{return Intl.getCanonicalLocales(e)[0]}catch{return}},f_=e=>{let t=d_(e);if(t)return Intl.Segmenter.supportedLocalesOf([t])[0]},p_=(e,t)=>{let n=f_(e),r=`${t}:${n??c_}`,i=t===`sentence`?u_:l_,a=i.get(r);if(a)return a;let o=new Intl.Segmenter(n,{granularity:t});return i.set(r,o),o},m_=(e,t)=>e?Array.from(p_(t,`word`).segment(e),e=>({text:e.segment,index:e.index,isWordLike:!!e.isWordLike})):[],h_=(e,t)=>e?Array.from(p_(t,`sentence`).segment(e),e=>({text:e.segment,index:e.index})):[],g_=/\s/u,__=/^[,.:;!?%)\]}>»]/u,v_=/[([{<«'"-]$/u,y_=/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u,b_=(e,t)=>{let n=e.at(-1)??``,r=t[0]??``;return!(!n||!r||g_.test(n)||g_.test(r)||v_.test(n)||__.test(r)||y_.test(n)&&y_.test(r))},x_=/\s/u,S_=e=>!!e.trim(),C_=e=>{let t=``,n=``,r=[];for(let i of e){let e=i.text.trim();if(!e)continue;t&&b_(n,e)&&(t+=` `);let a=t.length;t+=e;let o=t.length;r.push({line:{...i,text:e},text:e,start:a,end:o}),n=e}return{streamText:t,spans:r}},w_=(e,t,n)=>{let r=t,i=n;for(;rr&&x_.test(e[i-1]??``);)--i;return r>=i?null:{start:r,end:i}},T_=(e,t,n)=>{let r=Math.max(t,e.start),i=Math.min(n,e.end);if(r>=i)return null;let a=r-e.start,o=i-e.start,s=e.text.slice(a,o);if(!s)return null;let c=Math.max(e.text.length,1),l=e.line.startMs+Math.round(e.line.durationMs*a/c),u=e.line.startMs+Math.round(e.line.durationMs*o/c);return{text:s,startMs:l,durationMs:Math.max(0,u-l),isWordLike:S_(s)}},E_=(e,t,n)=>{let r=n.index,i=w_(e,r,r+n.text.length);if(!i)return null;let a=e.slice(i.start,i.end);if(!S_(a))return null;let o=[],s=`0`;for(let e of t){let t=T_(e,i.start,i.end);t&&(o.length===0&&(s=e.line.speakerId),o.push(t))}if(!o.length)return null;let c=Math.min(...o.map(e=>e.startMs)),l=Math.max(...o.map(e=>e.startMs+Math.max(0,e.durationMs)));return{text:a,startMs:c,durationMs:Math.max(0,l-c),speakerId:s,tokens:o}},D_=(e,t)=>{let{streamText:n,spans:r}=C_(e);if(!n||!r.length)return[];let i=h_(n,t).map(e=>E_(n,r,e)).filter(e=>e!==null);return i.length?i:r.map(({line:e})=>e)},O_=e=>typeof e==`number`&&Number.isFinite(e)?e:0,k_=e=>Math.max(0,O_(e)),A_=(e,t,n)=>{let r=e.subtitles;if(!Array.isArray(r)||r.length===0)return null;let i=t??n;if(i){let e=r.find(e=>e.language===i&&typeof e.translatedFromLanguage==`string`);if(e)return e;let t=r.find(e=>e.language===i);if(t)return t}return r[0]??null},j_=e=>`host`in e&&`videoId`in e&&`detectedLanguage`in e&&`duration`in e&&typeof e.host==`string`&&typeof e.videoId==`string`&&typeof e.detectedLanguage==`string`&&typeof e.duration==`number`,M_=e=>{let t=F.getPoToken();if(!t)return e;let n=t;for(let e=0;e<10;e+=1){let e;try{e=decodeURIComponent(n)}catch{break}if(e===n)break;n=e}let r=F.getDeviceParams(),i=typeof r==`string`?r.replace(/^[?&]+/u,``):``;try{let t=new URL(e);if(t.searchParams.set(`potc`,`1`),t.searchParams.set(`pot`,n),i){let e=new URLSearchParams(i);for(let[n,r]of e.entries())t.searchParams.set(n,r)}return t.toString()}catch{let t=e.includes(`?`)?`&`:`?`,r=i?`&${i}`:``;return`${e}${t}potc=1&pot=${encodeURIComponent(n)}${r}`}},N_=(e,t)=>e-t,P_=(e,t)=>et?1:0,F_=(e,t)=>{let n=Math.min(e.length,t.length);for(let r=0;re?t===0?n?1:0:n?0:1:0,L_=(e,t,n,r)=>!e||!t||n===r?0:1,R_=(e,t)=>{let n=e.source===`yandex`,r=n?0:1,i=e.language===Mi?0:1,a=!!e.translatedFromLanguage,o=t&&e.language===t?0:1;return[r,i,I_(n,o,a),L_(n,a,e.translatedFromLanguage,t),n&&!a?o:0,n?0:Number(!!e.isAutoGenerated)]},z_=(e,t,n)=>({descriptor:e,index:t,rank:R_(e,n),language:e.language,translatedFromLanguage:e.translatedFromLanguage??``,source:e.source,url:e.url,isAutoGenerated:Number(!!e.isAutoGenerated)}),B_=(e,t)=>{let n=e.map((e,n)=>z_(e,n,t));return n.sort((e,t)=>{let n=F_(e.rank,t.rank);if(n!==0)return n;let r=P_(e.language,t.language)||P_(e.translatedFromLanguage,t.translatedFromLanguage)||P_(e.source,t.source)||P_(e.url,t.url)||N_(e.isAutoGenerated,t.isAutoGenerated);return r===0?N_(e.index,t.index):r}),n.map(e=>e.descriptor)},V_=(e,t)=>typeof e==`boolean`?e:!!t.trim(),H_=e=>{if(!e||typeof e!=`object`)return null;let t=e,n=k_(t.start),r=k_(t.end);return r<=n?null:{start:n,end:r,style:Iu(t.style)}},U_=e=>{if(!e||typeof e!=`object`)return;let t=e,n={};typeof t.rawText==`string`&&(n.rawText=t.rawText);let r=Array.isArray(t.styledSpans)?t.styledSpans.map(H_).filter(e=>e!==null):[];return r.length&&(n.styledSpans=r),t.vtt&&typeof t.vtt==`object`&&(n.vtt=t.vtt),t.ass&&typeof t.ass==`object`&&(n.ass=t.ass),Object.keys(n).length?n:void 0},W_=e=>{if(!e||typeof e!=`object`)return{text:``,startMs:0,durationMs:0,isWordLike:!1};let t=e,n=typeof t.text==`string`?t.text:``;return{text:n,startMs:k_(t.startMs),durationMs:k_(t.durationMs),isWordLike:V_(t.isWordLike,n),style:Iu(t.style)}},G_=e=>{if(!e||typeof e!=`object`)return{text:``,startMs:0,durationMs:0,speakerId:`0`,tokens:[]};let t=e,n=Array.isArray(t.tokens)?t.tokens.map(W_):[];return{text:typeof t.text==`string`?t.text:``,startMs:k_(t.startMs),durationMs:k_(t.durationMs),speakerId:typeof t.speakerId==`string`?t.speakerId:`0`,tokens:n,metadata:U_(t.metadata)}},K_=e=>{if(!e||typeof e!=`object`)return{format:`json`,subtitles:[]};let t=e,n=Array.isArray(t.subtitles)?t.subtitles.map(G_):[];return{format:t.format??`json`,subtitles:n}},q_=(e,t)=>!t||e.tStartMs+e.dDurationMs<=t.tStartMs?Math.max(0,e.dDurationMs):Math.max(0,t.tStartMs-e.tStartMs),J_=(e,t,n)=>{let r=[],i=``,a=n,o=``;for(let s=0;se.durationMs>0,X_=e=>e.text?Tf(e.text):e.tokens.length?Tf(e.tokens.map(e=>e.text).join(``)):``,Z_=(e,t,n)=>{if(!e.length)return[];let r=Math.max(0,n),i=e.map(e=>Math.max(e.length,1)),a=i.reduce((e,t)=>e+t,0),o=Array(i.length+1).fill(0);for(let e=0;e{let t=[],n=0;for(let r=0;rTf(e.map(e=>e.text).join(``)),ev=e=>{let t=[];for(let n of e){if(!n.text.includes(` +`)){t.push(n);continue}let e=Q_(n.text),r=Z_(e.map(e=>e.text===` +`?``:e.text),n.startMs,n.durationMs);for(let i=0;i!n||!e.tokens.length||t.source===`youtube`||e.metadata?.styledSpans?.length&&!e.tokens.some(e=>e.style)?!1:$_(e.tokens)===n,nv=(e,t)=>{let n=[];for(let r of e){let e=Tf(r.text);if(!e||!Y_(r))continue;let i=m_(e,t).filter(e=>e.isWordLike&&e.text.trim());if(!i.length)continue;let a=Z_(i.map(e=>e.text),r.startMs,r.durationMs);n.push(...a)}return n},rv=(e,t,n,r)=>({text:e.text,startMs:t,durationMs:n,isWordLike:e.isWordLike,style:pf(r,e.index,e.index+e.text.length)}),iv=(e,t,n,r)=>{let i=Q_(e.text);if(i.length===1&&i[0].text===e.text)return[rv(e,t,n,r)];let a=Z_(i.map(e=>e.text===` +`?``:e.text),t,n);return i.map((n,i)=>{let o=n.text===` +`;return{text:n.text,startMs:a[i]?.startMs??t,durationMs:o?0:a[i]?.durationMs??0,isWordLike:!o&&e.isWordLike,style:o?void 0:pf(r,e.index+n.startOffset,e.index+n.endOffset)}})},av=e=>e.reduce((e,t,n)=>(t.isWordLike&&t.text.trim()&&e.push(n),e),[]),ov=(e,t)=>{if(!t.length)return e;let n=av(e);if(!n.length)return e;let r=n.length;for(let i=0;i{if(!n)return[];if(tv(e,t,n))return ev(e.tokens);let r=t.language,i=e.metadata?.styledSpans??ff(e.metadata?.rawText??e.text??n).styledSpans,a=m_(n,r);if(!a.length)return[];let o=Z_(a.map(e=>e.text),e.startMs,e.durationMs),s=[];for(let t=0;t{let n=await z(e,{timeout:7e3});return t===`vtt`||t===`srt`||t===`ass`?lp(await n.text(),t):n.json()},lv=(e,t)=>t.source===`youtube`?fv.formatYoutubeSubtitles(e,!!t.isAutoGenerated):(t.format===`srt`||t.format===`vtt`||t.format,up(K_(e))),uv=(e,t)=>{let n=fv.autoMerge(e,t);return{...n,subtitles:fv.processTokens(n,t)}},dv=e=>{let t=[],n=new Set;for(let r of e.subtitles??[])r.language&&!n.has(r.language)&&(n.add(r.language),t.push({source:`yandex`,format:`json`,language:r.language,url:r.url})),r.translatedLanguage&&t.push({source:`yandex`,format:`json`,language:r.translatedLanguage,translatedFromLanguage:r.language,url:r.translatedUrl??r.url});return t},fv={processTokens(e,t){let n=[];for(let r of e.subtitles){let e=X_(r),i=sv(r,t,e);n.push({...r,text:e,tokens:i})}return n},formatYoutubeSubtitles(e,t=!1){let n=e.events??[];if(!n.length)return console.error(`[VOT] Invalid YouTube subtitles format:`,e),{format:`json`,subtitles:[]};let r=[];for(let e=0;ee.tokens.length>0)?e:{...e,subtitles:D_(e.subtitles,t.language)}},async fetchSubtitles(e,t,n){let r=fu(e);if(!r&&j_(e)&&(r=A_(e,t,n)),!r)return{format:`json`,subtitles:[]};let{source:i,format:a}=r,{url:o}=r;i===`youtube`&&(o=M_(o));try{let e=uv(lv(await cv(o,a),r),r);return L.log(`[VOT] Processed subtitles:`,e),e}catch(e){return console.error(`[VOT] Failed to process subtitles:`,e),{format:`json`,subtitles:[]}}},async getSubtitles(e,t){let{host:n,url:r,detectedLanguage:i,videoId:a,duration:o,subtitles:s=[]}=t;try{let t={videoData:{host:n,url:r,videoId:a,duration:o},requestLang:i},c=await Promise.race([e.getSubtitles(t),new Promise((e,t)=>{setTimeout(()=>t(Error(`Timeout`)),5e3)})]);return L.log(`[VOT] Subtitles response:`,c),c.waiting&&console.error(`[VOT] Failed to get Yandex subtitles`),B_([...dv(c),...s],i)}catch(e){let t=`Error in getSubtitles function`;throw e instanceof Error&&e.message===`Timeout`&&(t=`Failed to get Yandex subtitles: timeout`),console.error(`[VOT] ${t}`,e),e}}},pv=new WeakMap;function mv(e){let t=e.videoData;return e.getPreferredSubtitlesLanguage(t?.detectedLanguage,t?.responseLanguage)??t?.responseLanguage??e.translateToLang}function hv(e){let t=e.videoData,n=t?.detectedLanguage?.toLowerCase();return n&&n!==`auto`?n:t?.responseLanguage?.toLowerCase()??e.translateToLang}function gv(e){let t=e.videoData;if(!t?.videoId)return null;let n=hv(e);if(!n)return null;let r=mv(e);return r?e.getSubtitlesCacheKey(t.videoId,n,r):null}function _v(e){return[e.source,e.format,e.language,e.translatedFromLanguage??``,e.isAutoGenerated?`1`:`0`,e.url].join(`|`)}function vv(e){let t=new Set,n=[];for(let r of e){let e=_v(r);t.has(e)||(t.add(e),n.push(r))}return n}function yv(e,t){let n=e.videoData;if(!n)throw Error(`Video data is required to load subtitles`);if(e.site.host!==`youtube`||!t)return n;let r=F.getSubtitles(t);return r.length?{...n,subtitles:vv([...Array.isArray(n.subtitles)?n.subtitles:[],...r])}:n}function bv(e){let t=(pv.get(e)??0)+1;return pv.set(e,t),t}function xv(e,t){return pv.get(e)===t}function Sv(e,t){return e.hasSubtitlesWidget()&&e.subtitlesWidget?.setContent(null),t.downloadSubtitlesButton.hidden=!0,e.yandexSubtitles=null,e}async function Cv(e){L.log(`[onchange] subtitles`,e);let t=bv(this),n=this.uiManager.votOverlayView;if(!n?.subtitlesSelect||!n.downloadSubtitlesButton)return this;if(n.subtitlesSelect.setSelectedValue(e),e===`disabled`)return Sv(this,n);let r=$h(e);if(r==null)return Sv(this,n);let i=eg(this.subtitles,r);if(!i)return Sv(this,n);let a={...i},o=qh(a.url,{translateProxyEnabled:this.data?.translateProxyEnabled,proxyWorkerHost:this.data?.proxyWorkerHost});o!==a.url&&(a={...a,url:o},console.log(`[VOT] Subs proxied via ${a.url}`));let s=await fv.fetchSubtitles(a);return xv(this,t)?(this.yandexSubtitles=s,this.getSubtitlesWidget().setContent(this.yandexSubtitles,a.language),n.downloadSubtitlesButton.hidden=!1,this):this}async function wv(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return;let t=rg(Qh(this.subtitles));e.subtitlesSelect.updateItems(t),await this.changeSubtitlesLang(Jh)}async function Tv(){let e=gv(this);if(!e)return(this.subtitlesCacheKey!==null||this.subtitles.length>0)&&(this.subtitles=[],this.subtitlesCacheKey=null,await this.updateSubtitlesLangSelect()),this;if(this.subtitlesCacheKey===e){let t=this.cacheManager.getSubtitles(e)!==void 0;if(this.subtitles.length>0||t)return this}let t=this.cacheManager.getSubtitles(e);return t===void 0?(await this.loadSubtitles(),this):(this.subtitles=Array.isArray(t)?t:[],this.subtitlesCacheKey=e,await this.updateSubtitlesLangSelect(),this)}async function Ev(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return this;try{await Tv.call(this)}catch{return this}let t=this.videoData?.detectedLanguage??this.translateFromLang,n=mv(this);if(!n)return this;let r=lg(Qh(this.subtitles),t,n);return r==null||ig(e.subtitlesSelect.selectedValues)===String(r)||await this.changeSubtitlesLang(String(r)),this}async function Dv(){return!this.data?.autoSubtitles||!this.videoData?.videoId||await this.enableSubtitlesForCurrentLangPair(),this}async function Ov(){let e=this.uiManager.votOverlayView;if(!e?.subtitlesSelect)return this;let t=ig(e.subtitlesSelect.selectedValues);return t&&t!==`disabled`?(await this.changeSubtitlesLang(Jh),this):(await this.enableSubtitlesForCurrentLangPair(),this)}async function kv(){if(!this.videoData?.videoId){console.error(`[VOT] ${V.getDefault(`VOTNoVideoIDFound`)}`),this.subtitles=[],this.subtitlesCacheKey=null;return}let e=mv(this);if(!e){this.subtitles=[],this.subtitlesCacheKey=null,await this.updateSubtitlesLangSelect();return}let t=this.getSubtitlesCacheKey(this.videoData.videoId,this.videoData.detectedLanguage,e);try{let n=this.cacheManager.getSubtitles(t);if(!n){let r=this.subtitlesLoadPromises.get(t);if(r===void 0){let n=yv(this,e);r=fv.getSubtitles(this.votClient,n),this.subtitlesLoadPromises.set(t,r)}try{n=await r,n=Array.isArray(n)?n:[],this.cacheManager.setSubtitles(t,n)}finally{this.subtitlesLoadPromises.get(t)===r&&this.subtitlesLoadPromises.delete(t)}}this.subtitles=Array.isArray(n)?n:[],this.subtitlesCacheKey=t}catch(e){console.error(`[VOT] Failed to load subtitles:`,e),this.subtitles=[],this.subtitlesCacheKey=null}await this.updateSubtitlesLangSelect()}new Set(bn);var Av=Promise.resolve(),jv=class{video;container;site;translateFromLang=`auto`;translateToLang=Ni;data;videoData;firstPlay=!0;audioContext;votClient;audioPlayer;abortController;actionsAbortController;actionsGeneration=0;notifier=new Vm;cacheManager;votSessionStorage=new da;subtitlesLoadPromises=new Map;downloadTranslationUrl=null;isRefreshingTranslation=!1;autoRetry;votOpts;volumeOnStart;volumeLinkState={initialized:!1,lastVideoPercent:0,lastTranslationPercent:0};internalVideoVolumeSetAt=0;internalVideoVolumeSetPercent=null;internalVideoVolumeSuppressionMs=250;internalVideoVolumeSetHistory=[];internalVideoVolumeSetHistoryLimit=48;smartVolumeDuckingInterval;smartVolumeDuckingTarget=.2;smartVolumeDuckingBaseline;smartVolumeLastApplied;smartVolumeLastTickAt=0;smartVolumeLastSoundAt=0;smartVolumeRmsMissingSinceAt=null;smartVolumeRmsEnvelope=0;smartVolumeSpeechGateOpen=!1;smartVolumeIsDucked=!1;longWaitingResCount=0;hadAsyncWait=!1;subtitles=[];subtitlesCacheKey=null;subtitlesWidget;activeTranslation=null;stopTranslatePromise=null;interactionChecker;uiManager;overlayVisibility;overlayVisibilityTargetsAbortController;translationOrchestrator;lifecycleController;translationHandler;videoManager;yandexSubtitles=null;resizeObserver;syncVolumeObserver;initialized=!1;mountCache;errorTranslationCache=new Map;getFullscreenOverlayRoot(){let e=document,t=e.fullscreenElement??e.webkitFullscreenElement;return t instanceof HTMLElement&&(t===this.container||t.contains(this.container)||this.container.contains(t))?t:null}getOverlayMountPoints(e=this.container){let t=this.getFullscreenOverlayRoot(),{base:n,root:r,portalContainer:i,subtitlesMountContainer:a}=Uo({container:e,site:this.site,fullscreenRoot:t}),o=this.mountCache;return o?.container===e&&o.base===n&&o.subtitlesMountContainer===a&&o.fullscreenRoot===t&&(o.root.isConnected??document.documentElement.contains(o.root))?{root:o.root,portalContainer:o.portalContainer,subtitlesMountContainer:o.subtitlesMountContainer,fullscreenRoot:o.fullscreenRoot}:(this.mountCache={container:e,base:n,root:r,portalContainer:i,subtitlesMountContainer:a,fullscreenRoot:t},{root:r,portalContainer:i,subtitlesMountContainer:a,fullscreenRoot:t})}getOverlayMount(e=this.container){let{root:t,portalContainer:n,subtitlesMountContainer:r}=this.getOverlayMountPoints(e);return{root:t,portalContainer:n,subtitlesMountContainer:r}}getTranslationCacheKey(e,t,n,r){let i=this.getRequestLangForTranslation(t,n),a=this.isLivelyVoiceAllowed(i,n)&&this.data?.useLivelyVoice,o=r==null?``:Hi(r);return`${e}_${i}_${n}_${a}_${o?Ui(o):`0`}`}getSubtitlesCacheKey(e,t,n){return`${e}_${t}_${n}_${!!this.data?.useLivelyVoice}`}getPreferredSubtitlesLanguage(e=this.videoData?.detectedLanguage??`auto`,t=this.videoData?.responseLanguage??this.translateToLang,n=this.data?.responseLanguageSubtitles){return cg(n,e,t)??t??e}isActionStale(e){return e?this.actionsGeneration!==e.gen||this.videoData?.videoId!==e.videoId:!1}updateVOTClientRequestSignal(){this.votClient&&(this.votClient.fetchOpts={...this.votClient.fetchOpts,signal:this.actionsAbortController.signal})}resetActionsAbortController(e){try{this.actionsAbortController?.abort(e)}catch{}this.actionsAbortController=new AbortController,this.actionsGeneration++,this.updateVOTClientRequestSignal()}constructor(e,t,n){L.log(`[VideoHandler] add video:`,e,`container:`,t,this),this.video=e,this.container=t,this.site=n,this.abortController=new AbortController,this.actionsAbortController=new AbortController,this.cacheManager=new fa,this.interactionChecker=Am(),this.interactionChecker.start(),this.uiManager=new Sm({mount:this.getOverlayMount(t),data:this.data,videoHandler:this,intervalIdleChecker:this.interactionChecker}),this.overlayVisibility=new Cm({checker:this.interactionChecker,getOverlayView:()=>this.uiManager.votOverlayView??null,getAutoHideDelay:()=>this.getAutoHideDelay(),isInteractiveNode:e=>this.isOverlayInteractiveNode(e)}),this.translationOrchestrator=new Js({isFirstPlay:()=>this.firstPlay,setFirstPlay:e=>{this.firstPlay=e},isAutoTranslateEnabled:()=>!!this.data?.autoTranslate,getVideoId:()=>this.videoData?.videoId,scheduleAutoTranslate:()=>this.runAutoTranslate(),isMobileYouTubeMuted:()=>this.site.host===`youtube`&&this.site.additionalData===`mobile`&&this.video.muted,setMuteWatcher:e=>{let t=!1,n=()=>{t||(t=!0,this.video.removeEventListener(`volumechange`,r),e())},r=()=>{this.video.muted||n()};this.video.addEventListener(`volumechange`,r,{signal:this.abortController.signal}),queueMicrotask(()=>{this.video.muted||n()})}}),this.lifecycleController=new Qs($s(this,e=>this.getOverlayMount(e))),this.translationHandler=new qs(this),this.videoManager=new tl(this)}getSubtitlesWidget(){if(!this.subtitlesWidget){let{subtitlesMountContainer:e}=this.getOverlayMountPoints();this.subtitlesWidget=new Ld(this.video,this.uiManager.votOverlayView?.root??e,this.interactionChecker),this.applySavedSubtitlesWidgetSettings(this.subtitlesWidget)}return this.subtitlesWidget}applySavedSubtitlesWidgetSettings(e){this.data&&(e.setSmartLayout(typeof this.data.subtitlesSmartLayout==`boolean`?this.data.subtitlesSmartLayout:!0),typeof this.data.subtitlesMaxLength==`number`&&e.setMaxLength(this.data.subtitlesMaxLength),typeof this.data.highlightWords==`boolean`&&e.setHighlightWords(this.data.highlightWords),typeof this.data.subtitlesFontSize==`number`&&e.setFontSize(this.data.subtitlesFontSize),typeof this.data.subtitlesFontFamily==`string`&&e.setFontFamily(this.data.subtitlesFontFamily),typeof this.data.subtitlesOpacity==`number`&&e.setOpacity(this.data.subtitlesOpacity))}hasSubtitlesWidget(){return!!this.subtitlesWidget}resetSubtitlesWidget(){this.hasSubtitlesWidget()&&(this.subtitlesWidget?.release(),this.subtitlesWidget=void 0)}get uiRoot(){return this.getOverlayMountPoints().root}get portalContainer(){return this.getOverlayMountPoints().portalContainer}getEventContainer(){return this.site.eventSelector?document.querySelector(this.site.eventSelector)??this.container:this.container}async runAutoTranslate(){await this.videoManager.videoValidator(),await this.uiManager.handleTranslationBtnClick()}getAudioContext(){if(this.audioContext)return this.audioContext;if(this.isAudioContextSupported)try{return this.audioContext=$r(),this.audioContext}catch(e){console.warn(`[VOT] Failed to init AudioContext, falling back:`,e);return}}get isAudioContextSupported(){return globalThis.AudioContext!==void 0||globalThis.webkitAudioContext!==void 0}getPreferAudio(){return!this.getAudioContext()||!this.data||!this.data.newAudioPlayer||this.videoData?.isStream?!0:this.data.newAudioPlayer&&!this.data.onlyBypassMediaCSP?!1:!this.site.needBypassCSP}createPlayer(){let e=this.getPreferAudio();return L.log(`preferAudio:`,e),this.audioPlayer=new ri({video:this.video,debug:!1,fetchFn:z,fetchOpts:{timeout:0},preferAudio:e}),this}isLikelyInternalVideoVolumeChange(e){let t=Date.now(),n=this.internalVideoVolumeSetHistory;if(n.length>0){let r=0,i=!1;for(let a of n)t-a.at>a.suppressMs||(n[r++]=a,!i&&Math.abs(e-a.percent)<=1&&(i=!0));return n.length=r,i}return this.internalVideoVolumeSetPercent===null||t-this.internalVideoVolumeSetAt>this.internalVideoVolumeSuppressionMs?!1:Math.abs(e-this.internalVideoVolumeSetPercent)<=1}callModule(e,...t){return e.call(this,...t)}callModuleAsync(e,...t){return e.call(this,...t)}init(){return s_.call(this)}async initVOTClient(){let e=Vh(this.data??{}),t=this.data?.translateProxyEnabled===1?fi:e?Bh(this.data?.proxyWorkerHost):ui;this.votOpts={fetchFn:z,fetchOpts:{signal:this.actionsAbortController.signal,forceGmXhr:Uh({...this.data,gmXhrSupported:La})},apiToken:this.data?.account?.token,hostVOT:mi,host:t},this.votClient=new(e?Qt:Zt)(this.votOpts),this.votClient.sessions=await this.votSessionStorage.restore(t,this.votClient.sessions);let n=this.votClient.getSession.bind(this.votClient);return this.votClient.getSession=async e=>{let r=await n(e);return await this.votSessionStorage.persist(t,this.votClient.sessions),r},this}transformBtn(e,t){return this.uiManager.transformBtn(e,t),this}hasActiveSource(){return!!this.audioPlayer?.player?.src}initExtraEvents(){return this.callModule(Qg)}refreshOverlayMount(){this.mountCache=void 0;let e=this.getOverlayMount(this.container),t=!xp(this.uiManager.mount,e);this.uiManager.updateMount(e),t&&this.rebindOverlayVisibilityTargets()}rebindOverlayVisibilityTargets=$g;setCanPlay(){return this.lifecycleController.setCanPlay()}isOverlayInteractiveNode(e){return this.callModule(e_,e)}getAutoHideDelay(){return this.callModule(t_)}changeSubtitlesLang=Cv;updateSubtitlesLangSelect=wv;ensureSubtitlesForCurrentLangPair=Tv;loadSubtitles=kv;enableSubtitlesForCurrentLangPair(){return this.callModuleAsync(Ev)}refreshAutoSubtitlesForCurrentLangPair(){return this.callModuleAsync(Dv)}toggleSubtitlesForCurrentLangPair(){return this.callModuleAsync(Ov)}getRequestLangForTranslation(e,t){return this.data?.useLivelyVoice&&this.data?.account?.token&&t===`ru`?`en`:e}isLivelyVoiceAllowed(e=this.videoData?.detectedLanguage??`auto`,t=this.videoData?.responseLanguage??this.translateToLang){return!(this.getRequestLangForTranslation(e,t)!==`en`||t!==`ru`||!this.data?.account?.token)}getVideoVolume(){return this.videoManager.getVideoVolume()}setVideoVolume(e,t={}){let n=Ac(e),r=typeof t.suppressSyncMs==`number`&&Number.isFinite(t.suppressSyncMs)?Math.max(0,t.suppressSyncMs):this.internalVideoVolumeSuppressionMs,i=Date.now(),a=Dc(n);return this.internalVideoVolumeSetAt=i,this.internalVideoVolumeSetPercent=a,this.internalVideoVolumeSetHistory.push({at:i,percent:a,suppressMs:r}),this.internalVideoVolumeSetHistory.length>this.internalVideoVolumeSetHistoryLimit&&this.internalVideoVolumeSetHistory.splice(0,this.internalVideoVolumeSetHistory.length-this.internalVideoVolumeSetHistoryLimit),this.videoManager.setVideoVolume(n),this}onVideoVolumeSliderSynced(e){let t=W(e);if(!this.volumeLinkState.initialized){Ym(this.volumeLinkState,t);return}this.data?.syncVolume&&this.hasActiveSource()&&!this.isLikelyInternalVideoVolumeChange(t)||Ym(this.volumeLinkState,t)}onTranslationVolumeSliderSynced(e){if(!this.volumeLinkState.initialized){Xm(this.volumeLinkState,e);return}Xm(this.volumeLinkState,e)}resetVolumeLinkState(e,t){Ym(this.volumeLinkState,e),Xm(this.volumeLinkState,t),this.volumeLinkState.initialized=!0}clearVolumeLinkState(){this.volumeLinkState.initialized=!1,this.volumeLinkState.lastVideoPercent=0,this.volumeLinkState.lastTranslationPercent=0}isMuted(){return this.videoManager.isMuted()}syncVideoVolumeSlider(){this.videoManager.syncVideoVolumeSlider()}setSelectMenuValues(e,t){this.videoManager.setSelectMenuValues(e,t)}syncVolumeWrapper(e,t){let n=this.uiManager.votOverlayView;if(!n?.isInitialized())return;let r=n.videoVolumeSlider,i=n.translationVolumeSlider;if(!r||!i)return;let{nextVideo:a,nextTranslation:o}=Qm({state:this.volumeLinkState,fromType:e,newVolume:t,currentVideo:Number(r.value),currentTranslation:Number(i.value),translationMin:i.min,translationMax:i.max});if(typeof o==`number`){i.value=o,this.audioPlayer?.player&&(this.audioPlayer.player.volume=o/100);return}typeof a==`number`&&(r.value=a,this.setVideoVolume(a/100))}getVideoData(){return this.videoManager.getVideoData()}videoValidator(){return this.videoManager.videoValidator()}stopTranslate(){if(this.stopTranslatePromise!==null)return this.stopTranslatePromise;let e=(async()=>{if(this.audioPlayer?.player){try{this.audioPlayer.player.removeVideoEvents(),this.audioPlayer.player.src=``,await this.audioPlayer.player.clear()}catch(e){L.log(`[stopTranslate] audioPlayer cleanup error`,e)}L.log(`audioPlayer after stopTranslate`,this.audioPlayer)}this.activeTranslation=null;let e=this.uiManager.votOverlayView;e&&(e.videoVolumeSlider&&(e.videoVolumeSlider.hidden=!0),e.translationVolumeSlider&&(e.translationVolumeSlider.hidden=!0),e.downloadTranslationButton&&(e.downloadTranslationButton.hidden=!0)),this.downloadTranslationUrl=null,this.longWaitingResCount=0,this.hadAsyncWait=!1,this.transformBtn(`none`,V.get(`translateVideo`)),L.log(`Volume on start: ${this.volumeOnStart}`);let t=typeof this.smartVolumeDuckingBaseline==`number`?this.smartVolumeDuckingBaseline:this.volumeOnStart;kh(this,{restoreVolume:t}),this.volumeOnStart=void 0,this.autoRetry!==void 0&&(clearTimeout(this.autoRetry),this.autoRetry=void 0),this.resetActionsAbortController(`stopTranslate`)})().finally(()=>{this.stopTranslatePromise===e&&(this.stopTranslatePromise=null)});return this.stopTranslatePromise=e,e}waitForPendingStopTranslate(){return this.stopTranslatePromise??Av}async updateTranslationErrorMsg(e,t){if(t?.aborted)return;let n=V.get(`translationTake`),r=V.lang;this.longWaitingResCount=e===V.get(`translationTakeAboutMinute`)?this.longWaitingResCount+1:0,L.log(`longWaitingResCount`,this.longWaitingResCount),this.longWaitingResCount>5&&(e=new U(`TranslationDelayed`)),L.log(`updateTranslationErrorMsg message`,e);let i=await this.resolveTranslationErrorDisplayMessage(e,n,r,t);t?.aborted||i===null||(this.transformBtn(`error`,i),!t?.aborted&&[`Подготавливаем перевод`,`Видео передано в обработку`,`Ожидаем перевод видео`,`Загружаем переведенное аудио`].includes(e)&&this.uiManager.votOverlayView?.votButton&&(this.uiManager.votOverlayView.votButton.loading=!0))}async resolveTranslationErrorDisplayMessage(e,t,n,r){return e?.name===`VOTLocalizedError`?e.localizedMessage:e instanceof Error?e.message:this.shouldTranslateErrorMessage(e,t,n)?await this.getTranslatedErrorMessage(e,n,r):this.stringifyTranslationError(e)}shouldTranslateErrorMessage(e,t,n){return!!this.data?.translateAPIErrors&&n!==`ru`&&!e?.includes(t)}stringifyTranslationError(e){return Array.isArray(e)?e.join(` +`):String(e??``)}async getTranslatedErrorMessage(e,t,n){let r=this.uiManager.votOverlayView;if(!r?.votButton)return null;let i=Array.isArray(e)?e.join(` `):String(e),a=`${t}:${i}`,o=this.errorTranslationCache.get(a);if(o)return o;r.votButton.loading=!0;let s=await vc(i,`ru`,t);if(n?.aborted)return null;let c=Array.isArray(s)?s.join(` +`):String(s);return this.errorTranslationCache.set(a,c),this.trimErrorTranslationCache(),c}trimErrorTranslationCache(){if(this.errorTranslationCache.size<=50)return;let e=this.errorTranslationCache.keys().next().value;e&&this.errorTranslationCache.delete(e)}afterUpdateTranslation(e){let t=this.uiManager.votOverlayView;if(!t?.votButton)return;let n=t.votButton.container.dataset.status===`success`;t.videoVolumeSlider&&(t.videoVolumeSlider.hidden=!this.data?.showVideoSlider||!n),t.translationVolumeSlider&&(t.translationVolumeSlider.hidden=!n),t.videoVolumeSlider&&t.translationVolumeSlider?(this.volumeLinkState.lastVideoPercent=Number(t.videoVolumeSlider.value),this.volumeLinkState.lastTranslationPercent=Number(t.translationVolumeSlider.value),this.volumeLinkState.initialized=!0):this.volumeLinkState.initialized=!1,this.videoData&&!this.videoData.isStream&&(t.downloadTranslationButton&&(t.downloadTranslationButton.hidden=!1),this.downloadTranslationUrl=e),L.log(`afterUpdateTranslation downloadTranslationUrl`,this.downloadTranslationUrl),this.data?.sendNotifyOnComplete&&this.hadAsyncWait&&n&&(this.notifier.translationCompleted(globalThis.location.hostname),this.hadAsyncWait=!1)}validateAudioUrl(e,t){return this.callModuleAsync(yg,e,t)}scheduleTranslationRefresh(){this.callModule(bg)}refreshTranslationAudio=Cg;proxifyAudio(e){return this.callModule(wg,e)}unproxifyAudio(e){return this.callModule(Tg,e)}handleProxySettingsChanged=Eg;isMultiMethodS3(e){return this.callModule(Dg,e)}updateTranslation=Ag;translateFunc(e,t,n,r,i){return Pg.call(this,e,t,n,r,i)}isYouTubeHosts(){return this.callModule(Fg)}setupAudioSettings(){return this.callModule(Ph)}applyManualVideoVolumeOverride(e){return this.callModule(Fh,e)}stopTranslation=async()=>{this.translationOrchestrator?.reset(),this.overlayVisibility?.cancel(),await this.stopTranslate(),this.syncVideoVolumeSlider()};handleSrcChanged(){return this.lifecycleController.handleSrcChanged()}async release(){L.log(`[VideoHandler] release`),this.initialized=!1;try{await this.stopTranslation()}catch(e){L.log(`[VideoHandler] stopTranslation failed during release`,e)}this.lifecycleController?.teardown(),this.abortController?.abort(),this.abortController=new AbortController,this.overlayVisibility?.release(),this.releaseExtraEvents(),this.hasSubtitlesWidget()&&(this.subtitlesWidget?.release(),this.subtitlesWidget=void 0),this.interactionChecker?.destroy(),this.uiManager.release()}collectReportInfo(){let e=am(),t=this.videoData?.detectedLanguage??`unknown`,n=this.videoData?.responseLanguage??`unknown`,r=`
+>>>>>>> Stashed changes Autogenerated by VOT:
  • OS: ${e.os}
  • @@ -385,4 +494,8 @@ var vot=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}
  • Player: ${this.data?.newAudioPlayer?`New`:`Old`} (CSP only: ${this.data?.onlyBypassMediaCSP??!1})
  • Proxying mode: ${this.data?.translateProxyEnabled??0}
-
`;return{assignees:`ilyhalight`,template:`1-bug-report-${V.lang===`ru`?`ru`:`en`}.yml`,os:e.os,"script-version":e.scriptVersion,"additional-info":r}}releaseExtraEvents=Qg},Dv=new Wm(Em()),Ov=new WeakMap,kv=null,Av=si();function jv(){return{frame:Co()?`iframe`:`top`,host:globalThis.location.hostname||`unknown`,path:globalThis.location.pathname||`/`}}function Mv(e,t){let n=jv(),r={host:n.host,path:n.path};t&&Object.assign(r,t),console.log(`[VOT][bootstrap][${n.frame}] ${e}`,r)}function Nv(){return kv||=qr(),kv}function Pv(e,t){if(L.log(`findContainer`,e,t),!e.selector)return L.log(`findContainer without selector, using parentElement`),t.parentElement;let n=zo(t,e.selector);return e.shadowRoot?L.log(`findContainer with site.shadowRoot`,n):L.log(`findContainer without shadowRoot`,n),n}async function Fv(){let e=Ao({isIframe:Co(),href:String(globalThis.location.href||``),origin:globalThis.location.origin,authOrigin:_i});if(e===`skip`){Mv(`Skipping bootstrap for non-runnable iframe`);return}li(),Mv(`Loading extension`,{mode:e}),e===`auth-eager`?await Eo(`auth-page`,Mv):Mv(`Lazy bootstrap enabled; waiting for video detection`),Oo({videoObserver:Dv,videosWrappers:Ov,ensureRuntimeActivated:e=>Eo(e,Mv),getServicesCached:Nv,findContainer:Pv,createVideoHandler:(e,t,n)=>new Ev(e,t,n)}),Dv.enable()}function Iv(){return Av.status===`booting`||Av.status===`booted`?(Mv(`bootstrap already initialized, skipping duplicate run`,{status:Av.status}),Av.promise??Promise.resolve()):(Av.status=`booting`,Av.promise=(async()=>{try{await Fv(),Av.status=`booted`}catch(e){Av.status=`failed`,Av.error=e,console.error(`[VOT]`,e)}})(),Av.promise)}return Iv(),e.VideoHandler=Ev,e.bootstrapContentScript=Iv,Object.defineProperty(e,`countryCode`,{enumerable:!0,get:function(){return $g}}),e.getEnvironmentInfo=tm,e})({}); \ No newline at end of file +<<<<<<< Updated upstream +
`;return{assignees:`ilyhalight`,template:`1-bug-report-${V.lang===`ru`?`ru`:`en`}.yml`,os:e.os,"script-version":e.scriptVersion,"additional-info":r}}releaseExtraEvents=Qg},Dv=new Wm(Em()),Ov=new WeakMap,kv=null,Av=si();function jv(){return{frame:Co()?`iframe`:`top`,host:globalThis.location.hostname||`unknown`,path:globalThis.location.pathname||`/`}}function Mv(e,t){let n=jv(),r={host:n.host,path:n.path};t&&Object.assign(r,t),console.log(`[VOT][bootstrap][${n.frame}] ${e}`,r)}function Nv(){return kv||=qr(),kv}function Pv(e,t){if(L.log(`findContainer`,e,t),!e.selector)return L.log(`findContainer without selector, using parentElement`),t.parentElement;let n=zo(t,e.selector);return e.shadowRoot?L.log(`findContainer with site.shadowRoot`,n):L.log(`findContainer without shadowRoot`,n),n}async function Fv(){let e=Ao({isIframe:Co(),href:String(globalThis.location.href||``),origin:globalThis.location.origin,authOrigin:_i});if(e===`skip`){Mv(`Skipping bootstrap for non-runnable iframe`);return}li(),Mv(`Loading extension`,{mode:e}),e===`auth-eager`?await Eo(`auth-page`,Mv):Mv(`Lazy bootstrap enabled; waiting for video detection`),Oo({videoObserver:Dv,videosWrappers:Ov,ensureRuntimeActivated:e=>Eo(e,Mv),getServicesCached:Nv,findContainer:Pv,createVideoHandler:(e,t,n)=>new Ev(e,t,n)}),Dv.enable()}function Iv(){return Av.status===`booting`||Av.status===`booted`?(Mv(`bootstrap already initialized, skipping duplicate run`,{status:Av.status}),Av.promise??Promise.resolve()):(Av.status=`booting`,Av.promise=(async()=>{try{await Fv(),Av.status=`booted`}catch(e){Av.status=`failed`,Av.error=e,console.error(`[VOT]`,e)}})(),Av.promise)}return Iv(),e.VideoHandler=Ev,e.bootstrapContentScript=Iv,Object.defineProperty(e,`countryCode`,{enumerable:!0,get:function(){return $g}}),e.getEnvironmentInfo=tm,e})({}); +======= +`;return{assignees:`ilyhalight`,template:`1-bug-report-${V.lang===`ru`?`ru`:`en`}.yml`,os:e.os,"script-version":e.scriptVersion,"additional-info":r}}releaseExtraEvents=n_},Mv=new Jm(Am()),Nv=new WeakMap,Pv=null,Fv=si();function Iv(){return{frame:Eo()?`iframe`:`top`,host:globalThis.location.hostname||`unknown`,path:globalThis.location.pathname||`/`}}function Lv(e,t){let n=Iv(),r={host:n.host,path:n.path};t&&Object.assign(r,t),console.log(`[VOT][bootstrap][${n.frame}] ${e}`,r)}function Rv(){return Pv||=Gr(),Pv}function zv(e,t){if(L.log(`findContainer`,e,e.selector,t),!e.selector)return L.log(`findContainer without selector, using parentElement`),t.parentElement;let n=Vo(t,e.selector);return e.shadowRoot?L.log(`findContainer with site.shadowRoot`,n):L.log(`findContainer without shadowRoot`,n),n}async function Bv(){let e=No({isIframe:Eo(),href:String(globalThis.location.href||``),origin:globalThis.location.origin,authOrigin:_i});if(e===`skip`){Lv(`Skipping bootstrap for non-runnable iframe`);return}li(),Lv(`Loading extension`,{mode:e}),e===`auth-eager`?await ko(`auth-page`,Lv):Lv(`Lazy bootstrap enabled; waiting for video detection`),jo({videoObserver:Mv,videosWrappers:Nv,ensureRuntimeActivated:e=>ko(e,Lv),getServicesCached:Rv,findContainer:zv,createVideoHandler:(e,t,n)=>new jv(e,t,n)}),Mv.enable()}function Vv(){return Fv.status===`booting`||Fv.status===`booted`?(Lv(`bootstrap already initialized, skipping duplicate run`,{status:Fv.status}),Fv.promise??Promise.resolve()):(Fv.status=`booting`,Fv.promise=(async()=>{try{await Bv(),Fv.status=`booted`}catch(e){Fv.status=`failed`,Fv.error=e,console.error(`[VOT]`,e)}})(),Fv.promise)}return Vv(),e.VideoHandler=jv,e.bootstrapContentScript=Vv,Object.defineProperty(e,`countryCode`,{enumerable:!0,get:function(){return r_}}),e.getEnvironmentInfo=am,e})({}); +>>>>>>> Stashed changes diff --git a/dist/vot.user.js b/dist/vot.user.js index 31d1b30b..48a46562 100644 --- a/dist/vot.user.js +++ b/dist/vot.user.js @@ -7,7 +7,11 @@ // @name:ru [VOT] - Закадровый перевод видео // @name:zh [VOT] - 画外音视频翻译 // @namespace vot +<<<<<<< Updated upstream // @version 1.11.4 +======= +// @version 1.11.5 +>>>>>>> Stashed changes // @author Toil, SashaXser, MrSoczekXD, mynovelhost, sodapng // @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 @@ -91,9 +95,7 @@ // @match *://*.archive.org/* // @match *://*.patreon.com/* // @match *://*.reddit.com/* -// @match *://*.kodik.info/* -// @match *://*.kodik.biz/* -// @match *://*.kodik.cc/* +// @match *://*.kodikplayer.com/* // @match *://*.kick.com/* // @match *://developer.apple.com/* // @match *://dev.epicgames.com/* @@ -286,14 +288,14 @@ var vot = (function(exports) { "host": "api.browser.yandex.ru", "hostVOT": "vot.toil.cc/v1", "hostWorker": "vot-worker.toil.cc", - "mediaProxy": "media-proxy.toil.cc", - "userAgent": " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 YaBrowser/26.3.1.981 Yowser/2.5 Safari/537.36", - "componentVersion": "26.3.1.981", + "mediaProxy": "media-proxy.transly.workers.dev", + "userAgent": " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 YaBrowser/26.3.3.869 Yowser/2.5 Safari/537.36", + "componentVersion": "26.3.3.869", "hmac": "bt8xH3VOlb4mqf0nqAibnDOoiPlXsisf", "defaultDuration": 310, "minChunkSize": 5295308, "loggerLevel": 1, - "version": "2.4.16" + "version": "2.4.17" }; //#endregion //#region node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js @@ -2592,7 +2594,7 @@ var vot = (function(exports) { function canLog(level) { return config_default$1.loggerLevel <= level; } - function log(...messages) { + function log$1(...messages) { if (!canLog(LoggerLevel.DEBUG)) return; console.log(prefix, ...messages); } @@ -2600,20 +2602,20 @@ var vot = (function(exports) { if (!canLog(LoggerLevel.INFO)) return; console.info(prefix, ...messages); } - function warn(...messages) { + function warn$1(...messages) { if (!canLog(LoggerLevel.WARN)) return; console.warn(prefix, ...messages); } - function error(...messages) { + function error$1(...messages) { if (!canLog(LoggerLevel.ERROR)) return; console.error(prefix, ...messages); } var Logger = { canLog, - log, + log: log$1, info, - warn, - error + warn: warn$1, + error: error$1 }; //#endregion //#region src/shims/nodeCrypto.ts @@ -2842,16 +2844,6 @@ var vot = (function(exports) { if (!(url instanceof URL)) return `${generalUrl}&url=${btoa(url)}`; return `${generalUrl}&url=${btoa(url.href)}&origin=${url.origin}&referer=${url.origin}`; } - function buildVkVideoUrl$1(videoId, sourceUrl) { - const cleanedVideoId = videoId.replace(/^\/+/, ""); - const out = new URL("https://vk.com/video"); - out.searchParams.set("z", cleanedVideoId); - for (const key of ["list", "access_key"]) { - const value = sourceUrl.searchParams.get(key); - if (value) out.searchParams.set(key, value); - } - return out.toString(); - } //#endregion //#region node_modules/@vot.js/core/dist/protobuf.js function encodeTranslationRequest(url, duration, requestLang, responseLang, translationHelp, { forceSourceLang = false, wasStream = false, videoTitle = "", bypassCache = false, useLivelyVoice = false, firstRequest = true } = {}) { @@ -3724,7 +3716,7 @@ var vot = (function(exports) { { additionalData: "mobile", host: VideoService$1.vk, - url: "https://vk.com/video?z=", + url: "https://vk.com/", match: [/^m.vk.(com|ru)$/, /^m.vkvideo.ru$/], selector: sharedSelectors.vkVideoPlayer, shadowRoot: true, @@ -3733,14 +3725,14 @@ var vot = (function(exports) { { additionalData: "clips", host: VideoService$1.vk, - url: "https://vk.com/video?z=", + url: "https://vk.com/", match: /^(www.|m.)?vk.(com|ru)$/, selector: "div[data-testid=\"clipcontainer-video\"]", needExtraData: true }, { host: VideoService$1.vk, - url: "https://vk.com/video?z=", + url: "https://vk.com/", match: [/^(www\.|m\.)?vk\.(com|ru)$/, /^(.*\.)?vkvideo\.ru$/], selector: sharedSelectors.vkVideoPlayer, needExtraData: true @@ -3956,7 +3948,6 @@ var vot = (function(exports) { url: "https://yadi.sk/", match: /^disk.yandex.(ru|kz|com(\.(am|ge|tr))?|by|az|co\.il|ee|lt|lv|md|net|tj|tm|uz)$/, selector: ".video-player__player > div:nth-child(1)", - eventSelector: ".video-player__player", needBypassCSP: true, needExtraData: true }, @@ -4015,12 +4006,13 @@ var vot = (function(exports) { host: VideoService$1.archive, url: "https://archive.org/details/", match: /^archive.org$/, - selector: sharedSelectors.jwPlayer + selector: sharedSelectors.jwPlayer, + needExtraData: true }, { host: VideoService$1.kodik, url: "stub", - match: /^kodik.(info|biz|cc)$/, + match: /^kodikplayer.com$/, selector: sharedSelectors.flowplayer, needExtraData: true }, @@ -4075,7 +4067,7 @@ var vot = (function(exports) { host: VideoService$1.odysee, url: "stub", match: /^odysee.com$/, - selector: sharedSelectors.videoJsUniversal, + selector: ".video-js-parent", needExtraData: true }, { @@ -4347,7 +4339,21 @@ var vot = (function(exports) { //#region node_modules/@vot.js/ext/dist/helpers/archive.js var ArchiveHelper = class extends BaseHelper { async getVideoId(url) { - return /(details|embed)\/([^/]+)/.exec(url.pathname)?.[2]; + const videoId = /(details|embed)\/(.+)/.exec(url.pathname)?.[2]; + if (!videoId) return void 0; + return videoId.replace(/\/$/, "") || void 0; + } + async getVideoData(videoId) { + if (!videoId) return void 0; + const downloadUrl = `https://archive.org/download/${videoId.replace(/\+/g, "%20").replace(/\.[^.]+$/, ".mp4")}`; + return { + url: videoId, + video_url: downloadUrl, + translationHelp: [{ + target: "video_file_url", + targetUrl: downloadUrl + }] + }; } }; //#endregion @@ -4551,14 +4557,18 @@ var vot = (function(exports) { const { file: videoUrl, duration, title } = lessonsData?.[lessonId - 1]; if (!videoUrl) return; return { - url: proxyMedia(videoUrl), + url: videoId, + video_url: videoUrl, + translationHelp: [{ + target: "video_file_url", + targetUrl: proxyMedia(videoUrl) + }], duration, title }; } async getVideoId(url) { - const courseId = /course\/([^/]+)/.exec(url.pathname)?.[0]; - return courseId ? courseId + url.search : void 0; + return url.href; } }; //#endregion @@ -4742,7 +4752,7 @@ var vot = (function(exports) { SUBTITLE_SOURCE = "datacamp"; getVideoDataFromInput() { try { - const input = document.getElementById("videoData"); + const input = document.querySelector("#slideDeckData") || document.getElementById("videoData"); if (!input || !(input instanceof HTMLInputElement) && !(input instanceof HTMLTextAreaElement) || !input.value) return null; return JSON.parse(input.value); } catch (err) { @@ -4751,10 +4761,9 @@ var vot = (function(exports) { } } async getVideoData(videoId) { - const data = this.getVideoDataByPlayer(videoId); - if (!data) return; + if (!this.getVideoDataByPlayer(videoId)) return; const meta = this.getVideoDataFromInput(); - const videoUrl = meta?.video_url ?? meta?.plain_video_mp4_link ?? meta?.plain_video_hls_link ?? meta?.video_mp4_link ?? meta?.video_hls_link ?? data.url; + const videoUrl = meta?.video_url ?? meta?.plain_video_mp4_link ?? meta?.plain_video_hls_link ?? meta?.video_mp4_link ?? meta?.video_hls_link; if (!videoUrl) return; return { url: videoId, @@ -5129,7 +5138,7 @@ var vot = (function(exports) { } } decryptUrl(encryptedUrl) { - return `https:${atob(encryptedUrl.replace(/[a-zA-Z]/g, (e) => { + return `${atob(encryptedUrl.replace(/[a-zA-Z]/g, (e) => { const charCode = e.charCodeAt(0) + 18; const pos = e <= "Z" ? 90 : 122; return String.fromCharCode(pos >= charCode ? charCode : charCode - 26); @@ -5142,7 +5151,7 @@ var vot = (function(exports) { if (!videoData) return; const videoLink = Object.entries(videoData.links[videoData.default.toString()]).find(([, data]) => data.type === "application/x-mpegURL")?.[1]; if (!videoLink) return; - return { url: videoLink.src.startsWith("//") ? `https:${videoLink.src}` : this.decryptUrl(videoLink.src) }; + return { url: videoLink.src.startsWith("//") ? `${videoLink.src}` : this.decryptUrl(videoLink.src) }; } async getVideoId(url) { return /\/(uv|video|seria|episode|season|serial)\/([^/]+)\/([^/]+)\/([\d]+)p/.exec(url.pathname)?.[0]; @@ -5327,15 +5336,7 @@ var vot = (function(exports) { var OdyseeHelper = class extends BaseHelper { API_ORIGIN = "https://odysee.com"; async getVideoData(videoId) { - try { - const content = await (await this.fetch(`${this.API_ORIGIN}/${videoId}`)).text(); - const url = /"contentUrl":(\s)?"([^"]+)"/.exec(content)?.[2]; - if (!url) throw new VideoHelperError("Odysee url doesn't parsed"); - return { url }; - } catch (err) { - Logger.error(`Failed to get odysee video data by video ID: ${videoId}`, err.message); - return; - } + return { url: `${this.API_ORIGIN}/${videoId}`.replace(/:[a-zA-Z0-9]+$/, "") }; } async getVideoId(url) { return url.pathname.slice(1); @@ -5481,18 +5482,28 @@ var vot = (function(exports) { //#region node_modules/@vot.js/ext/dist/helpers/reddit.js var RedditHelper = class extends BaseHelper { API_ORIGIN = "https://www.reddit.com"; - async getContentUrl(_videoId) { - if (this.service?.additionalData !== "old") { - const player = document.querySelector("shreddit-player-2, shreddit-player"); - return (player?.getAttribute("src") ?? player?.querySelector("source[type=\"application/vnd.apple.mpegURL\"]")?.getAttribute("src"))?.replaceAll("&", "&"); - } - return document.querySelector("[data-hls-url]")?.dataset.hlsUrl?.replaceAll("&", "&"); + async getDashAudioUrl(dashUrl) { + const res = await fetch(dashUrl); + if (!res.ok) return void 0; + const xml = await res.text(); + const doc = new DOMParser().parseFromString(xml, "application/xml"); + const audioBaseUrl = doc.querySelector("AdaptationSet[contentType=\"audio\"] BaseURL")?.textContent ?? doc.querySelector("Representation[id=\"AUDIO-1\"] BaseURL")?.textContent; + if (!audioBaseUrl) return void 0; + const base = new URL(dashUrl); + return new URL(audioBaseUrl, base).href; } async getVideoData(videoId) { try { - const contentUrl = await this.getContentUrl(videoId); - if (!contentUrl) throw new VideoHelperError("Failed to find content url"); - return { url: decodeURIComponent(contentUrl) }; + const res = await fetch(`${this.API_ORIGIN}/r/${videoId}.json`, { headers: { Accept: "application/json" } }); + if (!res.ok) throw new VideoHelperError(`Reddit API error: ${res.status}`); + const post = (await res.json())?.[0]?.data?.children?.[0]?.data; + const redditVideo = post?.secure_media?.reddit_video ?? post?.media?.reddit_video ?? post?.crosspost_parent_list?.[0]?.secure_media?.reddit_video ?? post?.crosspost_parent_list?.[0]?.media?.reddit_video; + if (!redditVideo) throw new VideoHelperError("No reddit_video found in post"); + const dashUrl = redditVideo.dash_url?.replaceAll("&", "&"); + if (!dashUrl) throw new VideoHelperError("No dash_url in reddit_video"); + const audioUrl = await this.getDashAudioUrl(dashUrl); + if (!audioUrl) throw new VideoHelperError("Failed to extract audio URL from DASH MPD"); + return { url: audioUrl }; } catch (err) { Logger.error(`Failed to get reddit video data by video ID: ${videoId}`, err.message); return; @@ -6165,22 +6176,11 @@ var vot = (function(exports) { var VKHelper = class VKHelper extends BaseHelper { static getPlayer() { if (typeof Videoview === "undefined") return; - try { - return Videoview?.getPlayerObject?.(); - } catch { - return; - } + return Videoview?.getPlayerObject?.call(void 0); } async getVideoData(videoId) { - const currentUrl = new URL(window.location.href); const player = VKHelper.getPlayer(); - if (!player) { - const base = this.returnBaseData(videoId); - return base ? { - ...base, - url: buildVkVideoUrl$1(videoId, currentUrl) - } : base; - } + if (!player) return this.returnBaseData(videoId); try { const { description: descriptionHTML, duration, md_title: title } = player.vars; const doc = new DOMParser().parseFromString(descriptionHTML, "text/html"); @@ -6194,7 +6194,7 @@ var vot = (function(exports) { isAutoGenerated: !!sub.is_auto })); return { - url: buildVkVideoUrl$1(videoId, currentUrl), + url: this.service?.url + videoId, title, description, duration, @@ -6202,26 +6202,19 @@ var vot = (function(exports) { }; } catch (err) { Logger.error(`Failed to get VK video data, because: ${err.message}`); - const base = this.returnBaseData(videoId); - return base ? { - ...base, - url: buildVkVideoUrl$1(videoId, currentUrl) - } : base; + return this.returnBaseData(videoId); } } async getVideoId(url) { - const pathID = /^\/((?:video|clip)-?\d+_\d+)(?:\/)?$/.exec(url.pathname); - if (pathID) return pathID[1]; - const idInsidePlaylist = /\/playlist\/[^/]+\/(video-?\d+_\d+)/.exec(url.pathname); + const pathID = /^\/(video|clip)-?\d{8,9}_\d{9}$/.exec(url.pathname); + if (pathID) return pathID[0].slice(1); + const idInsidePlaylist = /\/playlist\/[^/]+\/(video-?\d{8,9}_\d{9})/.exec(url.pathname); if (idInsidePlaylist) return idInsidePlaylist[1]; const paramZ = url.searchParams.get("z"); if (paramZ) return paramZ.split("/")[0]; const paramOID = url.searchParams.get("oid"); const paramID = url.searchParams.get("id"); - if (paramOID && paramID) { - const ownerId = Math.abs(Number.parseInt(paramOID, 10)); - if (!Number.isNaN(ownerId)) return `video-${ownerId}_${paramID}`; - } + if (paramOID && paramID) return `video-${Math.abs(parseInt(paramOID, 10))}_${paramID}`; } }; //#endregion @@ -6763,16 +6756,6 @@ var vot = (function(exports) { function hasHelper(host) { return host in availableHelpers; } - function buildVkVideoUrl(videoId, sourceUrl) { - const cleanedVideoId = videoId.replace(/^\/+/, ""); - const out = new URL("https://vk.com/video"); - out.searchParams.set("z", cleanedVideoId); - for (const key of ["list", "access_key"]) { - const value = sourceUrl.searchParams.get(key); - if (value) out.searchParams.set(key, value); - } - return out.toString(); - } function getService() { if (localLinkRe.exec(window.location.href)) return []; const hostname = window.location.hostname; @@ -6810,20 +6793,12 @@ var vot = (function(exports) { host: service.host, duration: void 0 }; - if (!service.needExtraData) { - if (service.host === VideoService$1.vk) return { - url: buildVkVideoUrl(videoId, currentUrl), - videoId, - host: service.host, - duration: void 0 - }; - return { - url: service.url + videoId, - videoId, - host: service.host, - duration: void 0 - }; - } + if (!service.needExtraData) return { + url: service.url + videoId, + videoId, + host: service.host, + duration: void 0 + }; if (!hasHelper(service.host)) throw new VideoDataError(`No helper is available for "${service.host}"`); const result = await new VideoHelper({ ...opts, @@ -6833,7 +6808,7 @@ var vot = (function(exports) { if (!result) throw new VideoDataError(`Failed to get video raw url for ${service.host}`); return { ...result, - url: service.host === VideoService$1.vk ? buildVkVideoUrl(videoId, currentUrl) : result.url, + url: result.url, videoId, host: service.host }; @@ -6979,7 +6954,11 @@ var vot = (function(exports) { audio; gainNode; audioSource; +<<<<<<< Updated upstream suspendTimer; +======= + gainValue = 1; +>>>>>>> Stashed changes constructor(chaimu, src) { super(chaimu, src); this.updateAudio(); @@ -7027,6 +7006,7 @@ var vot = (function(exports) { this.initAudioBooster(); return this; } +<<<<<<< Updated upstream async resumeAndPlayAudio() { if (!this.audio || this.isPlaybackBlocked()) return; this.cancelSuspend(); @@ -7036,6 +7016,16 @@ var vot = (function(exports) { } catch (error) { this.handlePlaybackError("play audio element", error); } +======= + audioErrorHandle = (e) => { + console.error("[AudioPlayer]", e); + }; + syncAudioToVideo() { + if (!this.chaimu.video) return false; + this.audio.currentTime = this.chaimu.video.currentTime; + this.audio.playbackRate = this.chaimu.video.playbackRate; + return true; +>>>>>>> Stashed changes } lipSync(mode = false) { debug_default.log("[AudioPlayer] lipsync video", this.chaimu.video); @@ -7080,14 +7070,22 @@ var vot = (function(exports) { } async play() { debug_default.log("[AudioPlayer] play called"); +<<<<<<< Updated upstream await this.resumeAndPlayAudio(); +======= + if (this.audio) await this.audio.play().catch(this.audioErrorHandle); +>>>>>>> Stashed changes return this; } async pause() { debug_default.log("[AudioPlayer] pause called"); +<<<<<<< Updated upstream this.isBuffering = false; if (this.audio) this.audio.pause(); this.scheduleSuspend(); +======= + if (this.audio) this.audio.pause(); +>>>>>>> Stashed changes return this; } set src(url) { @@ -7521,11 +7519,19 @@ var vot = (function(exports) { ]; //#endregion //#region src/utils/debug.ts - var noop = () => {}; + var log = (...text) => { + console.log("%c[VOT DEBUG]", "background: #3700ffff; color: #fff; padding: 5px;", ...text); + }; + var warn = (...text) => { + console.warn("%c[VOT DEBUG]", "background: #e1ff00ff; color: #fff; padding: 5px;", ...text); + }; + var error = (...text) => { + console.error("%c[VOT DEBUG]", "background: #F2452D; color: #fff; padding: 5px;", ...text); + }; var debug = { - log: noop, - warn: noop, - error: noop + log, + warn, + error }; //#endregion //#region src/utils/localization.ts @@ -7660,7 +7666,9 @@ var vot = (function(exports) { if (options.fileHandle) { if (await writeBlobToHandle(options.fileHandle, blob)) return true; } - if (options.preferShare) return await shareBlob(blob, filename) === "shared"; + if (options.preferShare) { + if (await shareBlob(blob, filename) === "shared") return true; + } return triggerBlobDownload(blob, filename); } function revokeObjectUrlLater(url, delayMs = DEFAULT_OBJECT_URL_REVOKE_DELAY_MS) { @@ -8181,6 +8189,7 @@ var vot = (function(exports) { } }; } +<<<<<<< Updated upstream //#endregion //#region src/utils/gm.ts var YANDEX_API_HOST = "api.browser.yandex.ru"; @@ -17329,6 +17338,8 @@ var vot = (function(exports) { "left", "right" ]; +======= +>>>>>>> Stashed changes var browserInfo = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => { (function(e, t) { "object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.bowser = t() : e.bowser = t(); @@ -19045,6 +19056,9358 @@ var vot = (function(exports) { })); })))(), 1)).default.getParser(globalThis.navigator.userAgent).getResult(); //#endregion + //#region src/utils/gm.ts + var YANDEX_API_HOST = "api.browser.yandex.ru"; + var GOOGLEVIDEO_HOST_SUFFIX = "googlevideo.com"; + var HEADER_LINE_RE = /^([\w-]+):\s*(.+)$/; + var URL_SCHEME_RE = /^[a-zA-Z][a-zA-Z\d+.-]*:/; + var scriptHandler = typeof GM_info === "undefined" ? void 0 : GM_info?.scriptHandler; + function getCallbackGmXhr() { + const gmXhr = typeof GM_xmlhttpRequest === "undefined" ? globalThis.GM_xmlhttpRequest : GM_xmlhttpRequest; + return typeof gmXhr === "function" ? gmXhr : void 0; + } + function getPromiseGmXhr() { + const gm = typeof GM === "undefined" ? globalThis.GM : GM; + const gmXhr = gm?.xmlHttpRequest ?? gm?.xmlhttpRequest; + return typeof gmXhr === "function" ? gmXhr.bind(gm) : void 0; + } + function hasSupportedGmXhr() { + return !!(getCallbackGmXhr() || getPromiseGmXhr()); + } + var isProxyOnlyExtension = !(typeof IS_EXTENSION !== "undefined" && IS_EXTENSION) && (browserInfo.browser?.name === "Safari" || !["Tampermonkey", "Violentmonkey"].includes(scriptHandler)); + var isSupportGM4 = typeof GM !== "undefined" || globalThis.GM !== void 0; + var isSupportGMXhr = hasSupportedGmXhr(); + function getRequestHost(url) { + const normalizedUrl = url.trim(); + try { + return new URL(normalizedUrl).hostname.toLowerCase(); + } catch { + if (!URL_SCHEME_RE.test(normalizedUrl)) try { + return new URL(`https://${normalizedUrl}`).hostname.toLowerCase(); + } catch {} + return; + } + } + function isHostOrSubdomain(host, targetHost) { + return host === targetHost || host.endsWith(`.${targetHost}`); + } + function shouldUseGmXhr(host, url, forceGmXhr = false) { + if (forceGmXhr) return true; + if (!host) { + const lowerUrl = url.toLowerCase(); + return lowerUrl.includes(YANDEX_API_HOST) || lowerUrl.includes(GOOGLEVIDEO_HOST_SUFFIX); + } + return isHostOrSubdomain(host, YANDEX_API_HOST) || isHostOrSubdomain(host, GOOGLEVIDEO_HOST_SUFFIX); + } + function toRequestUrl(url) { + if (typeof url === "string") return url; + if (url instanceof URL) return url.href; + return url.url; + } + function resolveRequestMethod(url, method) { + if (method) return method.toUpperCase(); + if (url instanceof Request) return (url.method || "GET").toUpperCase(); + return "GET"; + } + function parseResponseHeaders(rawHeaders) { + if (typeof rawHeaders !== "string" || rawHeaders.length === 0) return {}; + return rawHeaders.split(/\r?\n/).reduce((acc, line) => { + const headerMatch = HEADER_LINE_RE.exec(line); + if (!headerMatch) return acc; + const [, key, value] = headerMatch; + acc[key] = value; + return acc; + }, {}); + } + function getGmXhrErrorMessage(error) { + const maybeError = error; + if (typeof maybeError?.error === "string" && maybeError.error.trim().length > 0) return maybeError.error; + if (typeof maybeError?.statusText === "string" && maybeError.statusText.trim().length > 0 && maybeError.statusText !== "\"\"" && maybeError.statusText !== "''") return maybeError.statusText; + return getErrorMessage(error) || "Unknown GM XHR error"; + } + function buildResponse(resp, urlStr) { + const status = resp.status; + const statusText = typeof resp.statusText === "string" ? resp.statusText : ""; + const body = resp.response instanceof Blob ? resp.response : null; + const responseHeaders = parseResponseHeaders(resp.responseHeaders); + const response = new Response(body, { + status, + statusText, + headers: responseHeaders + }); + Object.defineProperty(response, "url", { value: resp.finalUrl ?? urlStr }); + return response; + } + async function executeCallbackGmXhr(gmXhr, urlStr, timeout, fetchOptions, method, headers) { + return new Promise((resolve, reject) => { + let settled = false; + let onAbort; + const cleanupAbort = () => { + if (onAbort) fetchOptions.signal?.removeEventListener("abort", onAbort); + }; + const failOnce = (error) => { + if (settled) return; + settled = true; + cleanupAbort(); + reject(error); + }; + const request = gmXhr({ + method, + url: urlStr, + responseType: "blob", + data: fetchOptions.body, + timeout, + headers, + onload: (resp) => { + if (settled) return; + settled = true; + cleanupAbort(); + try { + const response = buildResponse(resp, urlStr); + debug.log("[GM_fetch] GM_xmlhttpRequest completed", { + url: response.url, + method, + status: response.status, + statusText: response.statusText + }); + resolve(response); + } catch (buildErr) { + debug.warn("[GM_fetch] GM_xmlhttpRequest response build failed", { + url: urlStr, + method, + error: getErrorMessage(buildErr), + rawStatus: resp.status, + rawStatusText: resp.statusText + }); + reject(buildErr instanceof Error ? buildErr : new Error(getErrorMessage(buildErr))); + } + }, + ontimeout: () => { + debug.warn("[GM_fetch] GM_xmlhttpRequest timed out", { + url: urlStr, + method, + timeout + }); + failOnce(/* @__PURE__ */ new Error("Timeout")); + }, + onerror: (error) => { + const message = getGmXhrErrorMessage(error); + debug.warn("[GM_fetch] GM_xmlhttpRequest failed", { + url: urlStr, + method, + error: message + }); + failOnce(new Error(message)); + }, + onabort: () => { + debug.warn("[GM_fetch] GM_xmlhttpRequest aborted", { + url: urlStr, + method + }); + failOnce(makeAbortError()); + } + }); + onAbort = () => { + try { + request?.abort?.(); + } catch {} + failOnce(makeAbortError()); + }; + if (fetchOptions.signal) { + fetchOptions.signal.addEventListener("abort", onAbort, { once: true }); + if (fetchOptions.signal.aborted) { + onAbort(); + return; + } + } + }); + } + async function executePromiseGmXhr(gmXhr, urlStr, timeout, fetchOptions, method, headers) { + const request = gmXhr({ + method, + url: urlStr, + responseType: "blob", + data: fetchOptions.body, + timeout, + headers + }); + let abortHandler; + try { + const abortPromise = new Promise((_, reject) => { + if (!fetchOptions.signal) return; + abortHandler = () => { + try { + request.abort?.(); + } catch {} + reject(makeAbortError()); + }; + fetchOptions.signal.addEventListener("abort", abortHandler, { once: true }); + if (fetchOptions.signal.aborted) abortHandler(); + }); + const response = buildResponse(await Promise.race([request, abortPromise]), urlStr); + debug.log("[GM_fetch] GM.xmlHttpRequest completed", { + url: response.url, + method, + status: response.status, + statusText: response.statusText + }); + return response; + } finally { + if (abortHandler) fetchOptions.signal?.removeEventListener("abort", abortHandler); + } + } + async function gmXhrFetch(urlStr, timeout, fetchOptions) { + const headers = getHeaders(fetchOptions.headers); + const method = (fetchOptions.method || "GET").toUpperCase(); + debug.log("[GM_fetch] GM_xmlhttpRequest start", { + url: urlStr, + method, + timeout, + headerCount: Object.keys(headers).length + }); + const callbackGmXhr = getCallbackGmXhr(); + if (callbackGmXhr) { + debug.log("[GM_fetch] attempting callback-style GM_xmlhttpRequest"); + try { + return await executeCallbackGmXhr(callbackGmXhr, urlStr, timeout, fetchOptions, method, headers); + } catch (error) { + if (isAbortError$1(error)) throw error; + debug.warn("[GM_fetch] callback-style GM_xmlhttpRequest failed", { + url: urlStr, + method, + error: getGmXhrErrorMessage(error) + }); + } + } + const promiseGmXhr = getPromiseGmXhr(); + if (promiseGmXhr) { + debug.log("[GM_fetch] attempting promise-style GM.xmlHttpRequest"); + try { + return await executePromiseGmXhr(promiseGmXhr, urlStr, timeout, fetchOptions, method, headers); + } catch (error) { + if (isAbortError$1(error)) throw error; + debug.warn("[GM_fetch] promise-style GM.xmlHttpRequest failed", { + url: urlStr, + method, + error: getGmXhrErrorMessage(error) + }); + } + } + debug.warn("[GM_fetch] none of the GM approaches worked"); + throw new Error("All GM approaches failed"); + } + async function GM_fetch(url, opts = {}) { + const { timeout = 15e3, forceGmXhr = false, responseCache, ...fetchOptions } = opts; + const urlStr = toRequestUrl(url); + const host = getRequestHost(urlStr); + const method = resolveRequestMethod(url, fetchOptions.method); + const useGmXhr = shouldUseGmXhr(host, urlStr, forceGmXhr); + debug.log("[GM_fetch] request", { + url: urlStr, + method, + host: host ?? "unknown", + timeout, + transport: useGmXhr ? "GM_xmlhttpRequest" : "fetch", + forced: forceGmXhr, + responseCache: responseCache ? { + ttlMs: responseCache.ttlMs, + key: responseCache.key ?? null, + useMemory: responseCache.useMemory ?? true, + useCacheApi: responseCache.useCacheApi ?? true, + dedupe: responseCache.dedupe ?? true + } : null + }); + const performRequest = async () => { + if (useGmXhr) { + debug.log("[GM_fetch] using GM_xmlhttpRequest transport", { + url: urlStr, + method, + host: host ?? "unknown", + reason: forceGmXhr ? "forced" : "host-policy" + }); + try { + return await gmXhrFetch(urlStr, timeout, fetchOptions); + } catch (err) { + if (isAbortError$1(err)) throw err; + if (forceGmXhr || shouldUseGmXhr(host, urlStr)) throw err; + debug.warn("[GM_fetch] all GM approaches failed, falling back to native fetch", { + url: urlStr, + method, + host: host ?? "unknown", + error: getErrorMessage(err) || "Unknown error" + }); + const { signal, cleanup } = createTimeoutSignal(timeout, fetchOptions.signal); + try { + return await fetch(url, { + ...fetchOptions, + signal + }); + } finally { + cleanup(); + } + } + } + const { signal, cleanup } = createTimeoutSignal(timeout, fetchOptions.signal); + try { + return await fetch(url, { + ...fetchOptions, + signal + }); + } catch (err) { + if (signal.aborted || isAbortError$1(err)) throw err; + debug.warn("[GM_fetch] fetch failed, retrying via GM_xmlhttpRequest", { + url: urlStr, + method, + host: host ?? "unknown", + error: getErrorMessage(err) || "Unknown error" + }); + return await gmXhrFetch(urlStr, timeout, fetchOptions); + } finally { + cleanup(); + } + }; + if (!responseCache) return await performRequest(); + return await executeWithResponseCache({ + url: urlStr, + method, + body: fetchOptions.body + }, responseCache, performRequest); + } + //#endregion + //#region src/utils/storage.ts + var compatRules = Object.entries({ + numToBool: [ + ["autoTranslate"], + ["dontTranslateYourLang", "enabledDontTranslateLanguages"], + ["autoSetVolumeYandexStyle", "enabledAutoVolume"], + ["showVideoSlider"], + ["syncVolume"], + ["downloadWithName"], + ["sendNotifyOnComplete"], + ["highlightWords"], + ["onlyBypassMediaCSP"], + ["newAudioPlayer"], + ["showPiPButton"], + ["translateAPIErrors"], + ["audioBooster"], + ["useNewModel", "useLivelyVoice"] + ], + number: [["autoVolume"]], + array: [["dontTranslateLanguage", "dontTranslateLanguages"]], + string: [ + ["hotkeyButton", "translationHotkey"], + ["locale-lang-override", "localeLangOverride"], + ["locale-lang", "localeLang"] + ] + }).flatMap(([category, entries]) => entries.map(([oldKey, maybeNewKey]) => ({ + category, + oldKey, + newKey: maybeNewKey ?? oldKey, + shouldDeleteOldKey: Boolean(maybeNewKey) + }))); + var compatRuleByOldKey = new Map(compatRules.map((rule) => [rule.oldKey, rule])); + var compatKeysToRead = Array.from(new Set(compatRules.map((rule) => rule.oldKey))); + function createUndefinedDefaults(keys) { + const defaults = {}; + for (const key of keys) defaults[key] = void 0; + return defaults; + } + function isCompatValue(category, value) { + switch (category) { + case "numToBool": + case "number": return typeof value === "number"; + case "array": return Array.isArray(value); + case "string": return typeof value === "string" || value === null; + default: return false; + } + } + function convertByCompatCategory(category, value) { + switch (category) { + case "string": + case "array": + case "number": return value; + default: return !!value; + } + } + function normalizeCompatValue(rule, value) { + let convertedValue = convertByCompatCategory(rule.category, value); + if (rule.oldKey === "autoVolume" && typeof value === "number" && value < 1) convertedValue = Math.round(value * 100); + return convertedValue; + } + function areStorageValuesEqual(a, b) { + if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((item, index) => Object.is(item, b[index])); + return Object.is(a, b); + } + function parseStoredValue(rawValue) { + if (rawValue === null) return; + try { + return JSON.parse(rawValue); + } catch { + return; + } + } + async function updateConfig(data) { + if (data.compatVersion === "2025-05-09") return data; + const keysToRead = new Set([...Object.keys(data), ...compatKeysToRead]); + const persistedValues = await votStorage.getValues(createUndefinedDefaults(keysToRead)); + const newData = { ...data }; + const writeOperations = []; + const deleteOperations = []; + for (const [key, storedValue] of Object.entries(persistedValues)) { + if (storedValue === void 0) continue; + const compatRule = compatRuleByOldKey.get(key); + if (!compatRule || !isCompatValue(compatRule.category, storedValue)) continue; + const convertedValue = normalizeCompatValue(compatRule, storedValue); + newData[compatRule.newKey] = convertedValue; + const existingNewValue = persistedValues[compatRule.newKey]; + if (compatRule.shouldDeleteOldKey || !areStorageValuesEqual(existingNewValue, convertedValue)) writeOperations.push(votStorage.set(compatRule.newKey, convertedValue)); + if (compatRule.shouldDeleteOldKey) deleteOperations.push(votStorage.delete(compatRule.oldKey)); + } + await Promise.all([...writeOperations, ...deleteOperations]); + return { + ...newData, + compatVersion: actualCompatVersion + }; + } + var VOTStorage = class { + support = null; + localStorageListeners = /* @__PURE__ */ new Map(); + shouldUseSyntheticListeners(support) { + return !support.promiseAddValueChangeListener && !support.legacyAddValueChangeListener; + } + getGMRuntime() { + if (typeof GM !== "undefined") return GM; + return globalThis.GM; + } + resolveSupport() { + if (this.support) return this.support; + const gm = this.getGMRuntime(); + const support = { + legacyGet: typeof GM_getValue === "function", + legacySet: typeof GM_setValue === "function", + legacyDelete: typeof GM_deleteValue === "function", + legacyList: typeof GM_listValues === "function", + legacyAddValueChangeListener: typeof globalThis.GM_addValueChangeListener === "function", + legacyRemoveValueChangeListener: typeof globalThis.GM_removeValueChangeListener === "function", + promiseGet: isSupportGM4 && typeof gm?.getValue === "function", + promiseGetValues: isSupportGM4 && typeof gm?.getValues === "function", + promiseSet: isSupportGM4 && typeof gm?.setValue === "function", + promiseDelete: isSupportGM4 && typeof gm?.deleteValue === "function", + promiseList: isSupportGM4 && typeof gm?.listValues === "function", + promiseAddValueChangeListener: isSupportGM4 && typeof gm?.addValueChangeListener === "function", + promiseRemoveValueChangeListener: isSupportGM4 && typeof gm?.removeValueChangeListener === "function" + }; + this.support = support; + debug.log(`[VOT Storage] GM Promises: ${support.promiseGet} | GM legacy: ${support.legacyGet}`); + return support; + } + /** + * Check if storage type is LocalStorage + */ + get isSupportOnlyLS() { + const support = this.resolveSupport(); + return !support.legacyGet && !support.legacySet && !support.legacyDelete && !support.legacyList && !support.promiseGet && !support.promiseGetValues && !support.promiseSet && !support.promiseDelete && !support.promiseList; + } + syncGetByName(name, def, support) { + if (support.legacyGet) return GM_getValue(name, def); + const val = globalThis.localStorage.getItem(name); + if (val === null) return def; + try { + return JSON.parse(val); + } catch { + return def; + } + } + async getRaw(name, def) { + const support = this.resolveSupport(); + if (support.promiseGet && GM.getValue) return await GM.getValue(name, def); + return this.syncGetByName(name, def, support); + } + async get(name, def) { + return this.getRaw(name, def); + } + async getValues(data) { + const support = this.resolveSupport(); + if (support.promiseGetValues && GM.getValues) return await GM.getValues(data); + const entries = Object.entries(data); + if (support.promiseGet && GM.getValue) { + const values = await Promise.all(entries.map(async ([key, value]) => { + return [key, await GM.getValue(key, value)]; + })); + return Object.fromEntries(values); + } + return Object.fromEntries(entries.map(([key, value]) => [key, this.syncGetByName(key, value, support)])); + } + syncSetByName(name, value, support) { + if (support.legacySet) return GM_setValue(name, value); + return globalThis.localStorage.setItem(name, JSON.stringify(value)); + } + async setRaw(name, value) { + const support = this.resolveSupport(); + const storageKey = name; + const shouldNotify = this.shouldUseSyntheticListeners(support); + const oldValue = shouldNotify ? await this.getRaw(name) : void 0; + if (support.promiseSet && GM.setValue) { + await GM.setValue(name, value); + if (shouldNotify) this.notifyLocalStorageListeners(storageKey, oldValue, value, false); + return; + } + const setResult = this.syncSetByName(name, value, support); + this.notifyLocalStorageListeners(storageKey, oldValue, value, false); + return setResult; + } + async set(name, value) { + return this.setRaw(name, value); + } + syncDeleteByName(name, support) { + if (support.legacyDelete) return GM_deleteValue(name); + return globalThis.localStorage.removeItem(name); + } + async deleteRaw(name) { + const support = this.resolveSupport(); + const storageKey = name; + const shouldNotify = this.shouldUseSyntheticListeners(support); + const oldValue = shouldNotify ? await this.getRaw(name) : void 0; + if (support.promiseDelete && GM.deleteValue) { + await GM.deleteValue(name); + if (shouldNotify) this.notifyLocalStorageListeners(storageKey, oldValue, void 0, false); + return; + } + const deleteResult = this.syncDeleteByName(name, support); + this.notifyLocalStorageListeners(storageKey, oldValue, void 0, false); + return deleteResult; + } + async delete(name) { + return this.deleteRaw(name); + } + addValueChangeListener(name, listener) { + const support = this.resolveSupport(); + const gm = this.getGMRuntime(); + if (support.promiseAddValueChangeListener) { + const addListener = gm?.addValueChangeListener; + const removeListener = support.promiseRemoveValueChangeListener ? gm?.removeValueChangeListener : void 0; + if (typeof addListener === "function") { + const listenerId = addListener(name, this.createTypedListener(listener)); + return () => { + if (typeof removeListener === "function") removeListener(listenerId); + }; + } + } + if (support.legacyAddValueChangeListener) { + const addListener = globalThis.GM_addValueChangeListener; + const removeListener = support.legacyRemoveValueChangeListener ? globalThis.GM_removeValueChangeListener : void 0; + if (typeof addListener === "function") { + const listenerId = addListener(name, this.createTypedListener(listener)); + return () => { + if (typeof removeListener === "function") removeListener(listenerId); + }; + } + } + const listeners = this.getLocalStorageListeners(name); + const typedListener = listener; + listeners.add(typedListener); + const onStorage = (event) => { + if (event.storageArea !== globalThis.localStorage || event.key !== name) return; + typedListener(name, parseStoredValue(event.oldValue), parseStoredValue(event.newValue), true); + }; + globalThis.addEventListener("storage", onStorage); + return () => { + listeners.delete(typedListener); + if (listeners.size === 0) this.localStorageListeners.delete(name); + globalThis.removeEventListener("storage", onStorage); + }; + } + createTypedListener(listener) { + return (key, oldValue, newValue, remote) => { + listener(key, oldValue, newValue, remote); + }; + } + getLocalStorageListeners(name) { + const existing = this.localStorageListeners.get(name); + if (existing) return existing; + const created = /* @__PURE__ */ new Set(); + this.localStorageListeners.set(name, created); + return created; + } + notifyLocalStorageListeners(name, oldValue, newValue, remote) { + const listeners = this.localStorageListeners.get(name); + if (!listeners || listeners.size === 0) return; + for (const listener of listeners) listener(name, oldValue, newValue, remote); + } + syncList(support) { + if (support.legacyList) return GM_listValues(); + return storageKeys; + } + async list() { + const support = this.resolveSupport(); + if (support.promiseList && GM.listValues) return await GM.listValues(); + return this.syncList(support); + } + }; + var VOT_STORAGE_GLOBAL_KEY = "__VOT_STORAGE_SINGLETON__"; + var votStorage = (() => { + const scope = globalThis; + const existing = scope[VOT_STORAGE_GLOBAL_KEY]; + if (existing instanceof VOTStorage) return existing; + const created = new VOTStorage(); + scope[VOT_STORAGE_GLOBAL_KEY] = created; + return created; + })(); + //#endregion + //#region src/core/authRefreshMessage.ts + var AUTH_REFRESH_MESSAGE_SOURCE = "vot-auth"; + var AUTH_REFRESH_MESSAGE_TYPE = "account-updated"; + function createAuthRefreshMessage() { + return { + source: AUTH_REFRESH_MESSAGE_SOURCE, + type: AUTH_REFRESH_MESSAGE_TYPE + }; + } + function isAuthRefreshMessage(value) { + if (!value || typeof value !== "object") return false; + const candidate = value; + return candidate.source === "vot-auth" && candidate.type === "account-updated"; + } + function notifyAuthOpener(target = globalThis.opener) { + if (!target || typeof target.postMessage !== "function") return; + target.postMessage(createAuthRefreshMessage(), "*"); + } + //#endregion + //#region src/core/auth.ts + function getProfilePayload() { + const payload = globalThis._userData; + if (!payload || typeof payload !== "object") return null; + const candidate = payload; + if (typeof candidate.avatar_id !== "string" || typeof candidate.username !== "string" || candidate.avatar_id.length === 0 || candidate.username.length === 0) return null; + return { + avatar_id: candidate.avatar_id, + username: candidate.username + }; + } + async function handleAuthCallbackPage() { + const { access_token: token, expires_in: expiresIn } = Object.fromEntries(new URLSearchParams(globalThis.location.hash.slice(1))); + if (!token || !expiresIn) throw new Error("[VOT] Invalid token response"); + const numExpiresIn = Number.parseInt(expiresIn, 10); + if (Number.isNaN(numExpiresIn)) throw new TypeError("[VOT] Invalid expires_in value"); + await votStorage.set("account", { + token, + expires: Date.now() + numExpiresIn * 1e3, + username: void 0, + avatarId: void 0 + }); + notifyAuthOpener(); + } + async function handleProfilePage() { + const payload = getProfilePayload(); + if (!payload) throw new Error("[VOT] Invalid user data"); + const { avatar_id: avatarId, username } = payload; + const data = await votStorage.get("account"); + if (!data) throw new Error("[VOT] No account data found"); + await votStorage.set("account", { + ...data, + username, + avatarId + }); + notifyAuthOpener(); + } + async function initAuth() { + if (globalThis.location.pathname === "/auth/callback") return handleAuthCallbackPage(); + if (globalThis.location.pathname === "/my/profile") return handleProfilePage(); + } + var en_default = { + recommended: "recommended", + translateVideo: "Translate video", + disableTranslate: "Turn off", + translationSettings: "Translation settings", + subtitlesSettings: "Subtitles settings", + subtitlesSmartLayout: "Smart subtitle layout", + 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", + requestTranslationFailed: "Failed to request video translation", + audioNotReceived: "Audio link not received", + VOTFailedDownloadAudio: "Failed to download audio", + audioFormatNotSupported: "The audio format is not supported", + VOTAutoTranslate: "Translate on open", + VOTAutoSubtitles: "Subtitles on open", + VOTDontTranslateYourLang: "Don't 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", + VOTDisableFromYourLang: "You have disabled the translation of the video in your language", + VOTVideoIsTooLong: "Video is too long", + VOTNoVideoIDFound: "No video ID found", + VOTSubtitles: "Subtitles", + VOTSubtitlesDisabled: "Disabled", + VOTDefaultSubtitlesLanguage: "Default subtitle language", + VOTOriginalVideoLanguage: "Original video language", + 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" + }, + streamNoConnectionToServer: "There is no connection to the server", + searchField: "Search...", + VOTTranslateAPIErrors: "Translate errors from the API", + VOTDetectService: "Language detection service", + VOTProxyWorkerHost: "Enter the proxy worker address", + VOTM3u8ProxyHost: "Enter the address of the m3u8 proxy worker", + proxySettings: "Proxy Settings", + translationTakeApproximatelyMinute2: "The translation will take approximately {0} minutes", + VOTAudioBooster: "Extended translation volume increase", + VOTSubtitlesDesign: "Subtitles design", + VOTSubtitlesFont: "Subtitle font", + VOTSubtitlesFontSize: "Font size of subtitles", + VOTSubtitlesOpacity: "Transparency of the subtitle background", + VOTSubtitlesDownloadFormat: "The format for downloading subtitles", + VOTDownloadWithName: "Download files with the video name", + VOTUpdateLocaleFiles: "Update localization files", + VOTLocaleHash: "Locale hash", + VOTUpdatedAt: "Updated at", + VOTNeedWebAudioAPI: "To enable this, you must have a Web Audio API", + VOTMediaCSPEnabledOnSite: "Media CSP is enabled on this site", + VOTOnlyBypassMediaCSP: "Use it only for bypassing Media CSP", + VOTNewAudioPlayer: "Use the new audio player", + VOTUseNewModel: "Use an experimental variation of Yandex voices for some videos", + TranslationDelayed: "The translation is slightly delayed", + VOTTranslationCompletedNotify: "The translation on the {0} has been completed!", + VOTSendNotifyOnComplete: "Send a notification that the video has been translated", + VOTBugReport: "Report a bug", + VOTTranslateProxyDisabled: "Disabled", + VOTTranslateProxyEnabled: "Enabled", + VOTTranslateProxyEverything: "Proxy everything", + VOTTranslateProxyStatus: "Proxying mode", + VOTTranslatedBy: "Translated by {0}", + VOTStreamNotAvailable: "Translate stream isn't available", + VOTTranslationTextService: "Text translation service", + VOTNotAffectToVoice: "Doesn't affect the translation of text in voice over", + DontTranslateSelectedLanguages: "Don't translate from selected languages", + showVideoVolumeSlider: "Display the video volume slider", + hotkeysSettings: "Hotkeys settings", + None: "None", + VOTUseLivelyVoice: "Use lively voices. Speakers sound like native Russians.", + miscSettings: "Misc settings", + services: { + "yandexbrowser": "Yandex Browser", + "msedge": "Microsoft Edge", + "rust-server": "Rust Server" + }, + aboutExtension: "About extension", + appearance: "Appearance", + buttonPosition: "Button position in the player", + position: { + "left": "Left", + "right": "Right", + "top": "Top", + "default": "Default" + }, + secs: "secs", + autoHideButtonDelay: "Delay before hiding the translate button", + notFound: "not found", + minButtonPositionContainer: "The button position only changes in players larger than 600 pixels.", + VOTTranslateProxyStatusDefault: "Completely disabling proxying in your country may break the extension", + PressTheKeyCombination: "Press the key combination...", + VOTUseAudioDownload: "Use audio download", + VOTUseAudioDownloadWarning: "Disabling audio downloads may affect the functionality of the extension", + VOTAccountRequired: "You need to log in to use this feature", + VOTMyAccount: "My account", + VOTLogin: "Login", + VOTLogout: "Logout", + VOTRefresh: "Refresh", + VOTYandexToken: "Enter the Yandex OAuth Token", + VOTYandexTokenInfo: "You can manually set the account token in this field. Please note that we don't check its validity before sending a translate request", + VOTLoginViaToken: "Login via token", + smartDucking: "Adaptive volume" + }; + //#endregion + //#region src/localization/localizationProvider.ts + var LOCALE_STORAGE_KEYS = [ + "localePhrases", + "localeLang", + "localeHash", + "localeVersion", + "localeUpdatedAt", + "localeLangOverride" + ]; + var DEFAULT_LOCALE = toFlatObj(en_default); + var repoBranch = "master"; + var availableLocales = (() => { + const locales = Array.isArray([ + "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" + ]) ? [ + "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" + ] : ["en"]; + return locales.includes("auto") ? locales : ["auto", ...locales]; + })(); + function resolveRuntimeLocaleVersion(buildVersion, scriptVersion) { + return buildVersion || scriptVersion || "unknown"; + } + function getRuntimeLocaleVersion() { + return resolveRuntimeLocaleVersion(String("1.11.5"), typeof GM_info !== "undefined" ? String(GM_info?.script?.version || "") : ""); + } + var LocalizationProvider = class { + /** + * Language used before page was reloaded + */ + lang; + /** + * Locale phrases with current language + */ + locale; + defaultLocale = DEFAULT_LOCALE; + localesUrl = `${contentUrl}/${repoBranch}/src/localization/locales`; + hashesUrl = `${contentUrl}/${repoBranch}/src/localization/hashes.json`; + warnedMissingKeys = /* @__PURE__ */ new Set(); + _langOverride = "auto"; + constructor() { + this.lang = this.getLang(); + this.locale = {}; + } + async init() { + const [langOverride, phrases] = await Promise.all([votStorage.get("localeLangOverride", "auto"), votStorage.get("localePhrases", "")]); + this._langOverride = langOverride; + this.lang = this.getLang(); + this.setLocaleFromJsonString(phrases); + return this; + } + get langOverride() { + return this._langOverride; + } + getLang() { + return this.langOverride !== "auto" ? this.langOverride : lang; + } + getAvailableLangs() { + return [...availableLocales]; + } + async reset() { + await Promise.all(LOCALE_STORAGE_KEYS.map((key) => votStorage.delete(key))); + return this; + } + buildUrl(baseUrl, path = "", force = false) { + return `${baseUrl}${path}${force ? `?timestamp=${getTimestamp()}` : ""}`; + } + async changeLang(newLang) { + if (this.langOverride === newLang) return false; + await votStorage.set("localeLangOverride", newLang); + this._langOverride = newLang; + this.lang = this.getLang(); + await this.update(true); + return true; + } + async checkUpdates(force = false) { + debug.log("Check locale updates..."); + try { + const runtimeLocaleVersion = getRuntimeLocaleVersion(); + if (!force) { + const storedLocaleVersion = await votStorage.get("localeVersion", ""); + if (runtimeLocaleVersion !== "unknown" && storedLocaleVersion === runtimeLocaleVersion) return false; + } + const res = await GM_fetch(this.buildUrl(this.hashesUrl, "", force)); + if (!res.ok) throw res.status; + const hashes = await res.json(); + if (!hashes || typeof hashes !== "object") throw new Error("Invalid locale hashes payload"); + const nextHash = hashes[this.lang]; + if (typeof nextHash !== "string" || !nextHash) return false; + return await votStorage.get("localeHash", "") === nextHash ? false : nextHash; + } catch (err) { + console.error("[VOT] [localizationProvider] Failed to get locales hash:", err); + return null; + } + } + async update(force = false) { + const runtimeLocaleVersion = getRuntimeLocaleVersion(); + const storedLocaleVersion = await votStorage.get("localeVersion", ""); + const hash = await this.checkUpdates(force); + if (hash === null) return this; + if (!hash) { + if (storedLocaleVersion !== runtimeLocaleVersion) await votStorage.set("localeVersion", runtimeLocaleVersion); + return this; + } + const timestamp = getTimestamp(); + debug.log("Updating locale..."); + try { + const res = await GM_fetch(this.buildUrl(this.localesUrl, `/${this.lang}.json`, force)); + if (!res.ok) throw res.status; + const text = await res.text(); + this.setLocaleFromJsonString(text); + await Promise.all([ + votStorage.set("localePhrases", text), + votStorage.set("localeHash", hash), + votStorage.set("localeLang", this.lang), + votStorage.set("localeVersion", runtimeLocaleVersion), + votStorage.set("localeUpdatedAt", timestamp) + ]); + } catch (err) { + console.error("[VOT] [localizationProvider] Failed to get locale:", err); + this.setLocaleFromJsonString(await votStorage.get("localePhrases", "")); + } + return this; + } + setLocaleFromJsonString(json) { + const trimmed = json.trim(); + if (!trimmed) { + this.locale = {}; + this.warnedMissingKeys.clear(); + return this; + } + try { + const locale = JSON.parse(trimmed); + if (!locale || typeof locale !== "object" || Array.isArray(locale)) throw new Error("Locale payload should be a JSON object"); + this.locale = toFlatObj(locale); + } catch (err) { + console.error("[VOT] [localizationProvider]", err); + this.locale = {}; + } + this.warnedMissingKeys.clear(); + return this; + } + getFromLocale(locale, key, source = "locale") { + return locale[key] ?? this.warnMissingKey(locale, key, source); + } + warnMissingKey(locale, key, source) { + const warningKey = `${source}:${key}`; + if (this.warnedMissingKeys.has(warningKey)) return; + this.warnedMissingKeys.add(warningKey); + console.warn("[VOT] [localizationProvider] locale", locale, "doesn't contain key", key); + } + getDefault(key) { + return this.getFromLocale(this.defaultLocale, key, "default") ?? key; + } + get(key) { + return this.getFromLocale(this.locale, key) ?? this.getDefault(key); + } + getLangLabel(lang) { + const key = `langs.${lang}`; + if (key in this.defaultLocale) { + const label = this.get(key); + if (label) return label; + } + return lang.toUpperCase(); + } + }; + var localizationProvider = new LocalizationProvider(); + /** + * In the userscript build, SystemJS wrapping allowed a top-level await. + * For the extension build we bootstrap through loader scripts and keep the + * runtime initialization explicit, so avoid top-level await and expose a lazy + * ready Promise instead. + */ + var localizationProviderReadyPromise = null; + function ensureLocalizationProviderReady() { + localizationProviderReadyPromise ??= localizationProvider.init(); + return localizationProviderReadyPromise; + } + //#endregion + //#region src/utils/iframeConnector.ts + /** + * Runtime frame detection helper. + * + * Audio download no longer relies on service iframes or postMessage bridges. + * We keep only the minimal utility used by bootstrap policy. + */ + var isIframe = () => globalThis.self !== globalThis.top; + //#endregion + //#region src/bootstrap/runtimeActivation.ts + var runtimeActivated = false; + var runtimeActivationPromise = null; + async function ensureRuntimeActivated(reason, logBootstrap) { + if (runtimeActivated) return; + if (runtimeActivationPromise !== null) { + await runtimeActivationPromise; + return; + } + runtimeActivationPromise = (async () => { + logBootstrap("Activating runtime", { reason }); + if (globalThis.location.origin === "https://rust-server-531j.onrender.com") { + await initAuth(); + runtimeActivated = true; + return; + } + await ensureLocalizationProviderReady(); + if (!isIframe()) await localizationProvider.update(); + debug.log(`Selected menu language: ${localizationProvider.lang}`); + runtimeActivated = true; + })(); + try { + await runtimeActivationPromise; + } finally { + runtimeActivationPromise = null; + } + } + //#endregion + //#region src/bootstrap/videoObserverBinding.ts + var boundObservers = /* @__PURE__ */ new WeakSet(); + function bindObserverListeners(options) { + const { videoObserver, videosWrappers, ensureRuntimeActivated, getServicesCached, findContainer, createVideoHandler } = options; + if (boundObservers.has(videoObserver)) return; + boundObservers.add(videoObserver); + const initializingVideos = /* @__PURE__ */ new WeakSet(); + const containerOwners = /* @__PURE__ */ new WeakMap(); + const videoContainers = /* @__PURE__ */ new WeakMap(); + const pendingVideoByContainer = /* @__PURE__ */ new WeakMap(); + const clearContainerOwner = (video) => { + const container = videoContainers.get(video); + if (container && containerOwners.get(container) === video) containerOwners.delete(container); + videoContainers.delete(video); + return container ?? void 0; + }; + const clearPendingVideo = (container) => { + if (!container) return; + pendingVideoByContainer.delete(container); + }; + const releaseVideoHandler = async (video, reason) => { + const videoHandler = videosWrappers.get(video); + if (!videoHandler) return; + try { + await videoHandler.release(); + } catch (error) { + console.error(`[VOT] Failed to release videoHandler (${reason})`, error); + } finally { + videosWrappers.delete(video); + } + }; + const getMatchedSiteAndContainer = (video) => { + for (const candidate of getServicesCached()) { + const container = findContainer(candidate, video); + if (container) return { + site: candidate, + container + }; + } + return null; + }; + const withRuntimeSiteUrl = (site) => { + const host = String(site.host); + return host === "peertube" || host === "directlink" ? { + ...site, + url: globalThis.location.origin + } : site; + }; + const promotePendingVideo = async (container) => { + if (!container) return; + const pendingVideo = pendingVideoByContainer.get(container); + if (!pendingVideo) return; + pendingVideoByContainer.delete(container); + if (!pendingVideo.isConnected || videosWrappers.has(pendingVideo) || initializingVideos.has(pendingVideo)) return; + await handleVideoAdded(pendingVideo); + }; + const handleVideoAdded = async (video) => { + if (videosWrappers.has(video) || initializingVideos.has(video)) return; + initializingVideos.add(video); + try { + try { + await ensureRuntimeActivated("video-detected"); + } catch (err) { + console.error("[VOT] Failed to activate runtime", err); + return; + } + const match = getMatchedSiteAndContainer(video); + if (!match) return; + const { site, container } = match; + const activeVideoForContainer = containerOwners.get(container); + if (activeVideoForContainer && activeVideoForContainer !== video) { + if (activeVideoForContainer.isConnected) { + pendingVideoByContainer.set(container, video); + return; + } + await releaseVideoHandler(activeVideoForContainer, "stale container"); + clearContainerOwner(activeVideoForContainer); + } + const videoHandler = createVideoHandler(video, container, withRuntimeSiteUrl(site)); + videosWrappers.set(video, videoHandler); + videoContainers.set(video, container); + containerOwners.set(container, video); + try { + await videoHandler.init(); + if (videosWrappers.get(video) !== videoHandler) return; + try { + await videoHandler.setCanPlay(); + } catch (err) { + console.error("[VOT] Failed to get video data", err); + } + } catch (err) { + if (videosWrappers.get(video) === videoHandler) { + await releaseVideoHandler(video, "init failed"); + const container = clearContainerOwner(video); + clearPendingVideo(container); + await promotePendingVideo(container); + } + console.error("[VOT] Failed to initialize videoHandler", err); + } + } finally { + initializingVideos.delete(video); + } + }; + videoObserver.onVideoAdded.addListener(handleVideoAdded); + videoObserver.onVideoRemoved.addListener(async (video) => { + const container = clearContainerOwner(video); + await releaseVideoHandler(video, "video removed"); + initializingVideos.delete(video); + if (container && pendingVideoByContainer.get(container) === video) clearPendingVideo(container); + await promotePendingVideo(container); + }); + } + //#endregion + //#region src/core/bootstrapPolicy.ts + function shouldSkipIframeBootstrap(input) { + if (!input.isIframe) return false; + return input.href === "about:blank" || input.href.startsWith("about:srcdoc") || input.origin === "null"; + } + function resolveBootstrapMode(input) { + if (shouldSkipIframeBootstrap(input)) return "skip"; + if (!input.isIframe && input.origin === input.authOrigin) return "auth-eager"; + return "lazy"; + } + //#endregion + //#region src/utils/dom.ts + function getComposableParent(node) { + if (!node) return null; + if (typeof ShadowRoot !== "undefined" && node instanceof ShadowRoot) return node.host; + return node.parentNode ?? null; + } + function getDeepActiveElement(root = document) { + let activeElement = root.activeElement; + while (activeElement instanceof HTMLElement && activeElement.shadowRoot) { + const nestedActiveElement = activeElement.shadowRoot.activeElement; + if (!nestedActiveElement) break; + activeElement = nestedActiveElement; + } + return activeElement; + } + /** + * Checks whether `target` is a descendant of `container` in the composed tree + * (crossing ShadowRoot boundaries via hosts). + */ + function containsCrossShadow(container, target) { + let node = target; + while (node) { + if (node === container) return true; + node = getComposableParent(node); + } + return false; + } + function closestCrossShadow(element, selector) { + if (!element || !selector) return null; + return walkCrossShadow(element, selector, element instanceof Document ? null : element); + } + function findMatchingDocumentElement(current, selector, origin) { + if (!origin) return current.querySelector(selector); + const matches = current.querySelectorAll(selector); + for (const match of matches) if (containsCrossShadow(match, origin)) return match; + return null; + } + function getNextCrossShadowTarget(current) { + const root = current.getRootNode(); + if (root instanceof ShadowRoot) return root.host; + if (root instanceof Document) return root; + if (root !== current) { + const parent = getComposableParent(root); + if (parent && parent !== current && parent instanceof Element) return parent; + } + return null; + } + function walkCrossShadow(current, selector, origin) { + if (!current) return null; + if (current instanceof Document) return findMatchingDocumentElement(current, selector, origin); + const closest = current.closest(selector); + if (closest) return closest; + return walkCrossShadow(getNextCrossShadowTarget(current), selector, origin); + } + //#endregion + //#region src/core/containerResolution.ts + function findConnectedContainerBySelector(video, selector) { + if (!selector) return null; + const matched = closestCrossShadow(video, selector); + if (matched instanceof HTMLElement && matched.isConnected && containsCrossShadow(matched, video)) return matched; + return null; + } + //#endregion + //#region src/core/overlayMountTargets.ts + function resolveOverlayBaseContainer(container, site) { + return site.host === "youtube" && site.additionalData !== "mobile" ? container.parentElement ?? container : container; + } + function resolveOverlayMountTargets(input) { + const base = resolveOverlayBaseContainer(input.container, input.site); + const root = input.fullscreenRoot ?? base; + return { + base, + root, + portalContainer: base, + subtitlesMountContainer: root + }; + } + //#endregion + //#region src/core/eventImpl.ts + /** + * Tiny, dependency-free event emitter. + * + * Notes: + * - Uses generics so emitted arguments stay strongly typed. + * - Adding the same listener twice is a no-op (idempotent). + * - Listener errors are isolated so one bad subscriber doesn't break the emitter. + */ + var EventImpl = class { + listeners = /* @__PURE__ */ new Set(); + get size() { + return this.listeners.size; + } + addListener(handler) { + this.listeners.add(handler); + return this; + } + removeListener(handler) { + this.listeners.delete(handler); + return this; + } + dispatch(...args) { + for (const handler of this.listeners) try { + handler(...args); + } catch (exception) { + console.error("[VOT]", exception); + } + } + async dispatchAsync(...args) { + const pending = []; + for (const handler of this.listeners) try { + const result = handler(...args); + if (result && typeof result.then === "function") pending.push(Promise.resolve(result)); + } catch (exception) { + console.error("[VOT]", exception); + } + if (!pending.length) return; + const settled = await Promise.allSettled(pending); + for (const item of settled) if (item.status === "rejected") console.error("[VOT]", item.reason); + } + clear() { + this.listeners.clear(); + } + }; + //#endregion + //#region src/audioDownloader/strategies/fileId.ts + function makeFileId(downloadType, itag, fileSize, minChunkSize) { + return JSON.stringify({ + downloadType, + itag, + minChunkSize, + fileSize + }); + } + //#endregion + //#region src/audioDownloader/ytAudio/src/internal/format-selection.ts + function normalizeMimeType(mimeType) { + return mimeType?.toLowerCase() ?? ""; + } + function isAudioOnlyMimeType(mimeType) { + const normalizedMimeType = normalizeMimeType(mimeType); + return normalizedMimeType.includes("audio/") && !normalizedMimeType.includes("video/"); + } + function isMp4aAdaptiveAudioMimeType(mimeType) { + const normalizedMimeType = normalizeMimeType(mimeType); + return normalizedMimeType.includes("audio/mp4") && normalizedMimeType.includes("mp4a."); + } + function isOpusAdaptiveAudioMimeType(mimeType) { + const normalizedMimeType = normalizeMimeType(mimeType); + return normalizedMimeType.includes("audio/webm") && normalizedMimeType.includes("opus"); + } + function extractAudioCodecFromMimeType(mimeType) { + if (!mimeType) return "mp4a.40.2"; + const codecsMatch = /codecs="([^"]+)"/i.exec(mimeType); + if (!codecsMatch?.[1]) return "mp4a.40.2"; + const codecs = codecsMatch[1].split(",").map((value) => value.trim()); + return codecs.find((value) => value.toLowerCase().startsWith("mp4a.")) ?? codecs[0] ?? "mp4a.40.2"; + } + function pickByBitrate(formats, direction) { + let selected = null; + let selectedBitrate = direction === "max" ? -Infinity : Infinity; + for (const format of formats) { + const bitrate = format.bitrate ?? 0; + if (direction === "max" && bitrate > selectedBitrate || direction === "min" && bitrate < selectedBitrate) { + selected = format; + selectedBitrate = bitrate; + } + } + return selected; + } + function pickAdaptiveAudioFormat(formats, quality) { + const audioFormats = formats.filter((format) => isAudioOnlyMimeType(format.mimeType)); + if (!audioFormats.length) throw new Error("No adaptive audio formats were found in player response"); + const pickDirection = quality === "bestefficiency" ? "min" : "max"; + const candidateGroups = quality === "bestefficiency" ? [audioFormats.filter((format) => isOpusAdaptiveAudioMimeType(format.mimeType)), audioFormats] : [ + audioFormats.filter((format) => isMp4aAdaptiveAudioMimeType(format.mimeType)), + audioFormats.filter((format) => isOpusAdaptiveAudioMimeType(format.mimeType)), + audioFormats + ]; + for (const candidates of candidateGroups) { + if (!candidates.length) continue; + const selected = pickByBitrate(candidates, pickDirection); + if (selected) return selected; + } + throw new Error("No adaptive audio formats were found in player response"); + } + //#endregion + //#region src/audioDownloader/ytAudio/src/AudioDownloader.ts + var VIDEO_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/; + var YT_BASE = "https://www.youtube.com"; + var ANDROID_VR_CLIENT_VERSION = "1.60.19"; + var CLIENTS = ["ANDROID_VR"]; + var DEFAULT_HEADERS = { + accept: "*/*", + origin: YT_BASE, + referer: `${YT_BASE}/` + }; + var RANGE_FALLBACK_CHUNK_SIZE = 256 * 1024; + function withSignal(signal) { + return signal ? { signal } : {}; + } + function resolveInnertubeClient(requestedClient) { + if (requestedClient !== void 0 && requestedClient !== "ANDROID_VR") throw new Error(`Unsupported Innertube client: ${requestedClient}`); + return { + clientName: "ANDROID_VR", + clientVersion: ANDROID_VR_CLIENT_VERSION, + hl: "en", + gl: "US", + androidSdkVersion: 31, + osName: "Android", + osVersion: "12", + platform: "MOBILE" + }; + } + function extractVideoId(input) { + const value = input.trim(); + if (VIDEO_ID_PATTERN.test(value)) return value; + let url; + try { + url = new URL(value); + } catch { + throw new Error(`Cannot extract YouTube video id from: ${input}`); + } + const hostname = url.hostname.toLowerCase(); + if (hostname === "youtu.be" || hostname.endsWith(".youtu.be")) return getValidatedVideoId(url.pathname.split("/").find(Boolean), input); + const searchId = url.searchParams.get("v"); + if (searchId && VIDEO_ID_PATTERN.test(searchId)) return searchId; + const pathId = getVideoIdFromPathSegments(url.pathname.split("/").filter(Boolean)); + if (pathId) return pathId; + throw new Error(`Cannot extract YouTube video id from: ${input}`); + } + function getValidatedVideoId(id, input) { + if (id && VIDEO_ID_PATTERN.test(id)) return id; + throw new Error(`Cannot extract YouTube video id from: ${input}`); + } + function getVideoIdFromPathSegments(pathSegments) { + for (const marker of ["shorts", "embed"]) { + const markerIndex = pathSegments.indexOf(marker); + if (markerIndex === -1) continue; + const id = pathSegments[markerIndex + 1]; + if (id && VIDEO_ID_PATTERN.test(id)) return id; + } + return null; + } + function decodeEscapedJsonString(input) { + return input.replaceAll("\\u0026", "&").replaceAll("\\/", "/"); + } + function getRequiredVideoId(request) { + const source = request.videoId ?? request.videoUrl; + if (!source) throw new Error("Either videoId or videoUrl is required"); + return extractVideoId(source); + } + function matchFirst(source, patterns) { + for (const pattern of patterns) { + const matched = pattern.exec(source)?.[1]; + if (matched) return matched; + } + } + async function readResponseBytes(response) { + return new Uint8Array(await response.arrayBuffer()); + } + function makeCPN(length = 16) { + const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"; + let output = ""; + if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") { + const bytes = new Uint8Array(length); + crypto.getRandomValues(bytes); + for (const byte of bytes) output += alphabet[byte % 64] ?? "a"; + return output; + } + for (let i = 0; i < length; i++) output += alphabet[Math.floor(Math.random() * 64)] ?? "a"; + return output; + } + function parsePositiveInteger(value) { + if (!value) return null; + const parsed = Number.parseInt(value, 10); + if (!Number.isFinite(parsed) || parsed <= 0) return null; + return parsed; + } + function parseContentLengthFromContentRange(contentRange) { + if (!contentRange) return null; + return parsePositiveInteger(/\/(\d+)\s*$/i.exec(contentRange)?.[1]); + } + function parseContentRangeHeader(contentRange) { + if (!contentRange) return null; + const matched = /^bytes\s+(\d+)-(\d+)\/(?:\d+|\*)$/i.exec(contentRange.trim()); + if (!matched) return null; + const start = Number.parseInt(matched[1] ?? "", 10); + const end = Number.parseInt(matched[2] ?? "", 10); + if (!Number.isFinite(start) || !Number.isFinite(end) || start < 0 || end < start) return null; + return { + start, + end + }; + } + function getExpectedRangeLength(start, end) { + return end - start + 1; + } + function isValidRangeChunkResponse(response, bytes, start, end) { + const expectedLength = getExpectedRangeLength(start, end); + if (expectedLength <= 0) return false; + if (bytes.byteLength <= 0 || bytes.byteLength > expectedLength) return false; + const contentRange = parseContentRangeHeader(response.headers.get("content-range")); + if (contentRange) return contentRange.start === start && contentRange.end === start + bytes.byteLength - 1; + if (response.status === 206) return bytes.byteLength === expectedLength; + if (response.status === 200) return start === 0 && bytes.byteLength === expectedLength; + return false; + } + function describeRangeChunkResponse(response, bytes) { + const contentRange = response.headers.get("content-range") ?? "none"; + const contentLength = response.headers.get("content-length") ?? "none"; + return `status=${response.status}; bytes=${bytes.byteLength}; content-range=${contentRange}; content-length=${contentLength}`; + } + function getAudioMimeType(mimeType) { + const normalizedMimeType = mimeType?.toLowerCase() ?? ""; + if (normalizedMimeType.includes("audio/webm")) return "audio/webm"; + if (normalizedMimeType.includes("audio/mp4")) return "audio/mp4"; + return "audio/aac"; + } + function buildClientAttemptOrder(requestedClient) { + const ordered = requestedClient ? [requestedClient, ...CLIENTS] : [...CLIENTS]; + const seen = /* @__PURE__ */ new Set(); + return ordered.filter((client) => { + if (seen.has(client)) return false; + seen.add(client); + return true; + }); + } + var AudioDownloader$1 = class { + fetchFn; + constructor(options = {}) { + this.fetchFn = options.fetchImplementation ?? fetch; + } + async fetchRangeChunk(streamUrl, start, end, signal) { + const rangeHeader = `bytes=${start}-${end}`; + const response = await this.fetchFn(streamUrl, { + headers: { + ...DEFAULT_HEADERS, + range: rangeHeader + }, + ...withSignal(signal) + }); + if (!response.ok) throw new Error(`Failed to download stream chunk: ${response.status}`); + const bytes = await readResponseBytes(response); + if (!isValidRangeChunkResponse(response, bytes, start, end)) throw new Error(`Received unexpected stream chunk payload: ${describeRangeChunkResponse(response, bytes)}`); + return bytes; + } + async downloadStreamByRanges(streamUrl, contentLengthHint, signal) { + const fileSize = await this.resolveStreamContentLength(streamUrl, contentLengthHint, signal, true); + const merged = new Uint8Array(fileSize); + let offset = 0; + for (let start = 0; start < fileSize; start += RANGE_FALLBACK_CHUNK_SIZE) { + const end = Math.min(fileSize - 1, start + RANGE_FALLBACK_CHUNK_SIZE - 1); + const chunk = await this.fetchRangeChunk(streamUrl, start, end, signal); + if (offset + chunk.byteLength > merged.byteLength) throw new Error("Downloaded stream chunk exceeds probed stream content length"); + merged.set(chunk, offset); + offset += chunk.byteLength; + } + if (offset === merged.byteLength) return merged; + return merged.slice(0, offset); + } + async downloadAudioToChunkStream(request, options) { + if (options.chunkSize <= 0) throw new RangeError("Audio downloader. ytAudio. chunkSize must be > 0"); + return this.withResolvedPlayableAudioFormat(request, request.audioQuality ?? "best", "Chunk mode requires an adaptive audio stream format", "Unable to resolve streamable format for chunk mode", async ({ resolved, signal }) => { + const fileSize = await this.resolveStreamContentLength(resolved.streamUrl, resolved.chosenFormat.contentLength, signal, true); + const mediaPartsLength = Math.max(1, Math.ceil(fileSize / options.chunkSize)); + return { + videoId: resolved.videoId, + fileSize, + itag: resolved.chosenFormat.itag ?? 0, + mediaPartsLength, + getMediaBuffers: async function* () { + for (let index = 0; index < mediaPartsLength; index++) { + const start = index * options.chunkSize; + const end = Math.min(fileSize - 1, start + options.chunkSize - 1); + yield await this.fetchRangeChunk(resolved.streamUrl, start, end, signal); + } + }.bind(this) + }; + }); + } + async downloadAudioToUint8Array(request) { + const chunks = []; + let total = 0; + const streamResult = await this.extractAndWriteAudio(request, { async write(chunk) { + chunks.push(chunk); + total += chunk.byteLength; + } }); + const bytes = new Uint8Array(total); + let offset = 0; + for (const chunk of chunks) { + bytes.set(chunk, offset); + offset += chunk.byteLength; + } + return { + ...streamResult, + bytes + }; + } + async extractAndWriteAudio(request, sink) { + return this.withResolvedPlayableAudioFormat(request, request.audioQuality ?? "bestefficiency", "Selected stream is not audio-only", "Unable to download playable stream format", async ({ resolved, signal }) => { + const streamBytes = await this.downloadStreamByRanges(resolved.streamUrl, resolved.chosenFormat.contentLength, signal); + const hints = this.getExtractionHints(resolved.chosenFormat); + await sink.write(streamBytes); + return { + videoId: resolved.videoId, + bytesWritten: streamBytes.byteLength, + mimeType: getAudioMimeType(resolved.chosenFormat.mimeType), + codec: hints.codec, + sampleRate: hints.sampleRate, + channels: hints.channels + }; + }); + } + async withResolvedPlayableAudioFormat(request, quality, audioOnlyErrorMessage, failurePrefix, onResolved) { + const videoId = getRequiredVideoId(request); + const { signal } = request; + const watchContext = await this.fetchWatchContext(videoId, signal); + const clientAttempts = buildClientAttemptOrder(request.client); + const attemptErrors = []; + for (const client of clientAttempts) try { + const resolved = await this.resolvePlayableFormatForClient({ + videoId, + watchContext, + client, + quality, + signal + }); + if (!isAudioOnlyMimeType(resolved.chosenFormat.mimeType)) throw new Error(audioOnlyErrorMessage); + return await onResolved({ + resolved, + signal + }); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + attemptErrors.push(`${client}: ${message}`); + } + throw new Error(`${failurePrefix}. Attempts: ${attemptErrors.join(" | ")}`); + } + async resolvePlayableFormatForClient({ videoId, watchContext, client, quality, signal }) { + const directAdaptiveFormats = ((await this.fetchPlayerResponse(videoId, watchContext, client, signal)).streamingData?.adaptiveFormats ?? []).filter((format) => Boolean(format.url)); + if (!directAdaptiveFormats.length) throw new Error("Player response did not contain direct adaptive audio stream URLs"); + const chosenFormat = pickAdaptiveAudioFormat(directAdaptiveFormats, quality); + return { + videoId, + chosenFormat, + streamUrl: this.resolveFormatUrl(chosenFormat) + }; + } + async resolveStreamContentLength(streamUrl, contentLengthHint, signal, forceProbe = false) { + const hintedLength = parsePositiveInteger(contentLengthHint); + if (hintedLength !== null && !forceProbe) return hintedLength; + let probeResponse; + try { + probeResponse = await this.fetchFn(streamUrl, { + headers: { + ...DEFAULT_HEADERS, + range: "bytes=0-0" + }, + ...withSignal(signal) + }); + } catch (error) { + if (hintedLength !== null) return hintedLength; + const message = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to probe stream content length: ${message}`); + } + if (!probeResponse.ok) { + if (hintedLength !== null) return hintedLength; + throw new Error(`Failed to probe stream content length: ${probeResponse.status}`); + } + const contentRangeLength = parseContentLengthFromContentRange(probeResponse.headers.get("content-range")); + const storedLength = parsePositiveInteger(probeResponse.headers.get("x-goog-stored-content-length")); + const contentLength = parsePositiveInteger(probeResponse.headers.get("content-length")); + if (typeof probeResponse.body?.cancel === "function") try { + await probeResponse.body.cancel(); + } catch {} + return contentRangeLength ?? storedLength ?? hintedLength ?? contentLength ?? (() => { + throw new Error("Failed to resolve stream content length"); + })(); + } + getExtractionHints(format) { + const codec = extractAudioCodecFromMimeType(format.mimeType); + const sampleRate = Number.parseInt(format.audioSampleRate ?? "", 10); + return { + codec, + sampleRate: Number.isFinite(sampleRate) && sampleRate > 0 ? sampleRate : 44100, + channels: format.audioChannels && format.audioChannels > 0 ? format.audioChannels : 2 + }; + } + resolveFormatUrl(format) { + if (!format.url) throw new Error("Selected format does not contain a direct stream URL"); + const streamUrl = new URL(format.url); + streamUrl.searchParams.set("cpn", makeCPN()); + return streamUrl.toString(); + } + async fetchWatchContext(videoId, signal) { + const watchUrl = `${YT_BASE}/watch?v=${encodeURIComponent(videoId)}&hl=en`; + const response = await this.fetchFn(watchUrl, { + headers: DEFAULT_HEADERS, + ...withSignal(signal) + }); + if (!response.ok) throw new Error(`Failed to load watch page: ${response.status}`); + const html = await response.text(); + const apiKey = matchFirst(html, [/"INNERTUBE_API_KEY":"([^"]+)"/, /["']INNERTUBE_API_KEY["']\s*:\s*"([^"]+)"/]); + const clientVersion = matchFirst(html, [/"INNERTUBE_CLIENT_VERSION":"([^"]+)"/, /["']INNERTUBE_CLIENT_VERSION["']\s*:\s*"([^"]+)"/]); + const stsRaw = matchFirst(html, [/"STS":(\d+)/, /["']STS["']\s*:\s*(\d+)/]); + const visitorData = matchFirst(html, [ + /"VISITOR_DATA":"([^"]+)"/, + /"visitorData":"([^"]+)"/, + /["'](?:VISITOR_DATA|visitorData)["']\s*:\s*"([^"]+)"/ + ]); + if (!apiKey || !clientVersion) throw new Error("Failed to extract required player context from watch page"); + const signatureTimestamp = stsRaw ? Number.parseInt(stsRaw, 10) : void 0; + const context = { + apiKey, + clientVersion + }; + if (typeof signatureTimestamp === "number" && Number.isFinite(signatureTimestamp)) context.signatureTimestamp = signatureTimestamp; + if (visitorData) context.visitorData = decodeEscapedJsonString(visitorData); + return context; + } + async fetchPlayerResponse(videoId, watchContext, requestedClient, signal) { + const client = resolveInnertubeClient(requestedClient); + if (watchContext.visitorData) client.visitorData = watchContext.visitorData; + const body = { + context: { client }, + videoId, + contentCheckOk: true, + racyCheckOk: true + }; + if (watchContext.signatureTimestamp) body.playbackContext = { contentPlaybackContext: { signatureTimestamp: watchContext.signatureTimestamp } }; + const endpoint = `${YT_BASE}/youtubei/v1/player?key=${encodeURIComponent(watchContext.apiKey)}`; + const response = await this.fetchFn(endpoint, { + method: "POST", + headers: { + ...DEFAULT_HEADERS, + "content-type": "application/json", + ...watchContext.visitorData ? { "x-goog-visitor-id": watchContext.visitorData } : {} + }, + body: JSON.stringify(body), + ...withSignal(signal) + }); + if (!response.ok) throw new Error(`Player API request failed with status ${response.status}`); + const json = await response.json(); + const hasFormats = Boolean(json.streamingData?.formats?.length); + const hasAdaptiveFormats = Boolean(json.streamingData?.adaptiveFormats?.length); + if (!hasFormats && !hasAdaptiveFormats) throw new Error("Player response did not contain streaming formats"); + return json; + } + }; + //#endregion + //#region src/audioDownloader/ytAudio/strategy.ts + var DEFAULT_YT_AUDIO_QUALITY = "bestefficiency"; + var DEFAULT_FETCH_TIMEOUT_MS = 3e4; + function assertValidChunkSize(chunkSize) { + if (chunkSize <= 0) throw new RangeError("Audio downloader. ytAudio. chunkSize must be > 0"); + } + function createYtAudioFetch({ signal, timeoutMs }) { + return async (input, init = {}) => await GM_fetch(input, { + ...init, + signal: init.signal ?? signal, + forceGmXhr: true, + timeout: timeoutMs + }); + } + async function getAudioFromYtAudio({ videoId, signal }, deps = {}) { + const chunkSize = deps.chunkSize ?? config_default$1.minChunkSize; + assertValidChunkSize(chunkSize); + const fetchImplementation = createYtAudioFetch({ + signal, + timeoutMs: deps.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS + }); + const downloader = deps.createDownloader?.(fetchImplementation) ?? new AudioDownloader$1({ fetchImplementation }); + try { + const streamResult = await downloader.downloadAudioToChunkStream({ + videoId, + audioQuality: DEFAULT_YT_AUDIO_QUALITY, + signal + }, { chunkSize }); + return { + fileId: makeFileId(AudioDownloadType.WEB_API_STEAL_SIG_AND_N, streamResult.itag, String(streamResult.fileSize), chunkSize), + mediaPartsLength: streamResult.mediaPartsLength, + getMediaBuffers: streamResult.getMediaBuffers + }; + } catch (error) { + console.warn("[VOT] ytAudio streaming mode failed, falling back to buffered mode", error); + } + const bytes = (await downloader.downloadAudioToUint8Array({ + videoId, + audioQuality: DEFAULT_YT_AUDIO_QUALITY, + signal + })).bytes; + if (!bytes || bytes.byteLength === 0) throw new Error("Audio downloader. ytAudio. Empty audio"); + const mediaPartsLength = Math.max(1, Math.ceil(bytes.byteLength / chunkSize)); + return { + fileId: makeFileId(AudioDownloadType.WEB_API_STEAL_SIG_AND_N, 0, String(bytes.byteLength), chunkSize), + mediaPartsLength, + async *getMediaBuffers() { + for (let start = 0; start < bytes.byteLength; start += chunkSize) { + const end = Math.min(start + chunkSize, bytes.byteLength); + yield bytes.subarray(start, end); + } + } + }; + } + //#endregion + //#region src/audioDownloader/strategies/index.ts + var YT_AUDIO_STRATEGY = "ytAudio"; + var strategies = { [YT_AUDIO_STRATEGY]: getAudioFromYtAudio }; + //#endregion + //#region src/audioDownloader/index.ts + function assertValidMediaPartsLength(mediaPartsLength) { + if (!Number.isInteger(mediaPartsLength) || mediaPartsLength < 1) throw new Error("Audio downloader. Invalid media parts length"); + } + function assertHasAudioChunk(chunk) { + if (!chunk || chunk.byteLength === 0) throw new Error("Audio downloader. Empty audio"); + return chunk; + } + async function handleCommonAudioDownloadRequest({ audioDownloader, translationId, videoId, signal }) { + const audioData = await strategies[audioDownloader.strategy]({ + videoId, + signal + }); + if (!audioData) throw new Error("Audio downloader. Can not get audio data"); + debug.log("Audio downloader. Url found", { audioDownloadType: audioDownloader.strategy }); + const { getMediaBuffers, mediaPartsLength, fileId } = audioData; + assertValidMediaPartsLength(mediaPartsLength); + if (mediaPartsLength < 2) { + const { value } = await getMediaBuffers().next(); + const singleChunk = assertHasAudioChunk(value); + await audioDownloader.onDownloadedAudio.dispatchAsync(translationId, { + videoId, + fileId, + audioData: singleChunk + }); + return; + } + let index = 0; + for await (const audioChunk of getMediaBuffers()) { + const chunk = assertHasAudioChunk(audioChunk); + await audioDownloader.onDownloadedPartialAudio.dispatchAsync(translationId, { + videoId, + fileId, + audioData: chunk, + version: 1, + index, + amount: mediaPartsLength + }); + index++; + } + if (index !== mediaPartsLength) throw new Error(`Audio downloader. Expected ${mediaPartsLength} chunks, got ${index}`); + } + var AudioDownloader = class { + onDownloadedAudio = new EventImpl(); + onDownloadedPartialAudio = new EventImpl(); + onDownloadAudioError = new EventImpl(); + strategy; + constructor(strategy = YT_AUDIO_STRATEGY) { + this.strategy = strategy; + debug.log("Audio downloader created", { strategy }); + } + async runAudioDownload(videoId, translationId, signal) { + try { + await handleCommonAudioDownloadRequest({ + audioDownloader: this, + translationId, + videoId, + signal + }); + debug.log("Audio downloader. Audio download finished", { videoId }); + } catch (err) { + debug.error("Audio downloader. Failed to download audio", { + videoId, + error: err instanceof Error ? err.message : String(err) + }); + this.onDownloadAudioError.dispatch(videoId); + } + } + addEventListener(type, listener) { + switch (type) { + case "downloadedAudio": + this.onDownloadedAudio.addListener(listener); + break; + case "downloadedPartialAudio": + this.onDownloadedPartialAudio.addListener(listener); + break; + case "downloadAudioError": + this.onDownloadAudioError.addListener(listener); + break; + } + return this; + } + removeEventListener(type, listener) { + switch (type) { + case "downloadedAudio": + this.onDownloadedAudio.removeListener(listener); + break; + case "downloadedPartialAudio": + this.onDownloadedPartialAudio.removeListener(listener); + break; + case "downloadAudioError": + this.onDownloadAudioError.removeListener(listener); + break; + } + return this; + } + }; + //#endregion + //#region src/utils/timeFormatting.ts + var MAX_SECS_FRACTION = .66; + function formatTranslationEta(secs, getMessage) { + let minutes = Math.floor(secs / 60); + if (Math.floor(secs % 60) / 60 >= MAX_SECS_FRACTION) minutes += 1; + if (minutes >= 60) return getMessage("translationTakeMoreThanHour"); + if (minutes <= 1) return getMessage("translationTakeAboutMinute"); + const minutesStr = String(minutes); + if (minutes !== 11 && minutes % 10 === 1) return getMessage("translationTakeApproximatelyMinute2").replace("{0}", minutesStr); + if (![ + 12, + 13, + 14 + ].includes(minutes) && [ + 2, + 3, + 4 + ].includes(minutes % 10)) return getMessage("translationTakeApproximatelyMinute").replace("{0}", minutesStr); + return getMessage("translationTakeApproximatelyMinutes").replace("{0}", minutesStr); + } + //#endregion + //#region src/utils/VOTLocalizedError.ts + var VOTLocalizedError = class extends Error { + name = "VOTLocalizedError"; + /** Original (non-localized) message key. */ + unlocalizedMessage; + /** Resolved localized message. */ + localizedMessage; + constructor(message) { + super(localizationProvider.getDefault(message)); + this.unlocalizedMessage = message; + this.localizedMessage = localizationProvider.get(message); + } + }; + //#endregion + //#region src/videoHandler/modules/translationShared.ts + function normalizeTranslationHelp(translationHelp) { + return translationHelp ?? null; + } + async function requestTranslationAudio(requester, options) { + const response = await requester.translateVideoImpl(options.videoData, options.requestLang, options.responseLang, normalizeTranslationHelp(options.translationHelp), !options.useAudioDownload, options.signal); + if (!response?.url) return null; + return { + url: response.url, + usedLivelyVoice: Boolean(response.usedLivelyVoice) + }; + } + function buildTranslationCacheValue(options) { + return { + videoId: options.videoId, + from: options.requestLang, + to: options.responseLang, + url: options.downloadTranslationUrl ?? options.fallbackUrl, + useLivelyVoice: options.usedLivelyVoice + }; + } + async function updateTranslationIfFresh(options) { + if (options.isActionStale(options.actionContext)) return false; + await options.updateTranslation(options.url, options.actionContext); + if (options.isActionStale(options.actionContext)) return false; + return true; + } + async function requestAndApplyTranslation(options) { + const translateRes = await requestTranslationAudio(options.requester, { + videoData: options.request.videoData, + requestLang: options.request.requestLang, + responseLang: options.request.responseLang, + translationHelp: options.request.translationHelp, + useAudioDownload: options.request.useAudioDownload, + signal: options.request.signal + }); + if (!translateRes) return null; + if (!await updateTranslationIfFresh({ + url: translateRes.url, + actionContext: options.actionContext, + isActionStale: options.isActionStale, + updateTranslation: options.updateTranslation + }) || options.isActionStale(options.actionContext)) return null; + return translateRes; + } + function setTranslationCacheValue(options) { + options.setTranslation(options.cacheKey, buildTranslationCacheValue({ + videoId: options.videoId, + requestLang: options.requestLang, + responseLang: options.responseLang, + fallbackUrl: options.fallbackUrl, + downloadTranslationUrl: options.downloadTranslationUrl, + usedLivelyVoice: options.usedLivelyVoice + })); + } + function notifyTranslationFailureIfNeeded(options) { + if (options.aborted || !options.translateApiErrorsEnabled || !options.hadAsyncWait) return options.hadAsyncWait; + options.notify({ + videoId: options.videoId, + message: options.error + }); + return false; + } + //#endregion + //#region src/core/translationHandler.ts + function asVotClientErrorShape(value) { + if (!value || typeof value !== "object") return null; + const candidate = value; + const data = candidate.data && typeof candidate.data === "object" ? candidate.data : void 0; + return { + name: candidate.name, + message: candidate.message, + data + }; + } + function getServerErrorMessage(value) { + const message = asVotClientErrorShape(value)?.data?.message; + return typeof message === "string" && message.length > 0 ? message : void 0; + } + /** + * Historically we used `patch-package` to make `@vot.js/core` throw + * `VOTLocalizedError` for a few common failure cases. + * + * We now keep the dependency unpatched and instead map known error messages + * coming from the VOT client to the corresponding localized UI errors. + */ + function mapVotClientErrorForUi(error) { + const err = asVotClientErrorShape(error); + if (!err) return error; + if (err.name !== "VOTJSError") return error; + const message = typeof err.message === "string" ? err.message : ""; + const hasServerMessage = typeof err.data?.message === "string" && err.data.message.length > 0; + if (message === "Yandex couldn't translate video" && !hasServerMessage) return new VOTLocalizedError("requestTranslationFailed"); + if (message === "Failed to request video translation") return new VOTLocalizedError("requestTranslationFailed"); + if (message === "Audio link wasn't received" || message === "Audio link wasn't received from VOT response") return new VOTLocalizedError("audioNotReceived"); + return error; + } + function summarizeTranslationResponse(response) { + return { + status: response.status, + translated: response.translated, + remainingTime: response.remainingTime, + translationId: response.translationId + }; + } + var VOTTranslationHandler = class { + videoHandler; + audioDownloader; + downloading; + downloadWaiters = /* @__PURE__ */ new Set(); + requestedFailAudio = /* @__PURE__ */ new Set(); + constructor(videoHandler) { + this.videoHandler = videoHandler; + this.audioDownloader = new AudioDownloader(); + this.downloading = false; + this.audioDownloader.addEventListener("downloadedAudio", this.onDownloadedAudio).addEventListener("downloadedPartialAudio", this.onDownloadedPartialAudio).addEventListener("downloadAudioError", this.onDownloadAudioError); + } + onDownloadedAudio = async (translationId, data) => { + debug.log("downloadedAudio", data); + if (!this.downloading) { + debug.log("skip downloadedAudio"); + return; + } + const { videoId, fileId, audioData } = data; + const videoUrl = this.getCanonicalUrl(videoId); + try { + await this.videoHandler.votClient.requestVtransAudio(videoUrl, translationId, { + audioFile: audioData, + fileId + }); + } catch (error) { + debug.error("Failed to upload downloaded audio", error); + this.finishDownloadFailure(/* @__PURE__ */ new Error("Audio downloader failed while uploading full audio")); + return; + } + this.finishDownloadSuccess(); + }; + onDownloadedPartialAudio = async (translationId, data) => { + debug.log("downloadedPartialAudio", data); + if (!this.downloading) { + debug.log("skip downloadedPartialAudio"); + return; + } + const { audioData, fileId, videoId, amount, version, index } = data; + const videoUrl = this.getCanonicalUrl(videoId); + try { + await this.videoHandler.votClient.requestVtransAudio(videoUrl, translationId, { + audioFile: audioData, + chunkId: index + }, { + audioPartsLength: amount, + fileId, + version + }); + } catch (error) { + debug.error("Failed to upload downloaded audio chunk", error); + this.finishDownloadFailure(/* @__PURE__ */ new Error("Audio downloader failed while uploading chunk")); + return; + } + if (index === amount - 1) this.finishDownloadSuccess(); + }; + onDownloadAudioError = async (videoId) => { + if (!this.downloading) { + debug.log("skip downloadAudioError"); + return; + } + debug.log(`Failed to download audio ${videoId}`); + const videoUrl = this.getCanonicalUrl(videoId); + if (!(this.videoHandler.site.host === "youtube" && Boolean(this.videoHandler.data?.useAudioDownload))) { + this.finishDownloadFailure(new VOTLocalizedError("VOTFailedDownloadAudio")); + return; + } + try { + if (this.requestedFailAudio.has(videoUrl)) debug.log("fail-audio-js request already sent for this video"); + else { + debug.log("Sending fail-audio-js request"); + await this.videoHandler.votClient.requestVtransFailAudio(videoUrl); + this.requestedFailAudio.add(videoUrl); + } + this.finishDownloadSuccess(); + } catch (error) { + debug.error("fail-audio-js request failed", error); + this.finishDownloadFailure(new VOTLocalizedError("VOTFailedDownloadAudio")); + } + }; + finishDownloadSuccess() { + this.downloading = false; + this.resolveDownloadWaiters(); + } + finishDownloadFailure(error) { + this.downloading = false; + this.rejectDownloadWaiters(error); + } + getCanonicalUrl(videoId) { + return `https://youtu.be/${videoId}`; + } + /** + * Detector for cases when server rejects the request because + * "Lively/Live voices" are unavailable (unsupported language pair). + */ + isLivelyVoiceUnavailableError(value) { + const msg = getErrorMessage(value); + return !!msg && msg.toLowerCase().includes("обычная озвучка"); + } + scheduleRetry(fn, delayMs, signal) { + return new Promise((resolve, reject) => { + let timeoutId = null; + const cleanup = () => { + if (timeoutId !== null) clearTimeout(timeoutId); + signal.removeEventListener("abort", onAbort); + }; + const onAbort = () => { + cleanup(); + reject(makeAbortError()); + }; + signal.addEventListener("abort", onAbort, { once: true }); + if (signal.aborted) { + onAbort(); + return; + } + timeoutId = setTimeout(async () => { + if (signal.aborted) { + onAbort(); + return; + } + cleanup(); + try { + resolve(await fn()); + } catch (error) { + reject(error); + } + }, delayMs); + if (timeoutId !== null) this.videoHandler.autoRetry = timeoutId; + }); + } + getVideoTranslationRetryDelayMs(retryAttempt, videoDurationSeconds) { + if (retryAttempt > 0) return 25e3; + return videoDurationSeconds <= 600 ? 6e4 : 75e3; + } + async translateVideoImpl(videoData, requestLang, responseLang, translationHelp = null, shouldSendFailedAudio = false, signal = NEVER_ABORTED_SIGNAL, options = {}) { + const { disableLivelyVoice = false, retryAttempt = 0 } = options; + clearTimeout(this.videoHandler.autoRetry); + this.finishDownloadSuccess(); + const requestLangForApi = this.videoHandler.getRequestLangForTranslation(requestLang, responseLang); + debug.log("[Translation] translateVideoImpl start", { + videoId: videoData.videoId, + duration: videoData.duration, + requestLang, + requestLangForApi, + responseLang, + retryAttempt, + disableLivelyVoice, + shouldSendFailedAudio, + translationHelpCount: translationHelp?.length ?? 0 + }); + debug.log(videoData, `Translate video (requestLang: ${requestLang}, requestLangForApi: ${requestLangForApi}, responseLang: ${responseLang})`); + let livelyDisabled = disableLivelyVoice; + try { + throwIfAborted(signal); + const livelyVoiceAllowed = this.videoHandler.isLivelyVoiceAllowed(requestLangForApi, responseLang); + const translationAttempt = await this.requestTranslationWithLivelyFallback({ + videoData, + requestLangForApi, + responseLang, + translationHelp, + shouldSendFailedAudio, + livelyDisabled, + livelyVoiceAllowed + }); + livelyDisabled = translationAttempt.livelyDisabled; + const useLivelyVoice = translationAttempt.useLivelyVoice; + const res = translationAttempt.response; + if (!res) throw new Error("Failed to get translation response"); + debug.log("[Translation] translateVideoImpl response", { + videoId: videoData.videoId, + useLivelyVoice, + ...summarizeTranslationResponse(res) + }); + throwIfAborted(signal); + if (res.translated && res.remainingTime < 1) { + debug.log("[Translation] translation finished", { + videoId: videoData.videoId, + useLivelyVoice, + ...summarizeTranslationResponse(res) + }); + return { + ...res, + usedLivelyVoice: useLivelyVoice + }; + } + const message = res.message ?? localizationProvider.get("translationTakeFewMinutes"); + debug.log("[Translation] translation still processing", { + videoId: videoData.videoId, + useLivelyVoice, + ...summarizeTranslationResponse(res), + message + }); + await this.videoHandler.updateTranslationErrorMsg(res.remainingTime > 0 ? formatTranslationEta(res.remainingTime, (key) => localizationProvider.get(key)) : message, signal); + if (res.status === VideoTranslationStatus.AUDIO_REQUESTED && this.videoHandler.isYouTubeHosts()) { + this.videoHandler.hadAsyncWait = true; + debug.log("[Translation] audio download started", { + videoId: videoData.videoId, + translationId: res.translationId + }); + this.downloading = true; + await this.audioDownloader.runAudioDownload(videoData.videoId, res.translationId, signal); + debug.log("[Translation] waiting for audio download completion", { + videoId: videoData.videoId, + translationId: res.translationId, + timeoutMs: 15e3 + }); + await this.waitForAudioDownloadCompletion(signal, 15e3); + return await this.translateVideoImpl(videoData, requestLang, responseLang, translationHelp, true, signal, { + disableLivelyVoice: livelyDisabled, + retryAttempt + }); + } + } catch (err) { + if (isAbortError$1(err)) { + debug.log("[Translation] translation aborted", { + videoId: videoData.videoId, + retryAttempt + }); + return null; + } + const uiError = mapVotClientErrorForUi(err); + debug.error("[Translation] translation failed", { + videoId: videoData.videoId, + retryAttempt, + error: err, + mappedError: uiError + }); + await this.videoHandler.updateTranslationErrorMsg(getServerErrorMessage(uiError) ?? uiError, signal); + this.videoHandler.hadAsyncWait = notifyTranslationFailureIfNeeded({ + aborted: Boolean(this.videoHandler.actionsAbortController?.signal?.aborted), + translateApiErrorsEnabled: Boolean(this.videoHandler.data?.translateAPIErrors), + hadAsyncWait: this.videoHandler.hadAsyncWait, + videoId: videoData.videoId, + error: err, + notify: (params) => this.videoHandler.notifier.translationFailed(params) + }); + return null; + } + this.videoHandler.hadAsyncWait = true; + const retryDelayMs = this.getVideoTranslationRetryDelayMs(retryAttempt, videoData.duration); + debug.log("[Translation] scheduling translation retry", { + videoId: videoData.videoId, + retryAttempt, + retryDelayMs, + duration: videoData.duration + }); + return this.scheduleRetry(() => this.translateVideoImpl(videoData, requestLang, responseLang, translationHelp, shouldSendFailedAudio, signal, { + disableLivelyVoice: livelyDisabled, + retryAttempt: retryAttempt + 1 + }), retryDelayMs, signal); + } + async requestTranslationWithLivelyFallback({ videoData, requestLangForApi, responseLang, translationHelp, shouldSendFailedAudio, livelyDisabled, livelyVoiceAllowed }) { + let useLivelyVoice = !livelyDisabled && livelyVoiceAllowed && Boolean(this.videoHandler.data?.useLivelyVoice); + debug.log("[Translation] requesting translation from VOT client", { + videoId: videoData.videoId, + requestLangForApi, + responseLang, + shouldSendFailedAudio, + livelyDisabled, + livelyVoiceAllowed, + useLivelyVoice, + translationHelpCount: translationHelp?.length ?? 0 + }); + while (true) { + try { + debug.log("[Translation] votClient.translateVideo call", { + videoId: videoData.videoId, + requestLangForApi, + responseLang, + useLivelyVoice, + shouldSendFailedAudio, + translationHelpCount: translationHelp?.length ?? 0 + }); + const response = await this.videoHandler.votClient.translateVideo({ + videoData, + requestLang: requestLangForApi, + responseLang, + translationHelp, + extraOpts: { + useLivelyVoice, + videoTitle: this.videoHandler.videoData?.title + }, + shouldSendFailedAudio + }); + if (!useLivelyVoice || !this.isLivelyVoiceUnavailableError(response)) { + debug.log("[Translation] votClient.translateVideo resolved", { + videoId: videoData.videoId, + useLivelyVoice, + ...summarizeTranslationResponse(response) + }); + return { + response, + useLivelyVoice, + livelyDisabled + }; + } + debug.warn("[Translation] lively voice unavailable in response", { + videoId: videoData.videoId, + useLivelyVoice, + ...summarizeTranslationResponse(response) + }); + } catch (err) { + if (!useLivelyVoice || !this.isLivelyVoiceUnavailableError(err)) throw err; + debug.warn("[Translation] lively voice unavailable in error", { + videoId: videoData.videoId, + useLivelyVoice, + error: err + }); + } + livelyDisabled = true; + useLivelyVoice = false; + debug.log("[Translation] retrying translation without lively voice", { + videoId: videoData.videoId, + requestLangForApi, + responseLang + }); + } + } + waitForAudioDownloadCompletion(signal, timeoutMs) { + if (!this.downloading) return Promise.resolve(); + return new Promise((resolve, reject) => { + let entry; + const onAbort = () => { + cleanup(); + reject(makeAbortError()); + }; + const timeoutId = setTimeout(() => { + cleanup(); + resolve(); + }, timeoutMs); + const cleanup = () => { + clearTimeout(timeoutId); + signal.removeEventListener("abort", onAbort); + this.downloadWaiters.delete(entry); + }; + entry = { + resolve: () => { + cleanup(); + resolve(); + }, + reject: (error) => { + cleanup(); + reject(error); + } + }; + this.downloadWaiters.add(entry); + signal.addEventListener("abort", onAbort, { once: true }); + if (signal.aborted) onAbort(); + }); + } + resolveDownloadWaiters() { + this.forEachDownloadWaiter((waiter) => waiter.resolve()); + } + rejectDownloadWaiters(error) { + this.forEachDownloadWaiter((waiter) => waiter.reject(error)); + } + forEachDownloadWaiter(handler) { + if (!this.downloadWaiters.size) return; + const waiters = Array.from(this.downloadWaiters); + this.downloadWaiters.clear(); + for (const waiter of waiters) handler(waiter); + } + }; + //#endregion + //#region src/core/translationOrchestrator.ts + var TranslationOrchestrator = class { + state = { status: "idle" }; + deps; + constructor(deps) { + this.deps = deps; + } + get currentState() { + return this.state; + } + setState(next) { + this.state = next; + debug.log("[TranslationOrchestrator] state", next); + } + reset() { + this.setState({ status: "idle" }); + } + async runAutoTranslationIfEligible() { + if (this.state.status !== "idle") return; + if (!(this.deps.isFirstPlay() && this.deps.isAutoTranslateEnabled() && this.deps.getVideoId())) return; + if (this.deps.isMobileYouTubeMuted?.()) { + debug.log("[TranslationOrchestrator] Mobile YouTube video is muted, deferring auto-translate"); + this.setState({ + status: "deferred", + reason: "muted" + }); + this.deps.setMuteWatcher?.(() => { + debug.log("[TranslationOrchestrator] Video unmuted, running deferred auto-translate"); + this.setState({ status: "idle" }); + this.runAutoTranslationIfEligible(); + }); + return; + } + this.setState({ + status: "pending", + reason: "auto" + }); + try { + await this.deps.scheduleAutoTranslate(); + this.deps.setFirstPlay(false); + this.reset(); + } catch (err) { + this.setState({ + status: "error", + message: err + }); + throw err; + } + } + }; + //#endregion + //#region src/core/lifecycleShared.ts + function resetLifecycleTranslation(host, options = {}) { + const { requireVideoData = false, clearVideoData = false } = options; + if (requireVideoData && !host.videoData) return; + if (clearVideoData) host.videoData = void 0; + host.stopTranslation(); + host.resetSubtitlesWidget(); + } + function hideLifecycleOverlay(overlayView, options = {}) { + const { hideMenu = false } = options; + if (overlayView?.votButton?.container) overlayView.votButton.container.hidden = true; + if (hideMenu && overlayView?.votMenu) overlayView.votMenu.hidden = true; + } + function resetAndHideLifecycle(host, overlayView, options = {}) { + const { requireVideoData, clearVideoData, hideMenu } = options; + resetLifecycleTranslation(host, { + requireVideoData, + clearVideoData + }); + hideLifecycleOverlay(overlayView, { hideMenu }); + } + //#endregion + //#region src/core/videoLifecycleController.ts + var VideoLifecycleController = class { + host; + lifecycleGeneration = 0; + lastSetCanPlaySourceKey = ""; + activeSetCanPlaySourceKey = ""; + setCanPlayRequested = false; + setCanPlayLoopPromise; + constructor(host) { + this.host = host; + } + isStale(generation) { + return generation !== this.lifecycleGeneration; + } + resetActions(reason) { + if (typeof this.host.resetActionsAbortController === "function") { + this.host.resetActionsAbortController(reason); + return; + } + this.host.actionsAbortController?.abort(reason); + } + invalidateActiveSession(reason) { + if (this.lifecycleGeneration === 0) return; + this.lifecycleGeneration += 1; + this.resetActions(`[VideoLifecycle] ${reason}`); + debug.log(`[VideoLifecycle] cancelled active session (active: ${this.lifecycleGeneration})`, { reason }); + } + startSession(reason) { + this.lifecycleGeneration += 1; + const sessionId = this.lifecycleGeneration; + this.resetActions(`[VideoLifecycle][session:${sessionId}] ${reason}`); + debug.log(`[VideoLifecycle][session:${sessionId}] started`, { reason }); + return sessionId; + } + shouldAbortHandleSrcChanged(callId, stage) { + if (!this.isStale(callId)) return false; + debug.log(`[VideoLifecycle][session:${callId}] handleSrcChanged aborted at ${stage} (active: ${this.lifecycleGeneration})`); + return true; + } + showOverlayButton(overlayView) { + overlayView.votButton.container.hidden = false; + overlayView.votButton.opacity = 1; + this.host.queueOverlayAutoHide?.(); + } + teardown() { + this.setCanPlayRequested = false; + this.invalidateActiveSession("teardown"); + } + getCurrentSourceKey() { + const hasSrcObject = this.host.video.srcObject ? "1" : "0"; + if (this.host.site.host === "youtube") { + const path = globalThis.location.pathname; + return `${`${globalThis.location.origin}${path}${globalThis.location.search}`}||${hasSrcObject}`; + } + const src = this.host.video.currentSrc || this.host.video.src || ""; + return `${globalThis.location.href}||${src}||${hasSrcObject}`; + } + resolveContainer() { + const { site, video, container } = this.host; + if (!site.selector) return video.parentElement ?? container; + const matched = findConnectedContainerBySelector(video, site.selector); + if (matched) return matched; + if (container.isConnected && containsCrossShadow(container, video)) return container; + return video.parentElement ?? container; + } + async setCanPlay() { + this.setCanPlayRequested = true; + if (this.setCanPlayLoopPromise !== void 0) { + const incomingSourceKey = this.getCurrentSourceKey(); + if (this.activeSetCanPlaySourceKey && incomingSourceKey !== this.activeSetCanPlaySourceKey) this.invalidateActiveSession("setCanPlay source changed while previous trigger is running"); + else debug.log("[VideoLifecycle] setCanPlay deduplicated for same source", { sourceKey: incomingSourceKey }); + return await this.setCanPlayLoopPromise; + } + const loopPromise = (async () => { + while (this.setCanPlayRequested) { + this.setCanPlayRequested = false; + await this.runSetCanPlayOnce(); + } + })(); + this.setCanPlayLoopPromise = loopPromise; + try { + await loopPromise; + } finally { + if (this.setCanPlayLoopPromise === loopPromise) this.setCanPlayLoopPromise = void 0; + } + } + async runSetCanPlayOnce() { + const sourceKey = this.getCurrentSourceKey(); + if (this.host.videoData?.videoId && sourceKey === this.lastSetCanPlaySourceKey) { + debug.log("[VideoLifecycle] setCanPlay deduplicated for same source", { sourceKey }); + return; + } + let nextVideoData; + try { + nextVideoData = await this.host.getVideoData(); + } catch (err) { + debug.log(`[VideoLifecycle] getVideoData failed for source ${sourceKey}`, err); + this.host.videoData = void 0; + hideLifecycleOverlay(this.host.uiManager.votOverlayView, { hideMenu: true }); + return; + } + if (this.getCurrentSourceKey() !== sourceKey) { + debug.log("[VideoLifecycle] discarded stale getVideoData result after source change", { sourceKey }); + return; + } + this.host.videoData = nextVideoData; + this.activeSetCanPlaySourceKey = sourceKey; + const currentId = this.startSession(`setCanPlay (source: ${sourceKey})`); + debug.log(`[VideoLifecycle][session:${currentId}] setCanPlay started`, { sourceKey }); + try { + await this.handleSrcChanged(currentId, sourceKey); + if (this.isStale(currentId)) { + debug.log(`[VideoLifecycle][session:${currentId}] setCanPlay aborted after src change (active: ${this.lifecycleGeneration})`); + return; + } + const autoSubtitlesPromise = this.runAutoSubtitlesIfEnabled(currentId); + await this.host.translationOrchestrator.runAutoTranslationIfEligible(); + if (this.isStale(currentId)) { + debug.log(`[VideoLifecycle][session:${currentId}] auto-translation result ignored (stale session)`); + return; + } + await autoSubtitlesPromise; + if (this.isStale(currentId)) { + debug.log(`[VideoLifecycle][session:${currentId}] auto-subtitles result ignored (stale session)`); + return; + } + debug.log(`[VideoLifecycle][session:${currentId}] setCanPlay finished`); + } finally { + if (this.activeSetCanPlaySourceKey === sourceKey) this.activeSetCanPlaySourceKey = ""; + } + } + async runAutoSubtitlesIfEnabled(sessionId) { + if (!this.host.data.autoSubtitles || !this.host.videoData?.videoId) return; + try { + await this.host.enableSubtitlesForCurrentLangPair(); + } catch (err) { + debug.log(`[VideoLifecycle][session:${sessionId}] auto-subtitles failed`, err); + } + } + async handleSrcChanged(callId, expectedSourceKey) { + const sessionId = typeof callId === "number" ? callId : this.startSession("manual handleSrcChanged"); + const sourceKey = typeof expectedSourceKey === "string" && expectedSourceKey.length > 0 ? expectedSourceKey : this.getCurrentSourceKey(); + if (this.shouldAbortHandleSrcChanged(sessionId, "before start")) return; + debug.log(`[VideoLifecycle][session:${sessionId}] src changed`, { sourceKey }); + this.host.translationOrchestrator.reset(); + this.host.firstPlay = true; + const overlayView = this.host.uiManager.votOverlayView; + resetAndHideLifecycle(this.host, overlayView, { requireVideoData: true }); + if (!this.host.video.src && !this.host.video.currentSrc && !this.host.video.srcObject) hideLifecycleOverlay(overlayView, { hideMenu: true }); + const nextContainer = this.resolveContainer(); + if (nextContainer !== this.host.container) this.host.container = nextContainer; + if (this.shouldAbortHandleSrcChanged(sessionId, "before getVideoData")) return; + this.showOverlayButton(overlayView); + if (this.shouldAbortHandleSrcChanged(sessionId, "after getVideoData")) return; + if (!this.host.videoData?.videoId) { + debug.log(`[VideoLifecycle][session:${sessionId}] No videoId resolved, hiding overlay`); + hideLifecycleOverlay(overlayView, { hideMenu: true }); + return; + } + const subtitleLanguage = this.host.getPreferredSubtitlesLanguage(this.host.videoData.detectedLanguage, this.host.videoData.responseLanguage); + if (subtitleLanguage) { + const cacheKey = this.host.getSubtitlesCacheKey(this.host.videoData.videoId, this.host.videoData.detectedLanguage, subtitleLanguage); + const cachedSubtitles = this.host.cacheManager.getSubtitles(cacheKey); + this.host.subtitles = cachedSubtitles ?? []; + this.host.subtitlesCacheKey = cachedSubtitles !== void 0 ? cacheKey : null; + } else { + this.host.subtitles = []; + this.host.subtitlesCacheKey = null; + } + await this.host.updateSubtitlesLangSelect(); + if (this.shouldAbortHandleSrcChanged(sessionId, "after subtitles update")) return; + this.host.translateToLang = this.host.data.responseLanguage ?? "ru"; + this.host.setSelectMenuValues(this.host.videoData.detectedLanguage, this.host.videoData.responseLanguage); + this.showOverlayButton(overlayView); + this.lastSetCanPlaySourceKey = sourceKey; + debug.log(`[VideoLifecycle][session:${sessionId}] src handling finished`); + } + }; + //#endregion + //#region src/core/videoLifecycleHost.ts + function createVideoLifecycleHost(handler, resolveOverlayMount) { + const self = () => handler; + return { + get video() { + return self().video; + }, + get site() { + return self().site; + }, + get container() { + return self().container; + }, + set container(value) { + if (self().container === value) return; + self().container = value; + self().uiManager.updateMount(resolveOverlayMount(value)); + }, + get firstPlay() { + return self().firstPlay; + }, + set firstPlay(value) { + self().firstPlay = value; + }, + stopTranslation: () => handler.stopTranslation(), + get uiManager() { + return self().uiManager; + }, + getVideoData: () => handler.getVideoData(), + cacheManager: { getSubtitles: (key) => self().cacheManager.getSubtitles(key) }, + getSubtitlesCacheKey: (videoId, detectedLanguage, subtitleLanguage) => handler.getSubtitlesCacheKey(videoId, detectedLanguage, subtitleLanguage), + getPreferredSubtitlesLanguage: (detectedLanguage, responseLanguage) => handler.getPreferredSubtitlesLanguage(detectedLanguage, responseLanguage), + updateSubtitlesLangSelect: () => handler.updateSubtitlesLangSelect(), + enableSubtitlesForCurrentLangPair: () => handler.enableSubtitlesForCurrentLangPair(), + setSelectMenuValues: (from, to) => handler.setSelectMenuValues(from, to), + get translateToLang() { + return self().translateToLang; + }, + set translateToLang(value) { + self().translateToLang = value; + }, + get data() { + return self().data ?? {}; + }, + get subtitles() { + return self().subtitles; + }, + set subtitles(value) { + self().subtitles = value; + }, + get subtitlesCacheKey() { + return self().subtitlesCacheKey; + }, + set subtitlesCacheKey(value) { + self().subtitlesCacheKey = value; + }, + get videoData() { + return self().videoData; + }, + set videoData(value) { + self().videoData = value; + }, + get actionsAbortController() { + return self().actionsAbortController; + }, + set actionsAbortController(value) { + self().actionsAbortController = value; + }, + resetActionsAbortController: (reason) => handler.resetActionsAbortController(reason), + translationOrchestrator: handler.translationOrchestrator, + resetSubtitlesWidget: () => handler.resetSubtitlesWidget(), + queueOverlayAutoHide: () => handler.overlayVisibility?.queueAutoHide() + }; + } + //#endregion + //#region src/utils/text.ts + var MAX_TEXT_LENGTH = 450; + var REMOVABLE_TOKEN_FILTER = new RegExp([ + String.raw`(?:https?:\/\/|www\.)\S+`, + String.raw`#[^\s#]+`, + String.raw`auto-generated\s+by\s+youtube`, + String.raw`provided\s+to\s+youtube\s+by`, + String.raw`released\s+on`, + String.raw`\bpaypal\b`, + String.raw`\b0x[a-f0-9]{40}\b`, + String.raw`\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b`, + String.raw`\b(?:bc1|tb1|bcrt1)[ac-hj-np-z02-9]{11,71}\b`, + String.raw`\b(?:-1|0):[a-f0-9]{64}\b` + ].join("|"), "giu"); + var NOISE_CHARACTER_FILTER = /[\p{N}\p{P}\p{S}]+/gu; + var WHITESPACE_FILTER = /\s+/g; + var LETTER_FILTER = /\p{L}/u; + function trimToMaxLength(text, maxLength) { + if (text.length <= maxLength) return text; + return text.slice(0, maxLength).trimEnd(); + } + function cleanText(title, description) { + const raw = `${title ?? ""} ${description ?? ""}`.trim(); + if (!raw) return ""; + const cleaned = raw.normalize("NFKC").replace(REMOVABLE_TOKEN_FILTER, " ").replace(NOISE_CHARACTER_FILTER, " ").replace(WHITESPACE_FILTER, " ").trim(); + if (!LETTER_FILTER.test(cleaned)) return ""; + return trimToMaxLength(cleaned, MAX_TEXT_LENGTH); + } + //#endregion + //#region src/utils/translateApis.ts + var SETTINGS_CACHE_TTL_MS = 5e3; + var IMMUTABLE_API_CACHE_TTL_MS = Number.MAX_SAFE_INTEGER; + var cachedTranslationService = null; + var cachedTranslationServiceAt = 0; + var cachedDetectService = null; + var cachedDetectServiceAt = 0; + async function getTranslationServiceCached() { + const now = Date.now(); + if (cachedTranslationService && now - cachedTranslationServiceAt < SETTINGS_CACHE_TTL_MS) return cachedTranslationService; + const service = await votStorage.get("translationService", defaultTranslationService); + cachedTranslationService = String(service); + cachedTranslationServiceAt = now; + return cachedTranslationService; + } + async function getDetectServiceCached() { + const now = Date.now(); + if (cachedDetectService && now - cachedDetectServiceAt < SETTINGS_CACHE_TTL_MS) return cachedDetectService; + const service = await votStorage.get("detectService", defaultDetectService); + cachedDetectService = String(service); + cachedDetectServiceAt = now; + return cachedDetectService; + } + var foswlyServices = ["yandexbrowser", "msedge"]; + /** + * Limit: 10k symbols for yandex, 50k for msedge + */ + var FOSWLYTranslateAPI = new class { + isFOSWLYError(data) { + return Object.hasOwn(data, "error"); + } + async request(path, opts = {}) { + try { + const data = await (await GM_fetch(`${foswlyTranslateUrl}${path}`, { + timeout: 3e3, + responseCache: { + ttlMs: IMMUTABLE_API_CACHE_TTL_MS, + cacheName: "vot-foswly-api-v1", + allowStaleOnError: true + }, + ...opts + })).json(); + if (this.isFOSWLYError(data)) throw new Error(data.error); + return data; + } catch (err) { + console.error(`[VOT] Failed to get data from FOSWLY Translate API, because ${err instanceof Error ? err.message : String(err)}`); + return; + } + } + async translateMultiple(text, lang, service) { + const result = await this.request("/translate", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + text, + lang, + service + }) + }); + return result ? result.translations : text; + } + async translate(text, lang, service) { + const result = await this.request(`/translate?${new URLSearchParams({ + text, + lang, + service + })}`); + return result ? result.translations[0] : text; + } + async detect(text, service) { + const result = await this.request(`/detect?${new URLSearchParams({ + text, + service + })}`); + return result ? result.lang : "en"; + } + }(); + var RustServerAPI = { async detect(text) { + try { + return await (await GM_fetch(detectRustServerUrl, { + method: "POST", + body: text, + timeout: 3e3, + responseCache: { + ttlMs: IMMUTABLE_API_CACHE_TTL_MS, + cacheName: "vot-rust-detect-v1", + allowStaleOnError: true + } + })).text(); + } catch (error) { + console.error(`[VOT] Error getting lang from text, because ${error.message}`); + return "en"; + } + } }; + async function translate(text, fromLang = "", toLang = "ru") { + if (fromLang && toLang && fromLang === toLang) return text; + const service = await getTranslationServiceCached(); + switch (service) { + case "yandexbrowser": + case "msedge": { + const langPair = fromLang && toLang ? `${fromLang}-${toLang}` : toLang; + return Array.isArray(text) ? await FOSWLYTranslateAPI.translateMultiple(text, langPair, service) : await FOSWLYTranslateAPI.translate(text, langPair, service); + } + default: return text; + } + } + async function detect(text) { + const service = await getDetectServiceCached(); + switch (service) { + case "yandexbrowser": + case "msedge": return await FOSWLYTranslateAPI.detect(text, service); + case "rust-server": return await RustServerAPI.detect(text); + default: return "en"; + } + } + var detectServices = [...foswlyServices, "rust-server"]; + //#endregion + //#region src/utils/volume.ts + var VIDEO_VOLUME_MIN_PERCENT = 0; + var VIDEO_VOLUME_MAX_PERCENT = 100; + var VIDEO_VOLUME_STEP_01 = .01; + var EPS = 1e-6; + function clampNumber$2(value, min, max) { + if (!Number.isFinite(value)) return min; + if (max < min) return min; + return Math.max(min, Math.min(max, value)); + } + function clampInt(value, min, max) { + return Math.trunc(clampNumber$2(value, min, max)); + } + function clampPercentInt(value, min = VIDEO_VOLUME_MIN_PERCENT, max = VIDEO_VOLUME_MAX_PERCENT) { + if (!Number.isFinite(value)) return min; + return clampInt(Math.round(value), min, max); + } + function volume01ToPercent(volume01) { + return clampPercentInt(clampNumber$2(volume01, 0, 1) * 100); + } + function percentToVolume01(percent) { + return clampPercentInt(percent) / 100; + } + function quantizeToStep(value, step, direction) { + if (!Number.isFinite(value)) return value; + if (!Number.isFinite(step) || step <= 0) return value; + const inv = 1 / step; + const scaled = value * inv; + switch (direction) { + case "down": return Math.floor(scaled + EPS) / inv; + case "up": return Math.ceil(scaled - EPS) / inv; + default: return Math.round(scaled) / inv; + } + } + function snapVolume01(volume01, direction = "nearest", step = VIDEO_VOLUME_STEP_01) { + return clampNumber$2(quantizeToStep(clampNumber$2(volume01, 0, 1), step, direction), 0, 1); + } + function snapVolume01Towards(next, current, desired, step = VIDEO_VOLUME_STEP_01) { + const cur = clampNumber$2(current, 0, 1); + const des = clampNumber$2(desired, 0, 1); + if (des < cur) { + const q = snapVolume01(next, "down", step); + return Math.max(des, q); + } + if (des > cur) { + const q = snapVolume01(next, "up", step); + return Math.min(des, q); + } + return snapVolume01(next, "nearest", step); + } + //#endregion + //#region src/core/hostPolicies.ts + var EXTERNAL_VOLUME_HOSTS = new Set(["youtube", "googledrive"]); + var YOUTUBE_LIKE_HOSTS = EXTERNAL_VOLUME_HOSTS; + var MUTE_SYNC_DISABLED_HOSTS = new Set(["rutube", "ok"]); + var TRANSLATION_DOWNLOAD_HOSTS = new Set([ + "youtube", + "invidious", + "piped" + ]); + function isExternalVolumeHost(host) { + return EXTERNAL_VOLUME_HOSTS.has(host); + } + function isYouTubeLikeHost(host) { + return YOUTUBE_LIKE_HOSTS.has(host); + } + function isMuteSyncDisabledHost(host) { + return MUTE_SYNC_DISABLED_HOSTS.has(host); + } + function isDesktopYouTubeLikeSite(site) { + return isYouTubeLikeHost(site.host) && site.additionalData !== "mobile"; + } + function isTranslationDownloadHost(host) { + return TRANSLATION_DOWNLOAD_HOSTS.has(host); + } + //#endregion + //#region src/core/videoManager.ts + var FORCED_DETECTED_LANGUAGE_BY_HOST = { + rutube: "ru", + "ok.ru": "ru", + mail_ru: "ru", + weverse: "ko", + niconico: "ja", + youku: "zh", + bilibili: "zh", + weibo: "zh", + zdf: "de" + }; + var YT_VOLUME_NOW_SELECTOR = ".ytp-volume-panel [aria-valuenow]"; + var MIN_DETECT_TEXT_LENGTH = 35; + var MAX_SHARED_LANGUAGE_STATES = 500; + var REQUEST_LANG_SET = new Set(availableLangs); + /** + * Shared language caches across VideoManager instances within one frame. + * + * YouTube Shorts can transiently create multiple video handlers while the URL + * (and therefore resolved `videoId`) still points to the same active short. + * Per-instance caches are insufficient in that case and can trigger duplicate + * language detection requests. + */ + var sharedLanguageStateByVideoId = /* @__PURE__ */ new Map(); + function getSharedLanguageState(videoId) { + const cachedState = sharedLanguageStateByVideoId.get(videoId); + if (cachedState) return cachedState; + const createdState = {}; + sharedLanguageStateByVideoId.set(videoId, createdState); + while (sharedLanguageStateByVideoId.size > MAX_SHARED_LANGUAGE_STATES) { + const oldestVideoId = sharedLanguageStateByVideoId.keys().next().value; + if (typeof oldestVideoId !== "string") break; + sharedLanguageStateByVideoId.delete(oldestVideoId); + } + return createdState; + } + function normalizeToRequestLang(value) { + if (typeof value !== "string") return void 0; + const normalized = value.toLowerCase().split(/[-_]/)[0]; + return REQUEST_LANG_SET.has(normalized) ? normalized : void 0; + } + function isResolvedLanguage(value) { + return Boolean(value && value !== "auto"); + } + function buildDetectText(title, description) { + return cleanText(typeof title === "string" ? title : "", typeof description === "string" ? description : void 0); + } + function resolveHostDetectedLanguage(host) { + const forcedDetectedLanguage = FORCED_DETECTED_LANGUAGE_BY_HOST[host]; + if (forcedDetectedLanguage) return forcedDetectedLanguage; + if (host === "vk") { + const trackLang = document.getElementsByTagName("track")?.[0]?.srclang; + return normalizeToRequestLang(trackLang); + } + } + function resolveYoutubeDetectedLanguageFromSubtitles(subtitles) { + if (!Array.isArray(subtitles) || subtitles.length === 0) return; + const pickLanguage = (preferManual) => { + for (const subtitle of subtitles) { + if (!subtitle || typeof subtitle !== "object") continue; + const candidate = subtitle; + if (candidate.source !== "youtube") continue; + if (typeof candidate.translatedFromLanguage === "string") continue; + if (preferManual && candidate.isAutoGenerated === true) continue; + const language = normalizeToRequestLang(candidate.language); + if (isResolvedLanguage(language)) return language; + } + }; + return pickLanguage(true) ?? pickLanguage(false); + } + async function resolveDetectedLanguageForVideo(options) { + if (options.isStream) return { detectedLanguage: "auto" }; + if (options.userOverrideLanguage) return { detectedLanguage: options.userOverrideLanguage }; + const hostDetectedLanguage = resolveHostDetectedLanguage(options.host); + if (isResolvedLanguage(hostDetectedLanguage)) return { + detectedLanguage: hostDetectedLanguage, + cacheLanguage: hostDetectedLanguage + }; + const normalizedPossibleLanguage = normalizeToRequestLang(options.possibleLanguage); + if (isResolvedLanguage(normalizedPossibleLanguage)) return { + detectedLanguage: normalizedPossibleLanguage, + cacheLanguage: normalizedPossibleLanguage + }; + const youtubeSubtitleDetectedLanguage = options.host === "youtube" ? resolveYoutubeDetectedLanguageFromSubtitles(options.subtitles) : void 0; + if (isResolvedLanguage(youtubeSubtitleDetectedLanguage)) return { + detectedLanguage: youtubeSubtitleDetectedLanguage, + cacheLanguage: youtubeSubtitleDetectedLanguage + }; + if (options.cachedDetectedLanguage) return { detectedLanguage: options.cachedDetectedLanguage }; + if (!options.allowTextLanguageDetection) return { detectedLanguage: "auto" }; + const text = buildDetectText(options.title, options.description); + if (!text || text.length < MIN_DETECT_TEXT_LENGTH) return { detectedLanguage: "auto" }; + const detectedLanguage = await options.detectLanguage(text); + if (!detectedLanguage) return { detectedLanguage: "auto" }; + return { + detectedLanguage, + cacheLanguage: detectedLanguage + }; + } + function getAriaValueNowPercent(selector) { + const el = document.querySelector(selector); + const rawNow = el?.getAttribute("aria-valuenow"); + const rawMax = el?.getAttribute("aria-valuemax"); + const now = rawNow == null ? NaN : Number.parseFloat(rawNow); + const max = rawMax == null ? NaN : Number.parseFloat(rawMax); + if (!Number.isFinite(now)) return null; + if (Number.isFinite(max) && max > 0) return clampPercentInt(now / max * 100); + return clampPercentInt(now); + } + var VOTVideoManager = class { + videoHandler; + constructor(videoHandler) { + this.videoHandler = videoHandler; + } + setDetectedLanguageCache(videoId, language) { + getSharedLanguageState(videoId).detectedLanguage = language; + } + rememberUserLanguageSelection(videoId, language) { + const normalizedLanguage = normalizeToRequestLang(language); + if (!isResolvedLanguage(normalizedLanguage)) { + const sharedLanguageState = sharedLanguageStateByVideoId.get(videoId); + if (sharedLanguageState) delete sharedLanguageState.userLanguageOverride; + return; + } + const sharedLanguageState = getSharedLanguageState(videoId); + sharedLanguageState.userLanguageOverride = normalizedLanguage; + sharedLanguageState.detectedLanguage = normalizedLanguage; + } + rememberDetectedLanguage(videoId, language) { + const normalizedLanguage = normalizeToRequestLang(language); + if (!isResolvedLanguage(normalizedLanguage)) return; + this.setDetectedLanguageCache(videoId, normalizedLanguage); + if (this.videoHandler.videoData?.videoId === videoId) this.videoHandler.videoData.detectedLanguage = normalizedLanguage; + } + async detectLanguageSingleFlight(videoId, text) { + const sharedLanguageState = getSharedLanguageState(videoId); + const inFlightDetect = sharedLanguageState.detectInFlight; + if (inFlightDetect !== void 0) return inFlightDetect; + const task = (async () => { + debug.log(`Detecting language text: ${text}`); + const language = normalizeToRequestLang(await detect(text)); + return isResolvedLanguage(language) ? language : void 0; + })(); + sharedLanguageState.detectInFlight = task; + try { + return await task; + } finally { + if (sharedLanguageState.detectInFlight === task) delete sharedLanguageState.detectInFlight; + } + } + async ensureDetectedLanguageForTranslation(videoData) { + if (!videoData?.videoId || videoData.detectedLanguage !== "auto") return; + const sharedLanguageState = getSharedLanguageState(videoData.videoId); + const { detectedLanguage, cacheLanguage } = await resolveDetectedLanguageForVideo({ + isStream: videoData.isStream, + host: this.videoHandler.site.host, + possibleLanguage: videoData.detectedLanguage, + subtitles: videoData.subtitles, + userOverrideLanguage: sharedLanguageState.userLanguageOverride, + cachedDetectedLanguage: sharedLanguageState.detectedLanguage, + title: videoData.title, + description: videoData.description, + allowTextLanguageDetection: true, + detectLanguage: async (text) => await this.detectLanguageSingleFlight(videoData.videoId, text) + }); + if (cacheLanguage) this.setDetectedLanguageCache(videoData.videoId, cacheLanguage); + if (!detectedLanguage || detectedLanguage === "auto") return; + this.videoHandler.setSelectMenuValues(detectedLanguage, this.videoHandler.translateToLang); + } + async getVideoData() { + const { duration, url, videoId, host, title, translationHelp = null, localizedTitle, description, detectedLanguage: possibleLanguage, subtitles, isStream = false } = await getVideoData(this.videoHandler.site, { + fetchFn: GM_fetch, + video: this.videoHandler.video, + language: localizationProvider.lang + }); + const sharedLanguageState = getSharedLanguageState(videoId); + const { detectedLanguage, cacheLanguage } = await resolveDetectedLanguageForVideo({ + isStream, + host: this.videoHandler.site.host, + possibleLanguage, + subtitles, + userOverrideLanguage: sharedLanguageState.userLanguageOverride, + cachedDetectedLanguage: sharedLanguageState.detectedLanguage, + title, + description, + allowTextLanguageDetection: false, + detectLanguage: async (text) => await this.detectLanguageSingleFlight(videoId, text) + }); + if (cacheLanguage) this.setDetectedLanguageCache(videoId, cacheLanguage); + const videoData = { + translationHelp, + isStream, + duration: duration || this.videoHandler.video?.duration || config_default$1.defaultDuration, + videoId, + url, + host, + detectedLanguage, + responseLanguage: this.videoHandler.translateToLang, + subtitles, + title, + localizedTitle, + description, + downloadTitle: localizedTitle ?? title ?? document.title ?? videoId + }; + if (sharedLanguageState.lastLoggedDetectedLanguage !== detectedLanguage) { + console.log("[VOT] Detected language:", detectedLanguage); + sharedLanguageState.lastLoggedDetectedLanguage = detectedLanguage; + } + return videoData; + } + async videoValidator() { + const videoData = this.videoHandler.videoData; + const data = this.videoHandler.data; + if (!videoData || !data) throw new VOTLocalizedError("VOTNoVideoIDFound"); + debug.log("VideoValidator videoData: ", this.videoHandler.videoData); + if (this.videoHandler.data.enabledDontTranslateLanguages && this.videoHandler.data.dontTranslateLanguages?.includes(this.videoHandler.videoData.detectedLanguage)) throw new VOTLocalizedError("VOTDisableFromYourLang"); + if (this.videoHandler.videoData.isStream) throw new VOTLocalizedError("VOTStreamNotAvailable"); + if (this.videoHandler.videoData.duration > 14400) throw new VOTLocalizedError("VOTVideoIsTooLong"); + return true; + } + /** + * Gets current video volume (0.0 - 1.0) + */ + getVideoVolume() { + const video = this.videoHandler.video; + if (!video) return void 0; + if (isExternalVolumeHost(this.videoHandler.site.host)) { + const ariaPercent = getAriaValueNowPercent(YT_VOLUME_NOW_SELECTOR); + if (ariaPercent != null) return percentToVolume01(ariaPercent); + const extVolume = YoutubeHelper.getVolume(); + if (typeof extVolume === "number" && Number.isFinite(extVolume)) return snapVolume01(extVolume); + } + return snapVolume01(video.volume); + } + /** + * Sets the video volume + */ + setVideoVolume(volume) { + const snapped = snapVolume01(volume); + if (!isExternalVolumeHost(this.videoHandler.site.host)) { + this.videoHandler.video.volume = snapped; + return this; + } + try { + const result = YoutubeHelper.setVolume(snapped); + if (typeof result === "boolean" && result || typeof result === "number" && Number.isFinite(result)) return this; + } catch {} + this.videoHandler.video.volume = snapped; + return this; + } + /** + * Checks if the video is muted + */ + isMuted() { + return isExternalVolumeHost(this.videoHandler.site.host) ? YoutubeHelper.isMuted() : this.videoHandler.video?.muted; + } + /** + * Syncs the video volume slider with the actual video volume. + */ + syncVideoVolumeSlider() { + const overlayView = this.videoHandler.uiManager.votOverlayView; + if (!overlayView?.isInitialized()) return this; + const ariaPercent = isExternalVolumeHost(this.videoHandler.site.host) ? getAriaValueNowPercent(YT_VOLUME_NOW_SELECTOR) : null; + const volumePercent = this.isMuted() ? 0 : ariaPercent ?? volume01ToPercent(this.getVideoVolume() ?? 0); + overlayView.videoVolumeSlider.value = volumePercent; + this.videoHandler.onVideoVolumeSliderSynced?.(volumePercent); + return this; + } + setSelectMenuValues(from, to) { + const videoData = this.videoHandler.videoData; + if (!videoData) return this; + const normalizedFrom = normalizeToRequestLang(from) ?? "auto"; + const langPairLogKey = `${normalizedFrom}->${to}`; + const sharedLanguageState = getSharedLanguageState(videoData.videoId); + if (sharedLanguageState.lastLoggedLangPair !== langPairLogKey) { + console.log(`[VOT] Set translation from ${normalizedFrom} to ${to}`); + sharedLanguageState.lastLoggedLangPair = langPairLogKey; + } + videoData.detectedLanguage = normalizedFrom; + videoData.responseLanguage = to; + this.videoHandler.translateFromLang = normalizedFrom; + this.videoHandler.translateToLang = to; + const overlayView = this.videoHandler.uiManager.votOverlayView; + if (!overlayView?.isInitialized()) return this; + overlayView.languagePairSelect.fromSelect.selectTitle = localizationProvider.getLangLabel(normalizedFrom); + overlayView.languagePairSelect.toSelect.selectTitle = localizationProvider.getLangLabel(to); + overlayView.languagePairSelect.fromSelect.setSelectedValue(normalizedFrom); + overlayView.languagePairSelect.toSelect.setSelectedValue(to); + return this; + } + }, t = globalThis, i = (t) => t, s = t.trustedTypes, e = s ? s.createPolicy("lit-html", { createHTML: (t) => t }) : void 0, h = "$lit$", o = `lit$${Math.random().toFixed(9).slice(2)}$`, n = "?" + o, r = `<${n}>`, l = document, c = () => l.createComment(""), a = (t) => null === t || "object" != typeof t && "function" != typeof t, u = Array.isArray, d = (t) => u(t) || "function" == typeof t?.[Symbol.iterator], f = "[ \n\f\r]", v = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, _ = /-->/g, m = />/g, p = RegExp(`>|${f}(?:([^\\s"'>=/]+)(${f}*=${f}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`, "g"), g = /'/g, $ = /"/g, y = /^(?:script|style|textarea|title)$/i, x = (t) => (i, ...s) => ({ + _$litType$: t, + strings: i, + values: s + }), b = x(1), w = x(2); + x(3); + //#endregion + //#region node_modules/lit-html/lit-html.js + /** + * @license + * Copyright 2017 Google LLC + * SPDX-License-Identifier: BSD-3-Clause + */ + var E = Symbol.for("lit-noChange"), A = Symbol.for("lit-nothing"), C = /* @__PURE__ */ new WeakMap(), P = l.createTreeWalker(l, 129); + function V(t, i) { + if (!u(t) || !t.hasOwnProperty("raw")) throw Error("invalid template strings array"); + return void 0 !== e ? e.createHTML(i) : i; + } + var N = (t, i) => { + const s = t.length - 1, e = []; + let n, l = 2 === i ? "" : 3 === i ? "" : "", c = v; + for (let i = 0; i < s; i++) { + const s = t[i]; + let a, u, d = -1, f = 0; + for (; f < s.length && (c.lastIndex = f, u = c.exec(s), null !== u);) f = c.lastIndex, c === v ? "!--" === u[1] ? c = _ : void 0 !== u[1] ? c = m : void 0 !== u[2] ? (y.test(u[2]) && (n = RegExp("" === u[0] ? (c = n ?? v, d = -1) : void 0 === u[1] ? d = -2 : (d = c.lastIndex - u[2].length, a = u[1], c = void 0 === u[3] ? p : "\"" === u[3] ? $ : g) : c === $ || c === g ? c = p : c === _ || c === m ? c = v : (c = p, n = void 0); + const x = c === p && t[i + 1].startsWith("/>") ? " " : ""; + l += c === v ? s + r : d >= 0 ? (e.push(a), s.slice(0, d) + h + s.slice(d) + o + x) : s + o + (-2 === d ? i : x); + } + return [V(t, l + (t[s] || "") + (2 === i ? "" : 3 === i ? "" : "")), e]; + }; + var S = class S { + constructor({ strings: t, _$litType$: i }, e) { + let r; + this.parts = []; + let l = 0, a = 0; + const u = t.length - 1, d = this.parts, [f, v] = N(t, i); + if (this.el = S.createElement(f, e), P.currentNode = this.el.content, 2 === i || 3 === i) { + const t = this.el.content.firstChild; + t.replaceWith(...t.childNodes); + } + for (; null !== (r = P.nextNode()) && d.length < u;) { + if (1 === r.nodeType) { + if (r.hasAttributes()) for (const t of r.getAttributeNames()) if (t.endsWith(h)) { + const i = v[a++], s = r.getAttribute(t).split(o), e = /([.?@])?(.*)/.exec(i); + d.push({ + type: 1, + index: l, + name: e[2], + strings: s, + ctor: "." === e[1] ? I : "?" === e[1] ? L : "@" === e[1] ? z : H + }), r.removeAttribute(t); + } else t.startsWith(o) && (d.push({ + type: 6, + index: l + }), r.removeAttribute(t)); + if (y.test(r.tagName)) { + const t = r.textContent.split(o), i = t.length - 1; + if (i > 0) { + r.textContent = s ? s.emptyScript : ""; + for (let s = 0; s < i; s++) r.append(t[s], c()), P.nextNode(), d.push({ + type: 2, + index: ++l + }); + r.append(t[i], c()); + } + } + } else if (8 === r.nodeType) if (r.data === n) d.push({ + type: 2, + index: l + }); + else { + let t = -1; + for (; -1 !== (t = r.data.indexOf(o, t + 1));) d.push({ + type: 7, + index: l + }), t += o.length - 1; + } + l++; + } + } + static createElement(t, i) { + const s = l.createElement("template"); + return s.innerHTML = t, s; + } + }; + function M(t, i, s = t, e) { + if (i === E) return i; + let h = void 0 !== e ? s._$Co?.[e] : s._$Cl; + const o = a(i) ? void 0 : i._$litDirective$; + return h?.constructor !== o && (h?._$AO?.(!1), void 0 === o ? h = void 0 : (h = new o(t), h._$AT(t, s, e)), void 0 !== e ? (s._$Co ??= [])[e] = h : s._$Cl = h), void 0 !== h && (i = M(t, h._$AS(t, i.values), h, e)), i; + } + var R = class { + constructor(t, i) { + this._$AV = [], this._$AN = void 0, this._$AD = t, this._$AM = i; + } + get parentNode() { + return this._$AM.parentNode; + } + get _$AU() { + return this._$AM._$AU; + } + u(t) { + const { el: { content: i }, parts: s } = this._$AD, e = (t?.creationScope ?? l).importNode(i, !0); + P.currentNode = e; + let h = P.nextNode(), o = 0, n = 0, r = s[0]; + for (; void 0 !== r;) { + if (o === r.index) { + let i; + 2 === r.type ? i = new k(h, h.nextSibling, this, t) : 1 === r.type ? i = new r.ctor(h, r.name, r.strings, this, t) : 6 === r.type && (i = new Z(h, this, t)), this._$AV.push(i), r = s[++n]; + } + o !== r?.index && (h = P.nextNode(), o++); + } + return P.currentNode = l, e; + } + p(t) { + let i = 0; + for (const s of this._$AV) void 0 !== s && (void 0 !== s.strings ? (s._$AI(t, s, i), i += s.strings.length - 2) : s._$AI(t[i])), i++; + } + }; + var k = class k { + get _$AU() { + return this._$AM?._$AU ?? this._$Cv; + } + constructor(t, i, s, e) { + this.type = 2, this._$AH = A, this._$AN = void 0, this._$AA = t, this._$AB = i, this._$AM = s, this.options = e, this._$Cv = e?.isConnected ?? !0; + } + get parentNode() { + let t = this._$AA.parentNode; + const i = this._$AM; + return void 0 !== i && 11 === t?.nodeType && (t = i.parentNode), t; + } + get startNode() { + return this._$AA; + } + get endNode() { + return this._$AB; + } + _$AI(t, i = this) { + t = M(this, t, i), a(t) ? t === A || null == t || "" === t ? (this._$AH !== A && this._$AR(), this._$AH = A) : t !== this._$AH && t !== E && this._(t) : void 0 !== t._$litType$ ? this.$(t) : void 0 !== t.nodeType ? this.T(t) : d(t) ? this.k(t) : this._(t); + } + O(t) { + return this._$AA.parentNode.insertBefore(t, this._$AB); + } + T(t) { + this._$AH !== t && (this._$AR(), this._$AH = this.O(t)); + } + _(t) { + this._$AH !== A && a(this._$AH) ? this._$AA.nextSibling.data = t : this.T(l.createTextNode(t)), this._$AH = t; + } + $(t) { + const { values: i, _$litType$: s } = t, e = "number" == typeof s ? this._$AC(t) : (void 0 === s.el && (s.el = S.createElement(V(s.h, s.h[0]), this.options)), s); + if (this._$AH?._$AD === e) this._$AH.p(i); + else { + const t = new R(e, this), s = t.u(this.options); + t.p(i), this.T(s), this._$AH = t; + } + } + _$AC(t) { + let i = C.get(t.strings); + return void 0 === i && C.set(t.strings, i = new S(t)), i; + } + k(t) { + u(this._$AH) || (this._$AH = [], this._$AR()); + const i = this._$AH; + let s, e = 0; + for (const h of t) e === i.length ? i.push(s = new k(this.O(c()), this.O(c()), this, this.options)) : s = i[e], s._$AI(h), e++; + e < i.length && (this._$AR(s && s._$AB.nextSibling, e), i.length = e); + } + _$AR(t = this._$AA.nextSibling, s) { + for (this._$AP?.(!1, !0, s); t !== this._$AB;) { + const s = i(t).nextSibling; + i(t).remove(), t = s; + } + } + setConnected(t) { + void 0 === this._$AM && (this._$Cv = t, this._$AP?.(t)); + } + }; + var H = class { + get tagName() { + return this.element.tagName; + } + get _$AU() { + return this._$AM._$AU; + } + constructor(t, i, s, e, h) { + this.type = 1, this._$AH = A, this._$AN = void 0, this.element = t, this.name = i, this._$AM = e, this.options = h, s.length > 2 || "" !== s[0] || "" !== s[1] ? (this._$AH = Array(s.length - 1).fill(/* @__PURE__ */ new String()), this.strings = s) : this._$AH = A; + } + _$AI(t, i = this, s, e) { + const h = this.strings; + let o = !1; + if (void 0 === h) t = M(this, t, i, 0), o = !a(t) || t !== this._$AH && t !== E, o && (this._$AH = t); + else { + const e = t; + let n, r; + for (t = h[0], n = 0; n < h.length - 1; n++) r = M(this, e[s + n], i, n), r === E && (r = this._$AH[n]), o ||= !a(r) || r !== this._$AH[n], r === A ? t = A : t !== A && (t += (r ?? "") + h[n + 1]), this._$AH[n] = r; + } + o && !e && this.j(t); + } + j(t) { + t === A ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t ?? ""); + } + }; + var I = class extends H { + constructor() { + super(...arguments), this.type = 3; + } + j(t) { + this.element[this.name] = t === A ? void 0 : t; + } + }; + var L = class extends H { + constructor() { + super(...arguments), this.type = 4; + } + j(t) { + this.element.toggleAttribute(this.name, !!t && t !== A); + } + }; + var z = class extends H { + constructor(t, i, s, e, h) { + super(t, i, s, e, h), this.type = 5; + } + _$AI(t, i = this) { + if ((t = M(this, t, i, 0) ?? A) === E) return; + const s = this._$AH, e = t === A && s !== A || t.capture !== s.capture || t.once !== s.once || t.passive !== s.passive, h = t !== A && (s === A || e); + e && this.element.removeEventListener(this.name, this, s), h && this.element.addEventListener(this.name, this, t), this._$AH = t; + } + handleEvent(t) { + "function" == typeof this._$AH ? this._$AH.call(this.options?.host ?? this.element, t) : this._$AH.handleEvent(t); + } + }; + var Z = class { + constructor(t, i, s) { + this.element = t, this.type = 6, this._$AN = void 0, this._$AM = i, this.options = s; + } + get _$AU() { + return this._$AM._$AU; + } + _$AI(t) { + M(this, t); + } + }, B = t.litHtmlPolyfillSupport; + B?.(S, k), (t.litHtmlVersions ??= []).push("3.3.2"); + var D = (t, i, s) => { + const e = s?.renderBefore ?? i; + let h = e._$litPart$; + if (void 0 === h) { + const t = s?.renderBefore ?? null; + e._$litPart$ = h = new k(i.insertBefore(c(), t), t, void 0, s ?? {}); + } + return h._$AI(t), h; + }; + //#endregion + //#region src/ui.ts + function initKeyboardNavigationMode() { + if (globalThis.__votKeyboardNavInitialized) return; + globalThis.__votKeyboardNavInitialized = true; + const root = document.documentElement; + const CLASS = "vot-keyboard-nav"; + const enable = () => root.classList.add(CLASS); + const disable = () => root.classList.remove(CLASS); + globalThis.addEventListener("keydown", (e) => { + if (e.key === "Tab") enable(); + }, true); + for (const evt of [ + "pointerdown", + "mousedown", + "touchstart" + ]) globalThis.addEventListener(evt, disable, { + capture: true, + passive: true + }); + } + initKeyboardNavigationMode(); + var UI = { + makeButtonLike(el, { ariaLabel } = {}) { + el.setAttribute("role", "button"); + if (!el.hasAttribute("tabindex")) el.tabIndex = 0; + const enabledTabIndex = el.tabIndex; + const syncDisabledState = () => { + if (el.getAttribute("disabled") === "true") { + el.setAttribute("aria-disabled", "true"); + el.tabIndex = -1; + } else { + el.removeAttribute("aria-disabled"); + el.tabIndex = enabledTabIndex; + } + }; + syncDisabledState(); + new MutationObserver(() => syncDisabledState()).observe(el, { + attributes: true, + attributeFilter: ["disabled"] + }); + if (ariaLabel) el.setAttribute("aria-label", ariaLabel); + el.addEventListener("keydown", (e) => { + if (el.getAttribute("disabled") === "true" || el.getAttribute("aria-disabled") === "true") return; + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + el.click(); + } + }); + return el; + }, + createEl(tag, classes = [], content = null) { + const el = document.createElement(tag); + if (classes.length) el.classList.add(...classes); + if (content !== null) el.append(content); + return el; + }, + createHeader(html, level = 4) { + return UI.createEl("vot-block", ["vot-header", `vot-header-level-${level}`], html); + }, + createInformation(labelHtml, valueHtml) { + const container = UI.createEl("vot-block", ["vot-info"]); + const header = UI.createEl("vot-block"); + D(labelHtml, header); + const value = UI.createEl("vot-block"); + D(valueHtml, value); + container.append(header, value); + return { + container, + header, + value + }; + }, + createButton(html) { + const el = UI.createEl("vot-block", ["vot-button"], html); + return UI.makeButtonLike(el); + }, + createTextButton(html) { + const el = UI.createEl("vot-block", ["vot-text-button"], html); + return UI.makeButtonLike(el); + }, + createOutlinedButton(html) { + const el = UI.createEl("vot-block", ["vot-outlined-button"], html); + return UI.makeButtonLike(el); + }, + createIconButton(templateHtml, options = {}) { + const button = UI.createEl("vot-block", ["vot-icon-button"]); + D(templateHtml, button); + return UI.makeButtonLike(button, options); + }, + createInlineLoader() { + return UI.createEl("vot-block", ["vot-inline-loader"]); + }, + createPortal(local = false) { + return UI.createEl("vot-block", [`vot-portal${local ? "-local" : ""}`]); + }, + createSubtitleInfo(word, desc, translationService) { + const container = UI.createEl("vot-block", ["vot-subtitles-info"]); + container.id = "vot-subtitles-info"; + const translatedWith = UI.createEl("vot-block", ["vot-subtitles-info-service"], localizationProvider.get("VOTTranslatedBy").replace("{0}", translationService)); + const header = UI.createEl("vot-block", ["vot-subtitles-info-header"], word); + const context = UI.createEl("vot-block", ["vot-subtitles-info-context"], desc); + container.append(translatedWith, header, context); + return { + container, + translatedWith, + header, + context + }; + } + }; + //#endregion + //#region src/types/components/tooltip.ts + var positions$1 = [ + "left", + "top", + "right", + "bottom" + ]; + var triggers = ["hover", "click"]; + //#endregion + //#region src/ui/components/tooltip.ts + var Tooltip = class Tooltip { + /** Whether tooltip element is currently mounted. */ + showed = false; + target; + anchor; + content; + position; + preferredPosition; + trigger; + parentElement; + layoutRoot; + offsetX; + offsetY; + _hidden; + autoLayout; + pageWidth; + pageHeight; + globalOffsetX; + globalOffsetY; + renderOffsetX; + renderOffsetY; + maxWidth; + backgroundColor; + borderRadius; + _bordered; + container; + onResizeObserver; + intersectionObserver; + scrollListening = false; + positionRafId = null; + destroyFallbackTimerId; + static DESTROY_FALLBACK_MS = 700; + tooltipId = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `vot-tooltip-${Math.random().toString(36).slice(2)}`; + prevAriaDescribedBy = null; + constructor({ target, anchor = void 0, content = "", position = "top", trigger = "hover", offset = 4, maxWidth = void 0, hidden = false, autoLayout = true, backgroundColor = void 0, borderRadius = void 0, bordered = true, parentElement = document.body, layoutRoot = document.documentElement }) { + if (!(target instanceof HTMLElement)) throw new TypeError("target must be a valid HTMLElement"); + this.target = target; + this.anchor = anchor instanceof HTMLElement ? anchor : target; + this.content = content; + if (typeof offset === "number") this.offsetY = this.offsetX = offset; + else { + this.offsetX = offset.x; + this.offsetY = offset.y; + } + this._hidden = hidden; + this.autoLayout = autoLayout; + this.trigger = Tooltip.validateTrigger(trigger) ? trigger : "hover"; + this.position = Tooltip.validatePos(position) ? position : "top"; + this.preferredPosition = this.position; + this.parentElement = parentElement; + this.layoutRoot = layoutRoot; + this.borderRadius = borderRadius; + this._bordered = bordered; + this.maxWidth = maxWidth; + this.backgroundColor = backgroundColor; + this.updatePageSize(); + this.init(); + } + static validatePos(position) { + return positions$1.includes(position); + } + static validateTrigger(trigger) { + return triggers.includes(trigger); + } + setPosition(position) { + this.preferredPosition = Tooltip.validatePos(position) ? position : "top"; + this.position = this.preferredPosition; + this.schedulePositionUpdate(); + return this; + } + setContent(content) { + this.content = content; + if (this.container) { + this.container.replaceChildren(); + if (typeof content === "string") this.container.textContent = content; + else this.container.append(content); + this.schedulePositionUpdate(); + return this; + } + return this; + } + /** + * Update tooltip mount dependencies. + * If the tooltip is currently rendered, it will be moved to the new parent. + */ + updateMount({ parentElement, layoutRoot }) { + if (parentElement && this.parentElement !== parentElement) { + this.parentElement = parentElement; + if (this.container?.isConnected) parentElement.appendChild(this.container); + } + if (layoutRoot && this.layoutRoot !== layoutRoot) this.layoutRoot = layoutRoot; + this.schedulePositionUpdate(); + return this; + } + onResize = () => { + this.schedulePositionUpdate(); + }; + onClick = () => { + this.showed ? this.destroy() : this.create(); + }; + onTargetKeyDown = (event) => { + if (event.key !== "Escape" || !this.showed) return; + this.destroy(); + }; + onScroll = () => { + this.schedulePositionUpdate(); + }; + onHoverPointerDown = (e) => { + if (e.pointerType === "mouse") return; + this.create(); + }; + onHoverPointerUp = (e) => { + if (e.pointerType === "mouse") return; + this.destroy(); + }; + onMouseEnter = () => { + this.create(); + }; + onMouseLeave = (event) => { + if (this.isInTooltipContext(event.relatedTarget)) return; + this.destroy(); + }; + onTooltipMouseLeave = (event) => { + if (this.isInTooltipContext(event.relatedTarget)) return; + this.destroy(); + }; + isInTooltipContext(nextTarget) { + if (!(nextTarget instanceof Node)) return false; + return this.target.contains(nextTarget) || this.container?.contains(nextTarget); + } + updatePageSize() { + if (this.layoutRoot === document.documentElement) { + this.globalOffsetX = 0; + this.globalOffsetY = 0; + } else { + const { left, top } = this.layoutRoot.getBoundingClientRect(); + this.globalOffsetX = left; + this.globalOffsetY = top; + } + const { left: parentLeft, top: parentTop } = this.parentElement.getBoundingClientRect(); + this.renderOffsetX = parentLeft; + this.renderOffsetY = parentTop; + this.pageWidth = this.layoutRoot.clientWidth || document.documentElement.clientWidth; + this.pageHeight = this.layoutRoot.clientHeight || document.documentElement.clientHeight; + return this; + } + onIntersect = ([entry]) => { + if (!entry.isIntersecting) return this.destroy(true); + }; + init() { + this.onResizeObserver = new ResizeObserver(this.onResize); + this.intersectionObserver = new IntersectionObserver(this.onIntersect); + this.target.addEventListener("keydown", this.onTargetKeyDown); + if (this.trigger === "click") { + this.target.addEventListener("pointerdown", this.onClick); + return this; + } + this.target.addEventListener("mouseenter", this.onMouseEnter); + this.target.addEventListener("mouseleave", this.onMouseLeave); + this.target.addEventListener("focusin", this.onMouseEnter); + this.target.addEventListener("focusout", this.onMouseLeave); + this.target.addEventListener("pointerdown", this.onHoverPointerDown); + this.target.addEventListener("pointerup", this.onHoverPointerUp); + return this; + } + release() { + this.destroy(true); + this.detachScrollListener(); + this.target.removeEventListener("keydown", this.onTargetKeyDown); + if (this.trigger === "click") { + this.target.removeEventListener("pointerdown", this.onClick); + return this; + } + this.target.removeEventListener("mouseenter", this.onMouseEnter); + this.target.removeEventListener("mouseleave", this.onMouseLeave); + this.target.removeEventListener("focusin", this.onMouseEnter); + this.target.removeEventListener("focusout", this.onMouseLeave); + this.target.removeEventListener("pointerdown", this.onHoverPointerDown); + this.target.removeEventListener("pointerup", this.onHoverPointerUp); + return this; + } + schedulePositionUpdate() { + if (!this.container) return; + if (this.positionRafId !== null) return; + this.positionRafId = requestAnimationFrame(() => { + this.positionRafId = null; + this.updatePageSize(); + this.updatePos(); + }); + } + cancelPositionUpdate() { + if (this.positionRafId === null) return; + cancelAnimationFrame(this.positionRafId); + this.positionRafId = null; + } + clearDestroyFallbackTimer() { + if (this.destroyFallbackTimerId === void 0) return; + globalThis.clearTimeout(this.destroyFallbackTimerId); + this.destroyFallbackTimerId = void 0; + } + create() { + this.destroy(true); + this.showed = true; + this.container = UI.createEl("vot-block", ["vot-tooltip"], this.content); + if (this.bordered) this.container.classList.add("vot-tooltip-bordered"); + this.container.setAttribute("role", "tooltip"); + this.container.id = this.tooltipId; + this.container.dataset.trigger = this.trigger; + this.container.dataset.position = this.position; + this.parentElement.appendChild(this.container); + this.schedulePositionUpdate(); + if (this.backgroundColor !== void 0) this.container.style.backgroundColor = this.backgroundColor; + if (this.borderRadius !== void 0) this.container.style.borderRadius = `${this.borderRadius}px`; + if (this.hidden) this.container.hidden = true; + else this.syncAriaDescribedBy(true); + this.container.style.opacity = "1"; + if (this.trigger === "hover") this.container.addEventListener("mouseleave", this.onTooltipMouseLeave); + this.attachScrollListener(); + this.onResizeObserver?.observe(this.layoutRoot); + if (this.anchor !== this.layoutRoot) this.onResizeObserver?.observe(this.anchor); + this.intersectionObserver?.observe(this.target); + return this; + } + updatePos() { + if (!this.container) return this; + const { top, left } = this.calcPos(this.autoLayout, this.preferredPosition); + const availableWidth = Math.max(0, this.pageWidth - this.offsetX * 2); + const maxWidth = clamp(this.maxWidth ?? availableWidth, 0, availableWidth); + this.container.style.transform = `translate(${left}px, ${top}px)`; + this.container.dataset.position = this.position; + this.container.style.maxWidth = `${maxWidth}px`; + return this; + } + calcPos(autoLayout = true, position = this.preferredPosition) { + if (!this.container) return { + top: 0, + left: 0 + }; + const { left: anchorLeft, right: anchorRight, top: anchorTop, bottom: anchorBottom, width: anchorWidth, height: anchorHeight } = this.anchor.getBoundingClientRect(); + const { width: containerWidth, height: containerHeight } = this.container.getBoundingClientRect(); + const width = clamp(containerWidth, 0, this.pageWidth); + const height = clamp(containerHeight, 0, this.pageHeight); + const anchorBox = { + left: anchorLeft - this.globalOffsetX, + right: anchorRight - this.globalOffsetX, + top: anchorTop - this.globalOffsetY, + bottom: anchorBottom - this.globalOffsetY, + anchorWidth, + anchorHeight + }; + const size = { + width, + height + }; + const resolvedPosition = this.resolveTooltipPosition(anchorBox, size, position, autoLayout); + const coords = this.getTooltipCoordinates(anchorBox, size, resolvedPosition); + this.position = resolvedPosition; + return { + top: coords.top + this.globalOffsetY - this.renderOffsetY, + left: coords.left + this.globalOffsetX - this.renderOffsetX + }; + } + resolveTooltipPosition(anchorBox, size, position, autoLayout) { + if (!autoLayout) return position; + switch (position) { + case "top": return clamp(anchorBox.top - size.height - this.offsetY, 0, this.pageHeight) + this.offsetY < size.height ? "bottom" : "top"; + case "right": return clamp(anchorBox.right + this.offsetX, 0, this.pageWidth - size.width) + size.width > this.pageWidth - this.offsetX ? "left" : "right"; + case "bottom": return clamp(anchorBox.bottom + this.offsetY, 0, this.pageHeight - size.height) + size.height > this.pageHeight - this.offsetY ? "top" : "bottom"; + case "left": return Math.max(0, anchorBox.left - size.width - this.offsetX) + size.width > anchorBox.left - this.offsetX ? "right" : "left"; + default: return position; + } + } + getTooltipCoordinates(anchorBox, size, position) { + switch (position) { + case "top": return { + top: clamp(anchorBox.top - size.height - this.offsetY, 0, this.pageHeight), + left: clamp(anchorBox.left - size.width / 2 + anchorBox.anchorWidth / 2, this.offsetX, this.pageWidth - size.width - this.offsetX) + }; + case "right": return { + top: clamp(anchorBox.top + (anchorBox.anchorHeight - size.height) / 2, this.offsetY, this.pageHeight - size.height - this.offsetY), + left: clamp(anchorBox.right + this.offsetX, 0, this.pageWidth - size.width) + }; + case "bottom": return { + top: clamp(anchorBox.bottom + this.offsetY, 0, this.pageHeight - size.height), + left: clamp(anchorBox.left - size.width / 2 + anchorBox.anchorWidth / 2, this.offsetX, this.pageWidth - size.width - this.offsetX) + }; + case "left": return { + top: clamp(anchorBox.top + (anchorBox.anchorHeight - size.height) / 2, this.offsetY, this.pageHeight - size.height - this.offsetY), + left: Math.max(0, anchorBox.left - size.width - this.offsetX) + }; + default: return { + top: 0, + left: 0 + }; + } + } + destroy(instant = false) { + if (!this.container) return this; + const container = this.container; + this.cancelPositionUpdate(); + this.clearDestroyFallbackTimer(); + this.showed = false; + this.syncAriaDescribedBy(false); + this.onResizeObserver?.disconnect(); + this.intersectionObserver?.disconnect(); + this.detachScrollListener(); + if (instant) { + container.remove(); + this.container = void 0; + return this; + } + container.removeEventListener("mouseleave", this.onTooltipMouseLeave); + container.style.pointerEvents = "none"; + container.style.opacity = "0"; + const handleTransitionDone = () => { + this.clearDestroyFallbackTimer(); + container?.remove(); + if (this.container === container) this.container = void 0; + }; + container.addEventListener("transitionend", handleTransitionDone, { once: true }); + container.addEventListener("transitioncancel", handleTransitionDone, { once: true }); + this.destroyFallbackTimerId = globalThis.setTimeout(handleTransitionDone, Tooltip.DESTROY_FALLBACK_MS); + return this; + } + syncAriaDescribedBy(isShowing) { + const existing = this.target.getAttribute("aria-describedby"); + this.prevAriaDescribedBy ??= existing; + if (!isShowing) { + if (this.prevAriaDescribedBy === null) this.target.removeAttribute("aria-describedby"); + else this.target.setAttribute("aria-describedby", this.prevAriaDescribedBy); + this.prevAriaDescribedBy = null; + return; + } + const tokens = new Set((existing ?? "").split(/\s+/).filter(Boolean)); + tokens.add(this.tooltipId); + this.target.setAttribute("aria-describedby", Array.from(tokens).join(" ")); + } + set bordered(isBordered) { + this._bordered = isBordered; + this.container?.classList.toggle("vot-tooltip-bordered", isBordered); + } + get bordered() { + return this._bordered; + } + set hidden(isHidden) { + this._hidden = isHidden; + if (this.container) this.container.hidden = isHidden; + if (this.showed) this.syncAriaDescribedBy(!isHidden); + } + get hidden() { + return this._hidden; + } + attachScrollListener() { + if (this.scrollListening) return; + this.scrollListening = true; + document.addEventListener("scroll", this.onScroll, { + passive: true, + capture: true + }); + } + detachScrollListener() { + if (!this.scrollListening) return; + this.scrollListening = false; + document.removeEventListener("scroll", this.onScroll, { capture: true }); + } + }; + //#endregion + //#region src/ui/shadowMount.ts + var shadowScopedCssText = scopeCssForShadowRoots(".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));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-ontheme));background-color:rgb(var(--vot-helper-theme));box-shadow:var(--vot-shadow-1);transition:box-shadow var(--vot-duration-medium) var(--vot-easing-standard);outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-4)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;border:none!important;font-weight:500!important}.vot-button:before,.vot-button:after{content:\"\";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-button:before{background-color:rgb(var(--vot-helper-ontheme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-button:hover:before{opacity:.08}.vot-button:active:after{opacity:.32;background-size:100% 100%;transition:background-size}.vot-button:hover,.vot-button:active{box-shadow:var(--vot-shadow-2)}.vot-button[disabled=true]{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .12);color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);box-shadow:none;cursor:initial}.vot-button[disabled=true]:before,.vot-button[disabled=true]:after{opacity:0}.vot-outlined-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-theme));background-color:#0000;outline:none;font-size:14px;line-height:34px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-4)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;border:solid 1px var(--vot-border-color)!important;margin:0!important;font-weight:500!important}.vot-outlined-button:before,.vot-outlined-button:after{content:\"\";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-outlined-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-outlined-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-outlined-button:hover:before{opacity:.04}.vot-outlined-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-outlined-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-outlined-button[disabled=true]:before,.vot-outlined-button[disabled=true]:after{opacity:0}.vot-text-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;min-width:64px;height:36px;color:rgb(var(--vot-helper-theme));background-color:#0000;outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-2)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;border:none!important;margin:0!important;font-weight:500!important}.vot-text-button:before,.vot-text-button:after{content:\"\";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-text-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-text-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-text-button:hover:before{opacity:.04}.vot-text-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-text-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-text-button[disabled=true]:before,.vot-text-button[disabled=true]:after{opacity:0}.vot-icon-button{--vot-helper-onsurface:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;width:36px;min-width:36px;height:36px;fill:var(--vot-helper-onsurface);color:var(--vot-helper-onsurface);background-color:#0000;outline:none;font-size:14px;line-height:36px;display:inline-block;position:relative;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;border:none!important;border-radius:50%!important;margin:0!important;padding:0!important;font-weight:500!important}.vot-icon-button:before,.vot-icon-button:after{content:\"\";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-icon-button:before{background-color:var(--vot-helper-onsurface);transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-icon-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-icon-button:hover:before{opacity:.04}.vot-icon-button:active:after{opacity:.32;background-size:100% 100%;transition:background-size}.vot-icon-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);fill:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-icon-button[disabled=true]:before,.vot-icon-button[disabled=true]:after{opacity:0}.vot-icon-button svg{fill:inherit;stroke:inherit;width:24px;height:36px}.vot-hotkey{justify-content:flex-start;align-items:center;gap:var(--vot-space-3,12px);flex-wrap:wrap;display:flex}.vot-hotkey-label{word-break:break-word;max-width:80%}.vot-hotkey-button{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));box-sizing:border-box;vertical-align:middle;text-align:center;text-overflow:ellipsis;cursor:pointer;background-color:#0000;outline:none;width:fit-content;min-width:32px;height:fit-content;font-size:15px;line-height:1.5;display:inline-block;position:relative;border-radius:var(--vot-radius-s)!important;padding:0 var(--vot-space-2)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;border:solid 1px var(--vot-border-color)!important;margin:0!important;font-weight:400!important}.vot-hotkey-button:before,.vot-hotkey-button:after{content:\"\";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-hotkey-button:before{background-color:rgb(var(--vot-helper-theme));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-hotkey-button:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.vot-hotkey-button:hover:before{opacity:.04}.vot-hotkey-button:active:after{opacity:.16;background-size:100% 100%;transition:background-size}.vot-hotkey-button[data-status=active]{color:rgb(var(--vot-helper-theme))}.vot-hotkey-button[data-status=active]:before{opacity:.04}.vot-hotkey-button[disabled=true]{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial;background-color:#0000}.vot-hotkey-button[disabled=true]:before,.vot-hotkey-button[disabled=true]:after{opacity:0}.vot-textfield{display:inline-block;--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), .38)!important;--vot-helper-safari2:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;--vot-helper-safari3:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;text-align:start!important;padding-top:6px!important;font-size:16px!important;line-height:1.5!important;position:relative!important}.vot-textfield>:is(input,textarea){box-sizing:border-box!important;border-style:solid!important;border-width:1px!important;border-color:transparent var(--vot-helper-safari2) var(--vot-helper-safari2)!important;width:100%!important;height:inherit!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;-webkit-text-fill-color:currentColor!important;font-family:inherit!important;font-size:inherit!important;line-height:inherit!important;caret-color:var(--vot-helper-theme)!important;background-color:#0000!important;border-radius:4px!important;margin:0!important;padding:15px 13px!important;transition:border .2s,box-shadow .2s!important;box-shadow:inset 1px 0 #0000,inset -1px 0 #0000,inset 0 -1px #0000!important}.vot-textfield>:is(input,textarea):not(:focus):not(:is(.vot-show-placeholder,.vot-show-placeholer))::placeholder{color:#0000!important}.vot-textfield>:is(input,textarea):not(:focus):placeholder-shown{border-top-color:var(--vot-helper-safari2)!important}.vot-textfield>:is(input,textarea)+span{font-family:inherit;width:100%!important;max-height:100%!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;cursor:text!important;pointer-events:none!important;font-size:75%!important;line-height:15px!important;transition:color .2s,font-size .2s,line-height .2s!important;display:flex!important;position:absolute!important;top:0!important;left:0!important}.vot-textfield>:is(input,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;box-sizing:border-box!important;border-top:solid 1px var(--vot-helper-safari2)!important;pointer-events:none!important;min-width:10px!important;height:8px!important;margin-top:6px!important;transition:border .2s,box-shadow .2s!important;display:block!important;box-shadow:inset 0 1px #0000!important}.vot-textfield>input+span:before,.vot-textfield>textarea+span:before{border-left:1px solid #0000!important;border-radius:4px 0!important;margin-right:4px!important}.vot-textfield>input+span:after,.vot-textfield>textarea+span:after{border-right:1px solid #0000!important;border-radius:0 4px!important;flex-grow:1!important;margin-left:4px!important}.vot-textfield>input:is(.vot-show-placeholder,.vot-show-placeholer)+span:before,.vot-textfield>textarea:is(.vot-show-placeholder,.vot-show-placeholer)+span:before{margin-right:0!important}.vot-textfield>input:is(.vot-show-placeholder,.vot-show-placeholer)+span:after,.vot-textfield>textarea:is(.vot-show-placeholder,.vot-show-placeholer)+span:after{margin-left:0!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:#0000!important}.vot-textfield:hover>input:not(:disabled),.vot-textfield:hover>textarea:not(:disabled){border-color:transparent var(--vot-helper-safari3) var(--vot-helper-safari3)!important}.vot-textfield:hover>input:not(:disabled)+span:before,.vot-textfield:hover>input:not(:disabled)+span:after,.vot-textfield:hover>textarea:not(:disabled)+span:before,.vot-textfield:hover>textarea:not(:disabled)+span:after{border-top-color:var(--vot-helper-safari3)!important}.vot-textfield:hover>input:not(:disabled):not(:focus):placeholder-shown,.vot-textfield:hover>textarea:not(:disabled):not(:focus):placeholder-shown{border-color:var(--vot-helper-safari3)!important}.vot-textfield>input:focus,.vot-textfield>textarea:focus{border-color:transparent 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:transparent var(--vot-helper-safari1) var(--vot-helper-safari1)!important;color:rgba(var(--vot-onsurface-rgb,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,.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:#0000!important}@media not all and (resolution>=.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-checkbox-label-offset:30px;--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;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);text-align:start;font-size:16px;line-height:1.5;display:inline-block;position:relative;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;text-transform:none!important}.vot-checkbox-sub{padding-left:var(--vot-checkbox-label-offset)!important}.vot-checkbox>input{appearance:none;z-index:10000;box-sizing:border-box;opacity:1;cursor:pointer;background:0 0;outline:none;width:18px;height:18px;transition:border-color .2s,background-color .2s;display:block;position:absolute;border:2px solid!important;border-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6)!important;border-radius:2px!important;margin:3px 1px!important;padding:0!important}.vot-checkbox>input+span{box-sizing:border-box;width:inherit;cursor:pointer;font-family:inherit;display:inline-block;position:relative;padding-left:var(--vot-checkbox-label-offset)!important;font-weight:400!important}.vot-checkbox>input+span:before{content:\"\";background-color:rgb(var(--vot-onsurface-rgb,0, 0, 0));opacity:0;pointer-events:none;width:40px;height:40px;transition:opacity .3s,transform .2s;display:block;position:absolute;top:-8px;left:-10px;transform:scale(1);border-radius:50%!important}.vot-checkbox>input+span:after{content:\"\";z-index:10000;pointer-events:none;width:10px;height:5px;transition:border-color .2s;display:block;position:absolute;top:3px;left:1px;transform:translate(3px,4px)rotate(-45deg);box-sizing:content-box!important;border:0 solid #0000!important;border-width:0 0 2px 2px!important}.vot-checkbox>input:checked,.vot-checkbox>input:indeterminate{background-color:rgb(var(--vot-helper-theme));border-color:rgb(var(--vot-helper-theme))!important}.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))!important}.vot-checkbox>input:hover{box-shadow:none!important}.vot-checkbox>input:indeterminate+span:after{transform:translate(4px,3px);border-left-width:0!important}.vot-checkbox:hover>input+span:before{opacity:.04}.vot-checkbox:active>input,.vot-checkbox:active:hover>input:not(:disabled){border-color:rgb(var(--vot-helper-theme))!important}.vot-checkbox:active>input:checked{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6);border-color:#0000!important}.vot-checkbox:active>input+span:before{opacity:1;transition:transform,opacity;transform:scale(0)}.vot-checkbox>input:disabled{cursor:initial;border-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-checkbox>input:disabled:checked,.vot-checkbox>input:disabled:indeterminate{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);border-color:#0000!important}.vot-checkbox>input:disabled+span{color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38);cursor:initial}.vot-checkbox>input:disabled+span:before{opacity:0;transform:scale(0)}html.vot-keyboard-nav .vot-checkbox>input:focus-visible{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav .vot-checkbox>input:focus{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}}.vot-slider{flex-direction:column;gap:6px;display:flex;width:100%!important;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", BlinkMacSystemFont, system-ui, -apple-system)!important;text-align:start!important;font-size:16px!important;line-height:1.5!important}.vot-slider>span{order:1;margin:0!important;display:block!important}.vot-slider .vot-slider-label{flex-wrap:wrap;align-items:baseline;gap:6px;width:100%;display:inline-flex}.vot-slider-label-value{font-variant-numeric:tabular-nums;margin-left:0!important;font-weight:500!important}.vot-slider .vot-slider-label-text{min-width:0}.vot-slider>input{order:2;appearance:none!important;cursor:pointer!important;background-color:#0000!important;border:none!important;width:100%!important;height:32px!important;margin:0!important;padding:0!important;display:block!important;position:relative!important;top:0!important}.vot-slider>input:hover{box-shadow:none!important}.vot-slider>input:before{content:\"\"!important;width:calc(100% * var(--vot-progress,0))!important;background:rgb(var(--vot-primary-rgb,33, 150, 243))!important;height:2px!important;display:block!important;position:absolute!important;top:calc(50% - 1px)!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), .38)!important}.vot-slider>input:disabled::-webkit-slider-runnable-track{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-slider>input:disabled::-moz-range-track{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)!important}.vot-slider>input:disabled::-webkit-slider-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)!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)!important}.vot-slider>input:disabled::-moz-range-progress{background-color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87)!important}.vot-slider>input:focus{outline:none!important}.vot-slider>input::-webkit-slider-runnable-track{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important;border-radius:1px!important;width:100%!important;height:2px!important;margin:15px 0!important}.vot-slider>input::-moz-range-track{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important;border-radius:1px!important;width:100%!important;height:2px!important;margin:15px 0!important}.vot-slider>input::-webkit-slider-thumb{appearance:none!important;background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;width:2px!important;height:2px!important;box-shadow:none!important;border:none!important;border-radius:50%!important;transition:box-shadow .2s!important;transform:scale(6)!important}.vot-slider>input::-moz-range-thumb{appearance:none!important;background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;width:2px!important;height:2px!important;box-shadow:none!important;border:none!important;border-radius:50%!important;transition:box-shadow .2s!important;transform:scale(6)!important}.vot-slider>input::-webkit-slider-thumb{-webkit-appearance:none!important;margin:0!important}.vot-slider>input::-moz-range-progress{background-color:rgb(var(--vot-primary-rgb,33, 150, 243))!important;border-radius:1px!important;height:2px!important}.vot-slider>input:focus:not(:focus-visible)::-webkit-slider-thumb{box-shadow:none!important}.vot-slider>input:focus:not(:focus-visible)::-moz-range-thumb{box-shadow:none!important}html.vot-keyboard-nav .vot-slider>input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}html.vot-keyboard-nav .vot-slider>input:focus-visible::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav .vot-slider>input:focus::-webkit-slider-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}html.vot-keyboard-nav .vot-slider>input:focus::-moz-range-thumb{box-shadow:0 0 0 2px rgba(var(--vot-primary-rgb,33, 150, 243), .24)!important}}.vot-select{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);--vot-helper-safari1:rgba(var(--vot-onsurface-rgb,0, 0, 0), .6);--vot-helper-safari2:rgba(var(--vot-onsurface-rgb,0, 0, 0), .87);font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif);text-align:start;color:var(--vot-helper-theme);fill:var(--vot-helper-theme);justify-content:space-between;align-items:center;font-size:14px;line-height:1.5;display:flex;font-weight:400!important}.vot-select-outer{cursor:pointer;justify-content:space-between;align-items:center;width:120px;max-width:120px;display:flex;border:1px solid var(--vot-helper-safari1)!important;border-radius:4px!important;padding:0 5px!important;transition:border .2s!important}.vot-select-outer:hover{border-color:var(--vot-helper-safari2)!important}.vot-select-outer[disabled=true]{opacity:.5;cursor:default}.vot-select-outer[disabled=true]:hover{border-color:var(--vot-helper-safari1)!important}.vot-select-title{text-overflow:ellipsis;white-space:nowrap;font-family:inherit;overflow:hidden}.vot-select-arrow-icon{justify-content:center;align-items:center;width:20px;height:32px;display:flex}.vot-select-arrow-icon svg{fill:inherit;stroke:inherit}.vot-select-content-list{flex-direction:column;display:flex}.vot-select-content-list .vot-select-content-item{cursor:pointer;border-radius:8px!important;padding:5px 10px!important}.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), .2)}.vot-select-content-list .vot-select-content-item[data-vot-selected=true]:hover{background-color:rgba(var(--vot-primary-rgb,33, 150, 243), .1)!important}.vot-select-content-list .vot-select-content-item[inert]{cursor:default;color:rgba(var(--vot-onsurface-rgb,0, 0, 0), .38)}.vot-header{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif);text-align:start;line-height:1.5;font-weight:700!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{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif);text-align:start;-webkit-user-select:text;user-select:text;font-size:16px;line-height:1.5;display:flex}.vot-info>:not(:first-child){color:rgba(var(--vot-helper-onsurface-rgb), .5);flex:1;margin-left:8px!important}.vot-details{color:rgba(var(--vot-helper-onsurface-rgb), .87);font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif);text-align:start;cursor:pointer;transition:background var(--vot-duration-medium) var(--vot-easing-standard);justify-content:space-between;align-items:center;font-size:16px;line-height:1.5;display:flex;border-radius:.5em!important;margin:-.5em!important;padding:.5em!important}.vot-details-arrow-icon{width:20px;height:32px;fill:rgba(var(--vot-helper-onsurface-rgb), .87);justify-content:center;align-items:center;display:flex;transform:scale(1.25)rotate(-90deg)}.vot-details:hover{background:rgba(var(--vot-onsurface-rgb,0, 0, 0), .06)}.vot-settings-section{border:1px solid var(--vot-border-color);border-radius:var(--vot-radius-l);padding:var(--vot-space-2);background:rgba(var(--vot-helper-onsurface-rgb), .03);flex-direction:column;display:flex}.vot-settings-section>*{margin:0!important}.vot-settings-section>*+*{margin-top:var(--vot-space-2)!important}.vot-settings-section-header{border-radius:var(--vot-radius-m);margin:0!important;padding:.45em .5em!important}.vot-settings-section-header .vot-details-arrow-icon{transition:transform var(--vot-duration-medium) var(--vot-easing-standard)}.vot-settings-section-header[data-open=true] .vot-details-arrow-icon{transform:scale(1.25)rotate(0)}.vot-settings-section-content{--vot-settings-control-width:200px;--vot-settings-row-gap:var(--vot-space-2);padding:0 var(--vot-space-1) var(--vot-space-1);flex-direction:column;display:flex}.vot-settings-section-content>*{margin:0!important}.vot-settings-section-content>*+*{margin-top:var(--vot-settings-row-gap)!important}.vot-settings-section-content>.vot-checkbox,.vot-settings-section-content>.vot-hotkey,.vot-settings-section-content>.vot-textfield,.vot-settings-section-content>.vot-select,.vot-settings-section-content>.vot-slider{padding:var(--vot-space-1);box-sizing:border-box;width:100%!important}.vot-settings-section-content>.vot-textfield{gap:var(--vot-space-1);flex-direction:column;padding-top:0!important;display:flex!important}.vot-settings-section-content>.vot-textfield>span{order:0;width:auto!important;max-height:none!important;color:rgba(var(--vot-helper-onsurface-rgb), .72)!important;cursor:default!important;pointer-events:none!important;font-size:13px!important;line-height:1.2!important;display:block!important;position:static!important}.vot-settings-section-content>.vot-textfield>span:before,.vot-settings-section-content>.vot-textfield>span:after{content:none!important;display:none!important}.vot-settings-section-content>.vot-textfield>input,.vot-settings-section-content>.vot-textfield>textarea{transition:border-color var(--vot-duration-fast) var(--vot-easing-standard), background-color var(--vot-duration-fast) var(--vot-easing-standard);order:1;width:100%!important;height:36px!important;padding:0 var(--vot-space-3)!important;border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-s)!important;background:rgba(var(--vot-helper-onsurface-rgb), .04)!important;color:rgba(var(--vot-helper-onsurface-rgb), .9)!important;-webkit-text-fill-color:currentColor!important;box-shadow:none!important}.vot-settings-section-content>.vot-textfield>textarea{resize:vertical;height:auto!important;min-height:84px!important;padding:var(--vot-space-2) var(--vot-space-3)!important}.vot-settings-section-content>.vot-textfield>input::placeholder,.vot-settings-section-content>.vot-textfield>textarea::placeholder{color:rgba(var(--vot-helper-onsurface-rgb), .55)!important}.vot-settings-section-content>.vot-textfield:hover>input,.vot-settings-section-content>.vot-textfield:hover>textarea{border-color:var(--vot-border-color-hover)!important}.vot-settings-section-content>.vot-textfield>input:not(:focus):placeholder-shown,.vot-settings-section-content>.vot-textfield>textarea:not(:focus):placeholder-shown{border-color:var(--vot-border-color)!important}.vot-settings-section-content>.vot-textfield>input:focus,.vot-settings-section-content>.vot-textfield>textarea:focus{border-color:rgba(var(--vot-primary-rgb), .7)!important}.vot-lang-select{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);color:var(--vot-helper-theme);fill:var(--vot-helper-theme);justify-content:space-between;align-items:center;display:flex}.vot-lang-select-icon{justify-content:center;align-items:center;width:32px;height:32px;display:flex}.vot-lang-select-icon svg{fill:inherit;stroke:inherit}.vot-segmented-button{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);-webkit-user-select:none;user-select:none;background:rgb(var(--vot-surface-rgb,255, 255, 255));max-width:100vw;height:36px;color:var(--vot-helper-theme);fill:var(--vot-helper-theme);cursor:default;transition:opacity var(--vot-duration-slow) var(--vot-easing-standard);z-index:2147483647;align-items:center;font-size:16px;line-height:1.5;display:flex;position:absolute;top:5rem;left:50%;overflow:hidden;transform:translate(-50%);opacity:1!important;pointer-events:auto!important;touch-action:none!important;border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-s)!important;box-shadow:var(--vot-shadow-1)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important}.vot-segmented-button.vot-segmented-button--hidden{opacity:0!important;pointer-events:none!important}.vot-segmented-button *{box-sizing:border-box!important}.vot-segmented-button .vot-separator{background:rgba(var(--vot-helper-theme-rgb), .1);width:1px;height:50%}.vot-segmented-button .vot-segment,.vot-segmented-button .vot-segment-only-icon{height:100%;color:inherit;transition:background-color var(--vot-duration-fast) var(--vot-easing-standard);-webkit-tap-highlight-color:transparent;background-color:#0000;outline:none;justify-content:center;align-items:center;display:flex;position:relative;overflow:hidden;padding:0 var(--vot-space-2)!important;border:none!important}.vot-segmented-button .vot-segment:focus,.vot-segmented-button .vot-segment-only-icon:focus{box-shadow:inset 0 0 0 2px var(--vot-focus-ring-color);outline:none}.vot-segmented-button .vot-segment:focus:not(:focus-visible),.vot-segmented-button .vot-segment-only-icon:focus:not(:focus-visible){box-shadow:none}.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:\"\";opacity:0;position:absolute;inset:0;border-radius:inherit!important}.vot-segmented-button .vot-segment:before,.vot-segmented-button .vot-segment-only-icon:before{background-color:rgb(var(--vot-helper-theme-rgb));transition:opacity var(--vot-duration-medium) var(--vot-easing-standard)}.vot-segmented-button .vot-segment:after,.vot-segmented-button .vot-segment-only-icon:after{transition:opacity var(--vot-duration-slow) var(--vot-easing-standard), background-size var(--vot-duration-slow) var(--vot-easing-standard);background:radial-gradient(circle,currentColor 1%,#0000 1%) 50%/10000% 10000% no-repeat}.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}.vot-segmented-button .vot-segment-only-icon{min-width:36px;padding:0!important}.vot-segmented-button .vot-segment-label{white-space:nowrap;color:inherit;margin-left:var(--vot-space-2)!important;font-weight:400!important}.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[data-loading=true] #vot-loading-icon{display:block!important}.vot-segmented-button[data-loading=true] #vot-translate-icon{display:none!important}.vot-segmented-button[data-direction=column]{flex-direction:column;height:fit-content}.vot-segmented-button[data-direction=column] .vot-segment-label{display:none}.vot-segmented-button[data-direction=column]>.vot-segment-only-icon,.vot-segmented-button[data-direction=column]>.vot-segment{padding:8px!important}.vot-segmented-button[data-direction=column] .vot-separator{width:50%;height:1px}.vot-segmented-button[data-position=left]{top:12.5vh;left:50px}.vot-segmented-button[data-position=right]{top:12.5vh;left:auto;right:0}.vot-segmented-button svg{width:24px;fill:inherit;stroke:inherit}.vot-tooltip{--vot-helper-theme-rgb:var(--vot-onsurface-rgb,0, 0, 0);--vot-helper-theme:rgba(var(--vot-helper-theme-rgb), .87);--vot-helper-ondialog:rgb(var(--vot-ondialog-rgb,37, 38, 40));--vot-helper-border:rgb(var(--vot-tooltip-border,69, 69, 69));-webkit-user-select:none;user-select:none;background:rgb(var(--vot-surface-rgb,255, 255, 255));color:var(--vot-helper-theme);fill:var(--vot-helper-theme);cursor:default;z-index:2147483647;opacity:0;align-items:center;width:max-content;max-width:calc(100vw - 10px);height:max-content;font-size:14px;line-height:1.5;transition:opacity .5s;display:flex;position:absolute;inset:0;overflow:hidden;box-shadow:0 1px 3px #0000001f;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;border-radius:4px!important;padding:4px 8px!important}.vot-tooltip[data-trigger=click]{-webkit-user-select:text;user-select:text}.vot-tooltip.vot-tooltip-bordered{border:1px solid var(--vot-helper-border)}.vot-tooltip *{box-sizing:border-box!important;font-family:inherit!important}.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), .87);--vot-settings-control-width:clamp(120px, 45%, 200px);-webkit-user-select:none;user-select:none;background-color:var(--vot-helper-surface);color:var(--vot-helper-onsurface);cursor:default;z-index:2147483646;visibility:visible;opacity:1;transform-origin:top;width:fit-content;min-width:320px;max-width:min(90vw,560px);transition:opacity var(--vot-duration-medium) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);font-size:16px;line-height:1.5;position:absolute;top:calc(5rem + 48px);left:50%;overflow:hidden;transform:translate(-50%)scale(1);border:1px solid var(--vot-border-color)!important;border-radius:var(--vot-radius-m)!important;box-shadow:var(--vot-shadow-2)!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important}.vot-menu *{box-sizing:border-box!important}.vot-menu[hidden]{pointer-events:none;visibility:hidden;opacity:0;transform:translate(-50%,-4px)scale(.98);display:block!important}.vot-menu-content-wrapper{min-width:320px;min-height:100px;max-height:calc(var(--vot-container-height,75vh) - (5rem + 32px + 16px) * 2);flex-direction:column;display:flex;overflow:auto}.vot-menu-header-container{flex-shrink:0;align-items:center;min-height:31px;display:flex;padding-inline-end:var(--vot-space-2)!important}.vot-menu-header-container:empty{padding:0 0 16px!important}.vot-menu-header-container>.vot-icon-button{margin-inline-end:var(--vot-space-1)!important;margin-top:var(--vot-space-1)!important}.vot-menu-title-container{font-size:inherit;text-align:start;outline:0;flex:1;display:flex;font-weight:inherit!important;margin:0!important}.vot-menu-title{flex:1;font-size:16px;line-height:1;padding:var(--vot-space-4)!important;font-weight:500!important}.vot-menu-body-container{box-sizing:border-box;gap:var(--vot-space-2);overscroll-behavior:contain;flex-direction:column;min-height:1.375rem;display:flex;overflow:auto;padding:0 var(--vot-space-4)!important;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), .1) var(--vot-helper-surface)!important}.vot-menu-body-container::-webkit-scrollbar{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-menu-body-container::-webkit-scrollbar-track{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-menu-body-container::-webkit-scrollbar-thumb{border-radius:1ex;background:rgba(var(--vot-helper-onsurface-rgb), .1)!important;border:5px solid var(--vot-helper-surface)!important}.vot-menu-body-container::-webkit-scrollbar-thumb:hover{border-width:3px!important}.vot-menu-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface)!important}.vot-menu-footer-container{flex-shrink:0;justify-content:flex-end;display:flex;padding:var(--vot-space-4)!important}.vot-menu-footer-container:empty{padding:var(--vot-space-4) 0 0 0!important}.vot-menu .vot-select--labeled>.vot-select-outer{margin-left:auto}.vot-menu[data-position=left]{transform-origin:0;top:12.5vh;left:240px}.vot-menu[data-position=right]{transform-origin:100%;top:12.5vh;left:auto;right:-80px}.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), .87);--vot-dialog-viewport-margin:16px;--vot-dialog-max-height:75vh;max-width:initial;max-height:initial;width:min(var(--vot-dialog-width,512px), 100%);border:1px solid var(--vot-border-color);border-radius:var(--vot-radius-l);background-color:var(--vot-helper-surface);height:fit-content;color:var(--vot-helper-onsurface);box-shadow:var(--vot-shadow-2);-webkit-user-select:none;user-select:none;visibility:visible;opacity:1;transform-origin:50%;transition:opacity var(--vot-duration-medium) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);font-size:16px;line-height:1.5;display:block;position:fixed;inset-block:0;inset-inline:0;overflow:auto hidden;transform:scale(1);font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;margin:auto!important;padding:0!important}[hidden]>.vot-dialog{pointer-events:none;opacity:0;transition:opacity var(--vot-duration-fast) var(--vot-easing-standard), transform var(--vot-duration-medium) var(--vot-easing-standard);transform:translateY(-4px)scale(.98)}.vot-dialog[data-vertical-align=top]{inset-block-start:var(--vot-dialog-viewport-margin);inset-block-end:auto;margin:0 auto!important}.vot-dialog-container{visibility:visible;z-index:2147483647;position:absolute}.vot-dialog-container[hidden]{pointer-events:none;visibility:hidden;display:block!important}.vot-dialog-container *{box-sizing:border-box!important}.vot-dialog-backdrop{opacity:1;background-color:#0009;transition:opacity .3s;position:fixed;inset:0}[hidden]>.vot-dialog-backdrop{pointer-events:none;opacity:0}.vot-dialog-content-wrapper{max-height:var(--vot-dialog-max-height,75vh);flex-direction:column;display:flex;overflow:auto}.vot-dialog-header-container{flex-shrink:0;align-items:flex-start;min-height:31px;display:flex}.vot-dialog-header-container:empty{padding:0 0 20px}.vot-dialog-header-container>.vot-icon-button{margin-inline-end:var(--vot-space-1)!important;margin-top:var(--vot-space-1)!important}.vot-dialog-title-container{font-size:inherit;outline:0;flex:1;display:flex;font-weight:inherit!important;margin:0!important}.vot-dialog-title{flex:1;font-size:115.385%;line-height:1;padding:var(--vot-space-5) var(--vot-space-5) var(--vot-space-4)!important;font-weight:700!important}.vot-dialog-body-container{box-sizing:border-box;gap:var(--vot-space-4);overscroll-behavior:contain;flex-direction:column;min-height:1.375rem;display:flex;overflow:auto;padding:0 var(--vot-space-5)!important;scrollbar-color:rgba(var(--vot-helper-onsurface-rgb), .1) var(--vot-helper-surface)!important}.vot-dialog-body-container::-webkit-scrollbar{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-dialog-body-container::-webkit-scrollbar-track{background:var(--vot-helper-surface)!important;width:12px!important;height:12px!important}.vot-dialog-body-container::-webkit-scrollbar-thumb{border-radius:1ex;background:rgba(var(--vot-helper-onsurface-rgb), .1)!important;border:5px solid var(--vot-helper-surface)!important}.vot-dialog-body-container::-webkit-scrollbar-thumb:hover{border-width:3px!important}.vot-dialog-body-container::-webkit-scrollbar-corner{background:var(--vot-helper-surface)!important}.vot-dialog-footer-container{justify-content:flex-end;gap:var(--vot-space-2);flex-wrap:wrap;flex-shrink:0;display:flex;padding:var(--vot-space-4)!important}.vot-dialog-footer-container:empty{padding:var(--vot-space-5) 0 0 0!important}@media (width<=480px){.vot-dialog-footer-container{flex-direction:column;align-items:stretch}.vot-dialog-footer-container>:is(.vot-button,.vot-outlined-button,.vot-text-button){white-space:normal;text-overflow:clip;text-align:center;justify-content:center;align-items:center;width:100%;height:auto;min-height:36px;padding:8px 16px;line-height:1.2;display:flex;overflow:visible}}.vot-inline-loader{aspect-ratio:5;--vot-loader-bg:no-repeat radial-gradient(farthest-side, rgba(var(--vot-onsurface-rgb,0, 0, 0), .38) 94%, transparent);background:var(--vot-loader-bg), var(--vot-loader-bg), var(--vot-loader-bg), var(--vot-loader-bg);background-size:20% 100%;height:8px;animation:.75s infinite alternate dotsSlide,1.5s infinite alternate dotsFlip}.vot-loader-progress{--vot-helper-theme:var(--vot-theme-rgb,var(--vot-primary-rgb,33, 150, 243));fill:none;stroke:rgb(var(--vot-helper-theme));stroke-width:2px;stroke-linecap:round;transform-origin:50%;transform:rotate(-90deg)}@keyframes dotsSlide{0%,10%{background-position:0 0,0 0,0 0,0 0}33%{background-position:0 0,33.3333% 0,33.3333% 0,33.3333% 0}66%{background-position:0 0,33.3333% 0,66.6667% 0,66.6667% 0}90%,to{background-position:0 0,33.3333% 0,66.6667% 0,100% 0}}@keyframes dotsFlip{0%,49.99%{transform:scale(1)}50%,to{transform:scale(-1)}}.vot-label{font-family:inherit;font-size:16px;line-height:1.5;display:block}.vot-label-text{display:inline}.vot-label-icon{vertical-align:text-bottom;cursor:help;justify-content:center;align-items:center;width:20px;height:20px;margin-left:4px;display:inline-flex}.vot-label-icon>svg{width:20px;height:20px;display:block}.vot-account{justify-content:space-between;align-items:center;gap:1rem;display:flex}.vot-account-container,.vot-account-wrapper,.vot-account-buttons{align-items:center;gap:1rem;display:flex}.vot-account-avatar{min-width:36px;max-width:36px;min-height:36px;max-height:36px;overflow:hidden}.vot-account-avatar-img{object-fit:cover;border-radius:50%;width:36px;height:36px}@property --vot-subtitles-opacity{syntax:\"\";inherits:true;initial-value:.8}@property --vot-subtitles-scale-compensation{syntax:\"\";inherits:true;initial-value:1}.vot-subtitles{--vot-subtitles-background:rgba(var(--vot-surface-rgb,46, 47, 52), var(--vot-subtitles-opacity,.8));--vot-subtitles-effective-max-width:var(--vot-subtitles-max-width,var(--vot-subtitles-smart-max-width,70vw));max-width:var(--vot-subtitles-effective-max-width);max-inline-size:var(--vot-subtitles-effective-max-width);background:var(--vot-subtitles-background,#2e2f34cc);width:max-content;inline-size:max-content;color:var(--vot-subtitles-color,#e3e3e3);pointer-events:all;touch-action:none;font-size:calc(var(--vot-subtitles-font-size,clamp(18px, var(--vot-subtitles-smart-font-preferred,2.2vw), 50px)) * var(--vot-subtitles-scale-compensation,1));-webkit-text-stroke:var(--vot-subtitles-text-stroke-width,clamp(1px, .08em, 2px)) var(--vot-subtitles-text-stroke-color,#000000eb);paint-order:stroke fill;text-shadow:var(--vot-subtitles-text-shadow,0 1px 2px #00000073, 0 2px 8px #00000040);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-synthesis:none;position:relative;--vot-subtitles-font-family:var(--vot-subtitles-font-family-custom,var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif))!important;font-family:var(--vot-subtitles-font-family)!important;font-style:normal!important;font-weight:var(--vot-subtitles-font-weight,500)!important;text-transform:none!important;letter-spacing:normal!important;border-radius:.5em!important;padding:.5em .75em!important;line-height:1.25!important}.vot-subtitles,.vot-subtitles *{-webkit-text-stroke:inherit;paint-order:inherit;font-family:var(--vot-subtitles-font-family)!important}.vot-subtitles{box-sizing:border-box;-webkit-user-select:none;user-select:none;contain:layout paint;isolation:isolate;text-align:center;text-wrap:balance;white-space:normal;overflow-wrap:anywhere;unicode-bidi:plaintext;margin:0 auto;display:block}.vot-subtitles-widget{--vot-subtitles-anchor-width:100vw;--vot-subtitles-anchor-height:100vh;--vot-subtitles-effective-max-width:var(--vot-subtitles-max-width,var(--vot-subtitles-smart-max-width,70vw));--vot-subtitles-smart-target-width:48ch;--vot-subtitles-smart-min-width-ratio:.62;--vot-subtitles-smart-max-width-ratio:.78;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0333);--vot-subtitles-smart-max-width:clamp(calc(var(--vot-subtitles-anchor-width) * var(--vot-subtitles-smart-min-width-ratio)), var(--vot-subtitles-smart-target-width), calc(var(--vot-subtitles-anchor-width) * var(--vot-subtitles-smart-max-width-ratio)));box-sizing:border-box;z-index:2147483647;--vot-subtitles-fallback-bottom-inset:calc(env(safe-area-inset-bottom,0px) + clamp(56px, 10vh, 220px) + 10px);left:50%;top:calc(100% - var(--vot-subtitles-fallback-bottom-inset));width:max-content;inline-size:max-content;max-width:var(--vot-subtitles-effective-max-width);max-inline-size:var(--vot-subtitles-effective-max-width);pointer-events:none;will-change:left, top, transform;max-height:100%;display:block;position:absolute;transform:translate(-50%,-100%)}.vot-subtitles-info{flex-direction:column;gap:2px;max-width:100%;display:flex;padding:6px!important}.vot-subtitles-info-service,.vot-subtitles-info-header,.vot-subtitles-info-context{overflow-wrap:anywhere;word-break:break-word;white-space:normal!important}.vot-subtitles-info-service{color:var(--vot-subtitles-context-color,#86919b);margin-bottom:8px!important;font-size:10px!important;line-height:1!important}.vot-subtitles-info-header{color:var(--vot-subtitles-header-color,#fff);margin-bottom:6px!important;font-size:20px!important;font-weight:500!important;line-height:1!important}.vot-subtitles-info-context{color:var(--vot-subtitles-context-color,#86919b);font-size:12px!important;line-height:1.2!important}.vot-subtitles span[data-vot-highlight-index].passed{color:var(--vot-subtitles-passed-color,#2196f3)}.vot-subtitles span[data-vot-token=\"1\"]{cursor:pointer;white-space:normal;overflow-wrap:inherit;word-break:normal;position:relative;font-size:inherit!important;font-family:inherit!important;font-style:inherit!important;font-weight:inherit!important;line-height:inherit!important;text-transform:inherit!important;text-decoration:none!important}.vot-subtitles span[data-vot-token=\"1\"]:before{content:\"\";z-index:-1;position:absolute;inset:2px -2px;border-radius:4px!important}.vot-subtitles span[data-vot-token=\"1\"]:hover:before{background:var(--vot-subtitles-hover-color,#ffffff8c)}.vot-subtitles span[data-vot-token=\"1\"].selected:before{background:var(--vot-subtitles-passed-color,#2196f3)}.vot-subtitles span[data-vot-style-italic=\"1\"]{font-style:italic!important}.vot-subtitles span[data-vot-style-bold=\"1\"]{font-weight:700!important}.vot-subtitles span[data-vot-style-underline=\"1\"]{text-decoration:underline!important}.vot-subtitles span[data-vot-style-color=\"1\"]{color:var(--vot-subtitles-inline-color)!important}.vot-subtitles-layer{pointer-events:none;z-index:2147483647;contain:layout paint;width:100vw!important;height:100vh!important;position:fixed!important;inset:0!important}.vot-subtitles-guides{pointer-events:none;z-index:2147483646;position:absolute;inset:0}.vot-subtitles-guide{background:rgba(var(--vot-primary-rgb,33, 150, 243), .7);box-shadow:0 0 0 1px rgba(var(--vot-primary-rgb,33, 150, 243), .12);opacity:0;transition:opacity .12s linear;position:absolute}.vot-subtitles-guide[data-visible=true]{opacity:1}.vot-subtitles-guide--vertical{width:2px;transform:translate(-50%)}.vot-subtitles-guide--horizontal{height:2px;transform:translateY(-50%)}@media (aspect-ratio<=1){.vot-subtitles-widget{--vot-subtitles-smart-target-width:28ch;--vot-subtitles-smart-min-width-ratio:.8;--vot-subtitles-smart-max-width-ratio:.92;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0296)}}@media (aspect-ratio>=1) and (aspect-ratio<=7/5){.vot-subtitles-widget{--vot-subtitles-smart-target-width:32ch;--vot-subtitles-smart-min-width-ratio:.55;--vot-subtitles-smart-max-width-ratio:.9;--vot-subtitles-smart-font-preferred:calc(var(--vot-subtitles-anchor-height) * .0333)}}@media (width<=900px) and (pointer:coarse){.vot-subtitles-widget{--vot-subtitles-fallback-bottom-inset:env(safe-area-inset-bottom,0px)}}@media (prefers-contrast:more){.vot-subtitles{--vot-subtitles-background:rgba(var(--vot-surface-rgb,46, 47, 52), .92);--vot-subtitles-text-stroke-width:max(2px, .1em);--vot-subtitles-text-shadow:0 2px 10px #0000008c}}:is(:fullscreen .vot-subtitles-widget,:fullscreen .vot-subtitles-widget){--vot-subtitles-smart-max-width-ratio:.8}:is(:fullscreen .vot-subtitles,:fullscreen .vot-subtitles){font-size:calc(var(--vot-subtitles-font-size,clamp(18px, var(--vot-subtitles-smart-font-preferred,2vw), 50px)) * var(--vot-subtitles-fullscreen-scale,1) * .95 * var(--vot-subtitles-scale-compensation,1))}#vot-subtitles-info.vot-subtitles-info *{-webkit-user-select:text!important;user-select:text!important}:root{--vot-font-family:\"Roboto\", \"Segoe UI\", system-ui, sans-serif;--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-color:rgb(var(--vot-onsurface-rgb,227, 227, 227));--vot-subtitles-passed-color:rgb(var(--vot-primary-rgb,33, 150, 243));--vot-space-1:4px;--vot-space-2:8px;--vot-space-3:12px;--vot-space-4:16px;--vot-space-5:20px;--vot-space-6:24px;--vot-radius-xs:6px;--vot-radius-s:10px;--vot-radius-m:14px;--vot-radius-l:18px;--vot-border-color:rgba(var(--vot-onsurface-rgb,227, 227, 227), .14);--vot-border-color-hover:rgba(var(--vot-onsurface-rgb,227, 227, 227), .22);--vot-shadow-1:0 1px 2px #0000002e, 0 8px 24px #00000024;--vot-shadow-2:0 2px 4px #00000038, 0 12px 32px #00000038;--vot-duration-fast:.12s;--vot-duration-medium:.2s;--vot-duration-slow:.32s;--vot-easing-standard:cubic-bezier(.4, 0, .2, 1);--vot-focus-ring-color:rgba(var(--vot-primary-rgb,139, 180, 245), .9);--vot-focus-ring:0 0 0 2px var(--vot-focus-ring-color);--vot-focus-ring-offset:0 0 0 4px rgba(var(--vot-surface-rgb,32, 33, 36), .9)}vot-block,vot-block *{box-sizing:border-box;-webkit-tap-highlight-color:transparent}vot-block[hidden]:not(.vot-menu):not(.vot-dialog-container),vot-block [hidden]:not(.vot-menu):not(.vot-dialog-container){display:none!important}vot-block{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizelegibility;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;display:block;--vot-font-family:\"Roboto\", \"Segoe UI\", system-ui, sans-serif!important;font-family:var(--vot-font-family,\"Roboto\", \"Segoe UI\", system-ui, sans-serif)!important;visibility:visible!important;font-weight:400!important}vot-block *{font-weight:inherit!important}.vot-portal-local,.vot-subtitles-widget{isolation:isolate}vot-block:focus,vot-block :focus{box-shadow:none!important;outline:none!important}html.vot-keyboard-nav vot-block:focus-visible,html.vot-keyboard-nav vot-block :focus-visible{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}@supports not selector(:focus-visible){html.vot-keyboard-nav vot-block:focus,html.vot-keyboard-nav vot-block :focus{box-shadow:var(--vot-focus-ring), var(--vot-focus-ring-offset)!important}}@media (prefers-reduced-motion:reduce){.vot-portal-local *,.vot-portal *,.vot-subtitles-widget *{scroll-behavior:auto!important;transition-duration:.001ms!important;animation-duration:.001ms!important;animation-iteration-count:1!important}}.vot-portal{display:inline}.vot-portal-local{z-index:2147483647;position:fixed;top:0;left:0}.vot-overlay-root{pointer-events:none}.vot-overlay-root>.vot-segmented-button,.vot-overlay-root>.vot-menu{pointer-events:auto}"); + var sharedShadowStyleSheet; + function scopeCssForShadowRoots(cssText) { + return cssText.replace(/:root\b/g, ":host").replace(/html\.vot-keyboard-nav/g, ":host-context(.vot-keyboard-nav)").replace(/:fullscreen(?=\s|,)/g, ":host-context(:fullscreen)").replace(/:-webkit-full-screen(?=\s|,)/g, ":host-context(:-webkit-full-screen)"); + } + function applyInlineStyles(element, styles) { + if (!styles) return; + for (const [name, value] of Object.entries(styles)) { + if (typeof value !== "string") continue; + element.style.setProperty(name, value); + } + } + function getSharedShadowStyleSheet() { + if (sharedShadowStyleSheet !== void 0) return sharedShadowStyleSheet; + if (!(typeof CSSStyleSheet !== "undefined" && typeof CSSStyleSheet.prototype.replaceSync === "function")) { + sharedShadowStyleSheet = null; + return sharedShadowStyleSheet; + } + const sheet = new CSSStyleSheet(); + sheet.replaceSync(shadowScopedCssText); + sharedShadowStyleSheet = sheet; + return sharedShadowStyleSheet; + } + function adoptScopedStyles(shadowRoot) { + const sharedSheet = getSharedShadowStyleSheet(); + if (sharedSheet) { + if (!shadowRoot.adoptedStyleSheets.includes(sharedSheet)) shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, sharedSheet]; + return; + } + const style = document.createElement("style"); + style.textContent = shadowScopedCssText; + shadowRoot.append(style); + } + function createShadowMount({ parent, hostTag = "vot-shadow-host", rootTag = "vot-block", hostClasses = [], rootClasses = [], hostStyles, rootStyles, delegatesFocus = false }) { + const host = document.createElement(hostTag); + if (hostClasses.length > 0) host.classList.add(...hostClasses); + applyInlineStyles(host, hostStyles); + const shadowRoot = host.attachShadow({ + mode: "open", + delegatesFocus + }); + adoptScopedStyles(shadowRoot); + const root = document.createElement(rootTag); + if (rootClasses.length > 0) root.classList.add(...rootClasses); + applyInlineStyles(root, rootStyles); + shadowRoot.append(root); + parent.append(host); + return { + host, + root, + shadowRoot + }; + } + function reparentShadowMount(mount, parent) { + if (!mount) return; + if (mount.host.parentElement !== parent) parent.append(mount.host); + } + function destroyShadowMount(mount) { + mount?.host.remove(); + } + //#endregion + //#region src/subtitles/layoutController.ts + function isTimeInLine(time, line) { + return time >= line.startMs && time < line.startMs + line.durationMs; + } + //#endregion + //#region src/subtitles/activeCues.ts + var createFallbackTokens = (line) => { + if (line.tokens.length) return line.tokens; + const text = line.text.trim(); + if (!text) return []; + return [{ + text, + startMs: line.startMs, + durationMs: line.durationMs, + isWordLike: Boolean(text) + }]; + }; + var toRenderableTextKey = (line) => { + return (line.text || createFallbackTokens(line).map((token) => token.text).join("")).replaceAll(/\s+/gu, " ").trim(); + }; + var linesOverlapInTime = (left, right) => { + const leftEnd = left.startMs + Math.max(0, left.durationMs); + const rightEnd = right.startMs + Math.max(0, right.durationMs); + return left.startMs < rightEnd && right.startMs < leftEnd; + }; + var dedupeActiveLines = (lines) => { + const deduped = []; + for (const entry of lines) { + const textKey = toRenderableTextKey(entry.line); + if (!textKey) continue; + if (!deduped.some((existing) => { + return textKey === toRenderableTextKey(existing.line) && existing.line.speakerId === entry.line.speakerId && linesOverlapInTime(existing.line, entry.line); + })) deduped.push(entry); + } + return deduped; + }; + var findLastCueIndexStartingAtOrBefore = (time, subtitlesList) => { + let low = 0; + let high = subtitlesList.length - 1; + let candidate = -1; + while (low <= high) { + const mid = low + high >> 1; + if (subtitlesList[mid].startMs <= time) { + candidate = mid; + low = mid + 1; + continue; + } + high = mid - 1; + } + return candidate; + }; + var findActiveSubtitleLineIndices = (time, subtitlesList, maxCueDurationMs = Number.POSITIVE_INFINITY) => { + const lastCueIndex = findLastCueIndexStartingAtOrBefore(time, subtitlesList); + if (lastCueIndex < 0) return []; + const minStartMs = Number.isFinite(maxCueDurationMs) ? Math.max(0, time - Math.max(0, maxCueDurationMs)) : Number.NEGATIVE_INFINITY; + const activeLineIndices = []; + for (let index = lastCueIndex; index >= 0; index -= 1) { + const line = subtitlesList[index]; + if (line.startMs < minStartMs) break; + if (isTimeInLine(time, line)) activeLineIndices.push(index); + } + activeLineIndices.reverse(); + return activeLineIndices; + }; + var buildActiveSubtitleRenderLine = (time, subtitlesList, maxCueDurationMs = Number.POSITIVE_INFINITY) => { + const activeLineIndices = findActiveSubtitleLineIndices(time, subtitlesList, maxCueDurationMs); + if (!activeLineIndices.length) return null; + const activeEntries = dedupeActiveLines(activeLineIndices.map((index) => ({ + index, + line: subtitlesList[index] + }))); + if (!activeEntries.length) return null; + if (activeEntries.length === 1) { + const [entry] = activeEntries; + return { + line: entry.line, + lineKey: `${entry.index}` + }; + } + const tokens = []; + const textParts = []; + const rawTextParts = []; + const lineKeyParts = []; + let earliestStartMs = Number.POSITIVE_INFINITY; + let latestEndMs = 0; + for (const entry of activeEntries) { + const lineTokens = createFallbackTokens(entry.line); + if (!lineTokens.length) continue; + if (tokens.length > 0) { + const breakStartMs = Math.max(earliestStartMs, entry.line.startMs); + tokens.push({ + text: "\n", + startMs: breakStartMs, + durationMs: 0, + isWordLike: false + }); + } + tokens.push(...lineTokens); + textParts.push(entry.line.text || lineTokens.map((token) => token.text).join("")); + rawTextParts.push(entry.line.metadata?.rawText ?? entry.line.text); + lineKeyParts.push(`${entry.index}`); + earliestStartMs = Math.min(earliestStartMs, entry.line.startMs); + latestEndMs = Math.max(latestEndMs, entry.line.startMs + Math.max(0, entry.line.durationMs)); + } + if (!tokens.length || !lineKeyParts.length) return null; + return { + line: { + text: textParts.join("\n"), + startMs: earliestStartMs, + durationMs: Math.max(0, latestEndMs - earliestStartMs), + speakerId: activeEntries[0]?.line.speakerId ?? "0", + tokens, + metadata: rawTextParts.length ? { rawText: rawTextParts.join("\n") } : void 0 + }, + lineKey: lineKeyParts.join(",") + }; + }; + //#endregion + //#region src/types/subtitles.ts + var subtitleFormats = [ + "srt", + "vtt", + "ass", + "json" + ]; + var subtitleFontFamilies = [ + "default-sans", + "arial", + "helvetica", + "roboto", + "verdana", + "open-sans", + "poppins", + "lato", + "montserrat", + "barlow" + ]; + var subtitleFontFamilyCss = { + "default-sans": `"Roboto", "Segoe UI", system-ui, sans-serif`, + arial: `Arial, "Helvetica Neue", Helvetica, sans-serif`, + helvetica: `"Helvetica Neue", Helvetica, Arial, sans-serif`, + roboto: `"Roboto", "Segoe UI", system-ui, sans-serif`, + verdana: `Verdana, Geneva, sans-serif`, + "open-sans": `"Open Sans", "Segoe UI", system-ui, sans-serif`, + poppins: `"Poppins", "Segoe UI", system-ui, sans-serif`, + lato: `"Lato", "Segoe UI", system-ui, sans-serif`, + montserrat: `"Montserrat", "Segoe UI", system-ui, sans-serif`, + barlow: `"Barlow", "Segoe UI", system-ui, sans-serif` + }; + //#endregion + //#region src/subtitles/types.ts + var subtitleFormatsSet = new Set(subtitleFormats); + function isSubtitleFormat(value) { + return typeof value === "string" && subtitleFormatsSet.has(value); + } + function isRecord(value) { + return value !== null && typeof value === "object"; + } + function parseSubtitleDescriptor(value) { + if (!isRecord(value)) return null; + const format = value.format; + if (typeof value.source !== "string" || typeof value.language !== "string" || typeof value.url !== "string" || !isSubtitleFormat(format)) return null; + return { + source: value.source, + format, + language: value.language, + url: value.url, + translatedFromLanguage: typeof value.translatedFromLanguage === "string" ? value.translatedFromLanguage : void 0, + isAutoGenerated: typeof value.isAutoGenerated === "boolean" ? value.isAutoGenerated : void 0 + }; + } + function isBuiltInSubtitleFontFamily(fontFamily) { + return subtitleFontFamilies.includes(fontFamily); + } + //#endregion + //#region src/subtitles/fonts.ts + var GOOGLE_SUBTITLE_FONT_PREFIX = "google:"; + var GOOGLE_FONTS_CSS_API_URL = "https://fonts.googleapis.com/css2"; + var GOOGLE_FONTS_METADATA_URL = "https://fonts.google.com/metadata/fonts"; + var subtitleGoogleFontFamilyNames = { + roboto: "Roboto", + "open-sans": "Open Sans", + poppins: "Poppins", + lato: "Lato", + montserrat: "Montserrat", + barlow: "Barlow" + }; + var loadedSubtitleGoogleFonts = /* @__PURE__ */ new Set(); + var pendingSubtitleGoogleFonts = /* @__PURE__ */ new Map(); + var googleFontsCatalogPromise = null; + function toGoogleSubtitleFontFamily(familyName) { + return `${GOOGLE_SUBTITLE_FONT_PREFIX}${familyName}`; + } + function getGoogleSubtitleFontFamilyName(fontFamily) { + if (fontFamily.startsWith(GOOGLE_SUBTITLE_FONT_PREFIX)) { + const familyName = fontFamily.slice(7).trim(); + return familyName.length > 0 ? familyName : null; + } + return subtitleGoogleFontFamilyNames[fontFamily] ?? null; + } + function getSubtitleFontFamilyCssValue(fontFamily) { + if (isBuiltInSubtitleFontFamily(fontFamily)) return subtitleFontFamilyCss[fontFamily]; + const googleFontFamilyName = getGoogleSubtitleFontFamilyName(fontFamily); + if (googleFontFamilyName) return `"${googleFontFamilyName}", "Segoe UI", system-ui, sans-serif`; + return subtitleFontFamilyCss["default-sans"]; + } + function buildGoogleFontsCssUrl(fontFamily) { + const googleFontFamily = getGoogleSubtitleFontFamilyName(fontFamily); + if (!googleFontFamily) return null; + return `${GOOGLE_FONTS_CSS_API_URL}?family=${googleFontFamily.trim().replaceAll(/\s+/g, "+")}&display=swap`; + } + function injectFontStylesheet(fontFamily, cssText) { + const styleId = `vot-google-font-${fontFamily}`; + if (document.getElementById(styleId)) return; + const gmAddStyle = globalThis.GM_addStyle; + const styleElement = typeof gmAddStyle === "function" ? gmAddStyle(cssText) : document.createElement("style"); + if (!(styleElement instanceof HTMLElement)) return; + styleElement.id = styleId; + if (!styleElement.textContent) styleElement.textContent = cssText; + if (!styleElement.parentElement) (document.head || document.documentElement).appendChild(styleElement); + } + async function ensureGoogleSubtitleFontLoaded(fontFamily, options = {}) { + if (loadedSubtitleGoogleFonts.has(fontFamily)) return; + const existingLoad = pendingSubtitleGoogleFonts.get(fontFamily); + if (existingLoad !== void 0) { + await existingLoad; + return; + } + const cssUrl = buildGoogleFontsCssUrl(fontFamily); + if (!cssUrl) { + loadedSubtitleGoogleFonts.add(fontFamily); + return; + } + const googleFontFamily = getGoogleSubtitleFontFamilyName(fontFamily); + const loadPromise = (async () => { + try { + const response = await GM_fetch(cssUrl, { + timeout: 1e4, + forceGmXhr: options.forceGmXhr ?? true, + headers: { Accept: "text/css,*/*;q=0.1" } + }); + if (!response.ok) throw new Error(`Google Fonts CSS request failed with ${response.status}`); + const cssText = await response.text(); + if (!cssText.trim()) throw new Error("Google Fonts CSS response is empty"); + injectFontStylesheet(fontFamily, cssText); + loadedSubtitleGoogleFonts.add(fontFamily); + if (document.fonts && googleFontFamily) await document.fonts.load(`500 20px "${googleFontFamily}"`); + options.onLoaded?.(); + } catch (error) { + debug.log("Failed to load Google Font for subtitles", { + fontFamily, + error + }); + } finally { + pendingSubtitleGoogleFonts.delete(fontFamily); + } + })(); + pendingSubtitleGoogleFonts.set(fontFamily, loadPromise); + await loadPromise; + } + async function loadGoogleFontsCatalog() { + if (googleFontsCatalogPromise !== null) return await googleFontsCatalogPromise; + googleFontsCatalogPromise = (async () => { + const response = await GM_fetch(GOOGLE_FONTS_METADATA_URL, { + timeout: 15e3, + forceGmXhr: isSupportGMXhr + }); + if (!response.ok) throw new Error(`Google Fonts metadata request failed with ${response.status}`); + const sanitizedText = (await response.text()).replace(/^\)\]\}'\n?/, ""); + const fontFamilies = JSON.parse(sanitizedText).familyMetadataList?.map((entry) => entry.family?.trim() ?? "").filter((familyName) => familyName.length > 0); + return Array.from(new Set(fontFamilies)).sort((left, right) => left.localeCompare(right)); + })().catch((error) => { + googleFontsCatalogPromise = null; + debug.log("Failed to load Google Fonts catalog", error); + return []; + }); + return await googleFontsCatalogPromise; + } + //#endregion + //#region src/subtitles/fullscreenLayerController.ts + var FullscreenLayerController = class { + container; + constructor({ container }) { + this.container = container; + } + updateContainer(container) { + this.container = container; + } + getWidgetParentElement() { + return this.container; + } + getLayoutRootElement() { + return this.container; + } + syncWidgetContainer(widgetContainer) { + if (getComputedStyle(this.container).position === "static") this.container.style.position = "relative"; + if (widgetContainer && widgetContainer.parentElement !== this.container) this.container.appendChild(widgetContainer); + } + release() {} + }; + //#endregion + //#region src/subtitles/inlineStyle.ts + var SAFE_CSS_COLOR_NAME_RE = /^[a-z]+$/iu; + var SAFE_HEX_COLOR_RE = /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/iu; + var SAFE_CSS_FUNCTION_COLOR_RE = /^(?:rgb|rgba|hsl|hsla)\(\s*[0-9.,%\s/+-]+\)$/iu; + var SAFE_CLASS_NAME_RE = /^[a-z0-9_-]+$/iu; + var normalizeClassNames = (classes) => { + if (!classes?.length) return void 0; + const normalized = Array.from(new Set(classes.map((value) => value.trim()).filter((value) => value && SAFE_CLASS_NAME_RE.test(value)))).sort((left, right) => left.localeCompare(right)); + return normalized.length ? normalized : void 0; + }; + var normalizeCssColorValue = (value) => { + const normalized = value.trim(); + if (!normalized) return void 0; + if (SAFE_HEX_COLOR_RE.test(normalized)) return normalized.toLowerCase(); + if (SAFE_CSS_COLOR_NAME_RE.test(normalized)) return normalized.toLowerCase(); + if (SAFE_CSS_FUNCTION_COLOR_RE.test(normalized)) return normalized; + }; + var normalizeSubtitleInlineStyle = (style) => { + if (!style) return void 0; + const normalized = {}; + if (style.italic) normalized.italic = true; + if (style.bold) normalized.bold = true; + if (style.underline) normalized.underline = true; + const normalizedColor = typeof style.color === "string" ? normalizeCssColorValue(style.color) : void 0; + if (normalizedColor) normalized.color = normalizedColor; + const normalizedClasses = normalizeClassNames(style.classes); + if (normalizedClasses) normalized.classes = normalizedClasses; + return Object.keys(normalized).length ? normalized : void 0; + }; + var sanitizeSubtitleInlineStyle = (value) => { + if (!value || typeof value !== "object") return void 0; + const raw = value; + return normalizeSubtitleInlineStyle({ + italic: raw.italic === true, + bold: raw.bold === true, + underline: raw.underline === true, + color: typeof raw.color === "string" ? raw.color : void 0, + classes: Array.isArray(raw.classes) ? raw.classes.filter((entry) => typeof entry === "string") : void 0 + }); + }; + var subtitleInlineStylesEqual = (left, right) => { + const leftNormalized = normalizeSubtitleInlineStyle(left); + const rightNormalized = normalizeSubtitleInlineStyle(right); + const leftClasses = leftNormalized?.classes ?? []; + const rightClasses = rightNormalized?.classes ?? []; + return Boolean(leftNormalized?.italic) === Boolean(rightNormalized?.italic) && Boolean(leftNormalized?.bold) === Boolean(rightNormalized?.bold) && Boolean(leftNormalized?.underline) === Boolean(rightNormalized?.underline) && (leftNormalized?.color ?? "") === (rightNormalized?.color ?? "") && leftClasses.length === rightClasses.length && leftClasses.every((value, index) => value === rightClasses[index]); + }; + var buildSubtitleInlineStyleCssText = (style) => { + const normalized = normalizeSubtitleInlineStyle(style); + if (!normalized?.color) return ""; + return `--vot-subtitles-inline-color:${normalized.color};`; + }; + //#endregion + //#region src/subtitles/positionController.ts + function clampToRange(value, min, max) { + return Math.max(min, Math.min(value, max)); + } + function hasDragThresholdBeenExceeded(startClientX, startClientY, nextClientX, nextClientY, thresholdPx) { + const dx = nextClientX - startClientX; + const dy = nextClientY - startClientY; + return dx * dx + dy * dy >= thresholdPx * thresholdPx; + } + function getVerticalAnchorBounds({ elementHeight, boxHeight, bottomInset }) { + const minAnchorY = Math.max(0, elementHeight || 0); + const baselineAnchorY = Math.max(minAnchorY, boxHeight - bottomInset); + return { + minAnchorY, + baselineAnchorY, + travelPx: Math.max(0, baselineAnchorY - minAnchorY) + }; + } + function captureCustomVerticalAnchorState({ anchorY, elementHeight, boxHeight, bottomInset }) { + const { minAnchorY, baselineAnchorY, travelPx } = getVerticalAnchorBounds({ + elementHeight, + boxHeight, + bottomInset + }); + return { + offsetFromBaselinePx: clampToRange(anchorY, minAnchorY, baselineAnchorY) - baselineAnchorY, + travelPx + }; + } + function resolveCustomVerticalAnchor({ state, elementHeight, boxHeight, bottomInset }) { + const { minAnchorY, baselineAnchorY, travelPx } = getVerticalAnchorBounds({ + elementHeight, + boxHeight, + bottomInset + }); + if (!state || travelPx <= 0) return baselineAnchorY; + const storedTravelPx = Math.max(0, state.travelPx || 0); + const storedLiftPx = Math.max(0, -(state.offsetFromBaselinePx || 0)); + if (storedTravelPx <= 0 || storedLiftPx <= 0) return baselineAnchorY; + const ratioLiftPx = storedLiftPx / storedTravelPx * travelPx; + return clampToRange(baselineAnchorY - (travelPx >= storedTravelPx ? Math.min(storedLiftPx, ratioLiftPx) : Math.min(travelPx, ratioLiftPx)), minAnchorY, baselineAnchorY); + } + function clampAnchorWithinBox({ anchorX, anchorY, elementWidth, elementHeight, boxWidth, boxHeight, bottomInset }) { + let nextAnchorX = anchorX; + let nextAnchorY = anchorY; + const maxAnchorY = Math.max(0, boxHeight - bottomInset); + const minAnchorY = elementHeight || 0; + if (elementWidth) { + let leftPx = nextAnchorX - elementWidth / 2; + const maxLeftPx = boxWidth - elementWidth; + if (maxLeftPx >= 0) leftPx = clampToRange(leftPx, 0, maxLeftPx); + else leftPx = maxLeftPx / 2; + nextAnchorX = leftPx + elementWidth / 2; + } + nextAnchorY = clampToRange(nextAnchorY, minAnchorY, maxAnchorY); + return { + anchorX: nextAnchorX, + anchorY: nextAnchorY + }; + } + function snapValueToNearestCandidate({ current, candidates, thresholdPx }) { + let closestValue = current; + let closestDistance = Number.POSITIVE_INFINITY; + for (const candidate of candidates) { + const distance = Math.abs(candidate - current); + if (distance < closestDistance) { + closestDistance = distance; + closestValue = candidate; + } + } + if (!Number.isFinite(closestDistance) || closestDistance > thresholdPx) return { + snapped: false, + value: current + }; + return { + snapped: true, + value: closestValue + }; + } + //#endregion + //#region src/subtitles/renderPlan.ts + var LEADING_PUNCTUATION_RE = /^[\p{P}\p{S}]+/u; + var TRAILING_PUNCTUATION_RE = /[\p{P}\p{S}]+$/u; + var PUNCTUATION_ONLY_RE = /^[\p{P}\p{S}]+$/u; + var TEXT_TOKEN_SLICE_RE = /\s+|[\p{P}\p{S}]+|[^\s\p{P}\p{S}]+/gu; + var pushTextPart = (plan, text, style, options = {}) => { + plan.push({ + kind: "text", + text, + style, + highlightIndex: options.highlightIndex + }); + if (options.withBreak) plan.push({ kind: "break" }); + }; + var skipWhitespaceTokens = (tokens, startIndex, renderEndTokenIndex) => { + let index = startIndex; + while (index <= renderEndTokenIndex && !tokens[index]?.isWordLike && !tokens[index]?.text.trim()) index += 1; + return index; + }; + var hasFutureWordToken = (tokens, startIndex, renderEndTokenIndex) => { + for (let index = startIndex; index <= renderEndTokenIndex; index += 1) { + const tokenText = tokens[index]?.text ?? ""; + if (!tokens[index]?.isWordLike || !tokenText.trim()) continue; + if (tokenText.trimStart().replace(LEADING_PUNCTUATION_RE, "").replace(TRAILING_PUNCTUATION_RE, "")) return true; + } + return false; + }; + var consumeWordToken = (plan, tokens, startIndex, renderEndTokenIndex, breakAfterTokenIndexSet, highlightIndex) => { + const token = tokens[startIndex]; + const leadingWhitespace = /^\s+/u.exec(token.text)?.[0] ?? ""; + const body = token.text.slice(leadingWhitespace.length); + if (leadingWhitespace) pushTextPart(plan, leadingWhitespace, token.style); + const leadingPunctuation = LEADING_PUNCTUATION_RE.exec(body)?.[0] ?? ""; + const bodyWithoutLeadingPunctuation = body.slice(leadingPunctuation.length); + const trailingPunctuation = TRAILING_PUNCTUATION_RE.exec(bodyWithoutLeadingPunctuation)?.[0] ?? ""; + const wordText = trailingPunctuation ? bodyWithoutLeadingPunctuation.slice(0, bodyWithoutLeadingPunctuation.length - trailingPunctuation.length) : bodyWithoutLeadingPunctuation; + if (!wordText) { + if (body) pushTextPart(plan, body, token.style); + if (!breakAfterTokenIndexSet?.has(startIndex)) return { + consumedWord: false, + nextTokenIndex: startIndex + 1 + }; + plan.push({ kind: "break" }); + return { + consumedWord: false, + nextTokenIndex: skipWhitespaceTokens(tokens, startIndex + 1, renderEndTokenIndex) + }; + } + if (leadingPunctuation) pushTextPart(plan, leadingPunctuation, token.style, { highlightIndex }); + plan.push({ + kind: "word", + text: wordText, + style: token.style, + highlightIndex + }); + if (trailingPunctuation) pushTextPart(plan, trailingPunctuation, token.style, { highlightIndex }); + if (!breakAfterTokenIndexSet?.has(startIndex)) return { + consumedWord: true, + nextTokenIndex: startIndex + 1 + }; + plan.push({ kind: "break" }); + return { + consumedWord: true, + nextTokenIndex: skipWhitespaceTokens(tokens, startIndex + 1, renderEndTokenIndex) + }; + }; + var consumeTextToken = (plan, tokenIndex, tokens, renderEndTokenIndex, token, tokenText, hasBreakAfter, lastWordHighlightIndex, nextWordHighlightIndex) => { + const fallbackHighlightIndex = lastWordHighlightIndex ?? (hasFutureWordToken(tokens, tokenIndex + 1, renderEndTokenIndex) ? nextWordHighlightIndex : void 0); + const textParts = tokenText.match(TEXT_TOKEN_SLICE_RE) ?? [tokenText]; + for (const textPart of textParts) pushTextPart(plan, textPart, token.style, { highlightIndex: PUNCTUATION_ONLY_RE.test(textPart) ? fallbackHighlightIndex : void 0 }); + if (hasBreakAfter) { + plan.push({ kind: "break" }); + return skipWhitespaceTokens(tokens, tokenIndex + 1, renderEndTokenIndex); + } + return tokenIndex + 1; + }; + /** + * Build a render plan for subtitle tokens preserving existing grouping rules. + * + * Important detail: leading punctuation before a word (for example "(" or "\"") + * should be visually highlighted together with that word. + */ + function buildSubtitleRenderPlan(tokens, renderEndTokenIndex, breakAfterTokenIndexSet) { + const plan = []; + let wordHighlightIndex = 0; + let lastWordHighlightIndex = null; + for (let i = 0; i <= renderEndTokenIndex;) { + const token = tokens[i]; + const tokenText = token?.text ?? ""; + if (!tokenText) { + i += 1; + continue; + } + if (tokenText === "\n") { + plan.push({ kind: "break" }); + i += 1; + continue; + } + if (token.isWordLike) { + const result = consumeWordToken(plan, tokens, i, renderEndTokenIndex, breakAfterTokenIndexSet, wordHighlightIndex); + i = result.nextTokenIndex; + if (result.consumedWord) { + lastWordHighlightIndex = wordHighlightIndex; + wordHighlightIndex += 1; + } + continue; + } + const hasBreakAfter = Boolean(breakAfterTokenIndexSet?.has(i)); + i = consumeTextToken(plan, i, tokens, renderEndTokenIndex, token, tokenText, hasBreakAfter, lastWordHighlightIndex, wordHighlightIndex); + } + return plan; + } + //#endregion + //#region src/subtitles/smartLayout.ts + var clampNumber$1 = (value, min, max) => Math.min(max, Math.max(min, value)); + var roundToInt = (value) => Math.round(value); + var resolveAspectBand = (aspect) => { + if (aspect < .8) return { + widthRatio: .9, + charsPerLine: 27, + fontHeightRatio: .03 + }; + if (aspect < 1.1) return { + widthRatio: .84, + charsPerLine: 31, + fontHeightRatio: .031 + }; + if (aspect < 1.5) return { + widthRatio: .76, + charsPerLine: 36, + fontHeightRatio: .033 + }; + if (aspect < 1.95) return { + widthRatio: .72, + charsPerLine: 40, + fontHeightRatio: .034 + }; + return { + widthRatio: .68, + charsPerLine: 44, + fontHeightRatio: .035 + }; + }; + var resolveWidthBoost = (width) => { + if (width >= 1920) return { + extraChars: 4, + widthScale: 1.04 + }; + if (width >= 1440) return { + extraChars: 3, + widthScale: 1.03 + }; + if (width >= 960) return { + extraChars: 2, + widthScale: 1.02 + }; + if (width >= 640) return { + extraChars: 1, + widthScale: 1.01 + }; + return { + extraChars: 0, + widthScale: 1 + }; + }; + var estimateAverageGlyphWidth = (fontSizePx) => Math.max(7, fontSizePx * .56); + function computeSmartLayoutForBox(box, cssMetrics = null) { + const width = Number.isFinite(box.w) ? Math.max(0, box.w) : 0; + const height = Number.isFinite(box.h) ? Math.max(0, box.h) : 0; + if (width <= 0 || height <= 0) return { + fontSizePx: cssMetrics?.fontSizePx ?? 20, + maxWidthPx: cssMetrics?.maxWidthPx ?? null + }; + const { widthRatio, charsPerLine, fontHeightRatio } = resolveAspectBand(width / height); + const { extraChars, widthScale } = resolveWidthBoost(width); + const derivedFontSizePx = clampNumber$1(height * fontHeightRatio, 16, 42); + const fontSizePx = cssMetrics?.fontSizePx ?? derivedFontSizePx; + const averageGlyphWidth = estimateAverageGlyphWidth(fontSizePx); + const minWidthPx = width * Math.min(.92, widthRatio); + const maxWidthPx = width * clampNumber$1(widthRatio * widthScale, .66, .92); + return { + fontSizePx, + maxWidthPx: roundToInt(clampNumber$1(clampNumber$1(charsPerLine + extraChars, 25, 48) * averageGlyphWidth, minWidthPx, maxWidthPx)) + }; + } + //#endregion + //#region src/subtitles/smartWrap.ts + var STRONG_BREAK_RE = /[.!?…:;][)"'\]»”]*\s*$/u; + var SOFT_BREAK_RE = /[,،、][)"'\]»”]*\s*$/u; + var DISCOURAGED_LINE_START_RE = /^\s*[\p{Pe}\p{Pf},.;:!?%‰…]/u; + var DISCOURAGED_LINE_END_RE = /\s*[\p{Ps}\p{Pi}¿¡([{«“"'`-]\s*$/u; + var normalizeTokenText = (text) => text.replaceAll(/\s+/gu, " ").trim(); + var resolveBoundary = (text) => { + if (STRONG_BREAK_RE.test(text)) return "strong"; + if (SOFT_BREAK_RE.test(text)) return "soft"; + return "neutral"; + }; + var startsWithDiscouragedLineStart = (text) => DISCOURAGED_LINE_START_RE.test(text); + var endsWithDiscouragedLineEnd = (text) => DISCOURAGED_LINE_END_RE.test(text); + var isWordToken = (token) => Boolean(token?.isWordLike && token.text.trim()); + var getTokenStartMs = (token) => token && Number.isFinite(token.startMs) ? token.startMs : 0; + var getTokenEndMs = (token) => token ? getTokenStartMs(token) + Math.max(0, token.durationMs) : 0; + var getRangeStartMs = (tokens, start, end) => { + for (let index = start; index < end; index += 1) { + const token = tokens[index]; + if (isWordToken(token)) return getTokenStartMs(token); + } + return getTokenStartMs(tokens[start]); + }; + var getRangeEndMs = (tokens, start, end) => { + for (let index = end - 1; index >= start; index -= 1) { + const token = tokens[index]; + if (isWordToken(token)) return getTokenEndMs(token); + } + return getTokenEndMs(tokens[end - 1]); + }; + var createForcedBreakSlice = (tokens, tokenIndex) => { + const token = tokens[tokenIndex]; + const startMs = getTokenStartMs(token); + return { + text: "\n", + tokenIndex, + breakAfterTokenIndex: tokenIndex, + startToken: tokenIndex, + endToken: tokenIndex + 1, + charLength: 0, + startMs, + endMs: startMs, + boundary: "strong", + forcesLineBreak: true + }; + }; + var buildSliceFromWord = (tokens, wordTokenIndex) => { + let startToken = wordTokenIndex; + while (startToken > 0 && tokens[startToken - 1]?.text !== "\n" && !isWordToken(tokens[startToken - 1])) startToken -= 1; + let endToken = wordTokenIndex + 1; + while (endToken < tokens.length && tokens[endToken]?.text !== "\n" && !isWordToken(tokens[endToken])) endToken += 1; + const text = tokens.slice(startToken, endToken).map((token) => token.text).join(""); + return { + text, + tokenIndex: wordTokenIndex, + breakAfterTokenIndex: endToken - 1, + startToken, + endToken, + charLength: normalizeTokenText(text).length, + startMs: getRangeStartMs(tokens, startToken, endToken), + endMs: getRangeEndMs(tokens, startToken, endToken), + boundary: resolveBoundary(text), + forcesLineBreak: false + }; + }; + function buildWordSlices(tokens) { + const slices = []; + const keyParts = []; + let index = 0; + while (index < tokens.length) { + const token = tokens[index]; + if (!token?.text) { + index += 1; + continue; + } + if (token.text === "\n") { + const slice = createForcedBreakSlice(tokens, index); + slices.push(slice); + keyParts.push("\n"); + index += 1; + continue; + } + if (!isWordToken(token)) { + index += 1; + continue; + } + const slice = buildSliceFromWord(tokens, index); + slices.push(slice); + keyParts.push(normalizeTokenText(slice.text)); + index = slice.breakAfterTokenIndex + 1; + } + if (!slices.length && tokens.length) { + const text = tokens.map((token) => token.text).join(""); + slices.push({ + text, + tokenIndex: 0, + breakAfterTokenIndex: tokens.length - 1, + startToken: 0, + endToken: tokens.length, + charLength: normalizeTokenText(text).length, + startMs: getRangeStartMs(tokens, 0, tokens.length), + endMs: getRangeEndMs(tokens, 0, tokens.length), + boundary: resolveBoundary(text), + forcesLineBreak: false + }); + keyParts.push(normalizeTokenText(text)); + } + return { + slices, + key: keyParts.join("|") + }; + } + function measureWordSlices(wordSlices, measureText) { + return wordSlices.map((slice) => ({ + ...slice, + width: slice.forcesLineBreak ? 0 : measureText(slice.text) + })); + } + var getSegmentEndMs = (tokens, endTokenExclusive) => { + if (endTokenExclusive <= 0) return 0; + return getTokenEndMs(tokens[endTokenExclusive - 1]); + }; + var finalizeSegment = (out, tokens, startToken, endToken) => { + if (endToken <= startToken) return; + const startMs = getRangeStartMs(tokens, startToken, endToken); + const endMs = getSegmentEndMs(tokens, endToken); + out.push({ + startToken, + endToken, + startMs, + endMs: Math.max(startMs, endMs) + }); + }; + function computeTwoLineSegments(tokens, metrics, maxWidthPx, maxLength) { + if (!metrics.length || !tokens.length) return []; + const maxWidth = Math.max(1, maxWidthPx); + const charBudget = Math.max(1, maxLength); + const segments = []; + let segmentStartToken = metrics[0].startToken; + let segmentCharLength = 0; + let currentLineWidth = 0; + let currentLineCount = 1; + let lastTokenInSegment = segmentStartToken; + for (const metric of metrics) { + if (metric.forcesLineBreak) { + currentLineCount += 1; + currentLineWidth = 0; + lastTokenInSegment = metric.endToken; + if (currentLineCount > 2) { + const splitToken = Math.max(metric.startToken, metric.tokenIndex); + finalizeSegment(segments, tokens, segmentStartToken, splitToken); + segmentStartToken = splitToken; + segmentCharLength = 0; + lastTokenInSegment = segmentStartToken; + } + continue; + } + const nextCharLength = segmentCharLength + metric.charLength; + if ((currentLineWidth === 0 || currentLineWidth + metric.width <= maxWidth) && nextCharLength <= charBudget) { + currentLineWidth += metric.width; + segmentCharLength = nextCharLength; + lastTokenInSegment = metric.endToken; + continue; + } + if (currentLineCount === 1) { + currentLineCount = 2; + currentLineWidth = metric.width; + segmentCharLength = nextCharLength; + lastTokenInSegment = metric.endToken; + continue; + } + const splitToken = Math.max(metric.startToken, metric.tokenIndex); + finalizeSegment(segments, tokens, segmentStartToken, splitToken); + segmentStartToken = splitToken; + segmentCharLength = metric.charLength; + currentLineWidth = metric.width; + currentLineCount = 1; + lastTokenInSegment = metric.endToken; + } + finalizeSegment(segments, tokens, segmentStartToken, lastTokenInSegment); + if (!segments.length) return [{ + startToken: 0, + endToken: tokens.length, + startMs: getRangeStartMs(tokens, 0, tokens.length), + endMs: getRangeEndMs(tokens, 0, tokens.length) + }]; + for (let index = 0; index < segments.length - 1; index += 1) { + const current = segments[index]; + const next = segments[index + 1]; + if (next.startMs > current.startMs) current.endMs = next.startMs; + } + const last = segments.at(-1); + if (last) last.endMs = Math.max(last.endMs, getRangeEndMs(tokens, last.startToken, last.endToken)); + return segments.filter((segment) => segment.endToken > segment.startToken); + } + var measureTokenRange = (tokens, startToken, endToken, measureText) => { + if (endToken <= startToken) return 0; + return measureText(tokens.slice(startToken, endToken).map((token) => token.text).join("")); + }; + var resolveSafeBreakAfterTokenIndex = (tokens, breakAfterTokenIndex) => { + let safeBreakIndex = breakAfterTokenIndex; + while (safeBreakIndex + 1 < tokens.length && tokens[safeBreakIndex + 1]?.text !== "\n" && !tokens[safeBreakIndex + 1]?.isWordLike) safeBreakIndex += 1; + return safeBreakIndex; + }; + var findFallbackBreakAfterTokenIndex = (tokens, measureText, maxWidthPx) => { + let bestBreakAfterTokenIndex = null; + let bestScore = Number.POSITIVE_INFINITY; + for (let index = 0; index < tokens.length - 1; index += 1) { + const token = tokens[index]; + const nextToken = tokens[index + 1]; + if (!token?.text || !nextToken?.text || nextToken.text === "\n") continue; + const candidateBreakAfterTokenIndex = resolveSafeBreakAfterTokenIndex(tokens, index); + if (candidateBreakAfterTokenIndex >= tokens.length - 1) continue; + const firstEndToken = candidateBreakAfterTokenIndex + 1; + const secondStartToken = firstEndToken; + const firstWidth = measureTokenRange(tokens, 0, firstEndToken, measureText); + const secondWidth = measureTokenRange(tokens, secondStartToken, tokens.length, measureText); + const firstText = tokens.slice(0, firstEndToken).map((currentToken) => currentToken.text).join(""); + const secondText = tokens.slice(secondStartToken).map((currentToken) => currentToken.text).join(""); + const score = Math.max(0, firstWidth - maxWidthPx) * 12 + Math.max(0, secondWidth - maxWidthPx) * 12 + Math.abs(secondWidth - firstWidth) * .4 + (startsWithDiscouragedLineStart(secondText) ? 260 : 0) + (endsWithDiscouragedLineEnd(firstText) ? 70 : 0); + if (score < bestScore) { + bestScore = score; + bestBreakAfterTokenIndex = candidateBreakAfterTokenIndex; + } + } + return bestBreakAfterTokenIndex; + }; + var scoreBreakCandidate = ({ firstWidth, secondWidth, firstText, secondText, firstWordCount, secondWordCount, maxWidthPx, boundary }) => { + const overflowPenalty = Math.max(0, firstWidth - maxWidthPx) * 12 + Math.max(0, secondWidth - maxWidthPx) * 12; + const balancePenalty = Math.abs(secondWidth / Math.max(firstWidth, 1) - 1.08) * 120; + const shortTopPenalty = firstWordCount < 2 ? 80 : 0; + const orphanPenalty = secondWordCount < 2 ? 80 : 0; + const lineStartPenalty = startsWithDiscouragedLineStart(secondText) ? 260 : 0; + const lineEndPenalty = endsWithDiscouragedLineEnd(firstText) ? 70 : 0; + const boundaryBonus = boundary === "strong" ? -28 : boundary === "soft" ? -14 : 0; + return overflowPenalty + balancePenalty + shortTopPenalty + orphanPenalty + lineStartPenalty + lineEndPenalty + boundaryBonus; + }; + function computeTokenWrapPlan(tokens, measureText, maxWidthPx) { + if (!tokens.length) return { breakAfterTokenIndices: [] }; + if (tokens.reduce((count, token) => count + Number(token.text === "\n"), 0) > 0) return { breakAfterTokenIndices: [] }; + const { slices } = buildWordSlices(tokens); + const measurableSlices = slices.filter((slice) => !slice.forcesLineBreak); + if (!measurableSlices.length) return { breakAfterTokenIndices: [] }; + if (measureTokenRange(tokens, 0, tokens.length, measureText) <= maxWidthPx) return { breakAfterTokenIndices: [] }; + let bestBreakAfterTokenIndex = null; + let bestScore = Number.POSITIVE_INFINITY; + for (let index = 0; index < measurableSlices.length - 1; index += 1) { + const slice = measurableSlices[index]; + const nextSlice = measurableSlices[index + 1]; + const candidateBreakAfterTokenIndex = Math.max(slice.breakAfterTokenIndex, nextSlice.tokenIndex - 1); + const firstEndToken = candidateBreakAfterTokenIndex + 1; + const secondStartToken = nextSlice.tokenIndex; + const score = scoreBreakCandidate({ + firstWidth: measureTokenRange(tokens, 0, firstEndToken, measureText), + secondWidth: measureTokenRange(tokens, secondStartToken, tokens.length, measureText), + firstText: tokens.slice(0, firstEndToken).map((token) => token.text).join(""), + secondText: tokens.slice(secondStartToken).map((token) => token.text).join(""), + firstWordCount: index + 1, + secondWordCount: measurableSlices.length - (index + 1), + maxWidthPx, + boundary: slice.boundary + }); + if (score < bestScore) { + bestScore = score; + bestBreakAfterTokenIndex = candidateBreakAfterTokenIndex; + } + } + if (bestBreakAfterTokenIndex !== null) return { breakAfterTokenIndices: [bestBreakAfterTokenIndex] }; + const fallbackBreakAfterTokenIndex = findFallbackBreakAfterTokenIndex(tokens, measureText, maxWidthPx); + if (fallbackBreakAfterTokenIndex !== null) return { breakAfterTokenIndices: [fallbackBreakAfterTokenIndex] }; + return { breakAfterTokenIndices: [] }; + } + //#endregion + //#region src/subtitles/widget.ts + var WRAP_WIDTH_GUARD_PX = 8; + var WRAP_WIDTH_GUARD_RATIO = .97; + var MIN_EFFECTIVE_WRAP_WIDTH_PX = 24; + function applyWrapWidthGuard(maxWidthPx) { + if (!Number.isFinite(maxWidthPx) || maxWidthPx <= 0) return 0; + const byPixelGuard = maxWidthPx - WRAP_WIDTH_GUARD_PX; + const byRatioGuard = maxWidthPx * WRAP_WIDTH_GUARD_RATIO; + return Math.max(MIN_EFFECTIVE_WRAP_WIDTH_PX, Math.min(byPixelGuard, byRatioGuard)); + } + var SubtitlesWidget = class { + video; + container; + fullscreenLayerController; + tooltipMount; + subtitlesContainer = null; + subtitlesBlock = null; + renderedHighlightEls = []; + passedFlagsBuffer = []; + subtitles = null; + subtitleLang; + lastRenderKey = null; + lastActiveLineKey = null; + maxActiveCueLookbackMs = 0; + highlightWords = false; + fontSize = 20; + fontSizeOverridden = false; + fontFamily = "default-sans"; + maxLength = 300; + smartLayoutEnabled = true; + smartFontSizePx = 0; + smartMaxWidthPx = 0; + smartAnchorWidthPx = 0; + smartAnchorHeightPx = 0; + lastSmartLayoutKey = null; + lastSmartLayoutCheckTs = 0; + opacity = "0.2"; + repositionPending = false; + positionRefreshPending = false; + updatePending = false; + lastUpdateRequestTs = 0; + updateMinIntervalMs = 100; + updateMinIntervalHighlightMs = 33; + useVideoFrameCallbacks; + videoFrameRequestId = null; + lastPlaybackTimeMs = null; + dragDocListenersAttached = false; + lastPositionRefreshTs = 0; + positionRefreshIntervalMs = 250; + subtitleMaxWidthPx = 0; + breakAfterTokenIndices = []; + breakAfterTokenIndexSet = null; + wrapPending = false; + lastWrapKey = null; + lastWrapTokens = null; + measureCanvas = null; + measureCtx = null; + tokenProcessingMemo = null; + tokenPrecomputeMemo = null; + lineMeasureMemo = null; + lastSegmentIndex = 0; + lastAppliedLeftPct = null; + lastAppliedTopPct = null; + position = { + left: 50, + top: 100 + }; + customVerticalAnchorState = null; + positionPreset = "bottom-center"; + dragging = { + pointerId: null, + candidate: false, + active: false, + moved: false, + startClientX: 0, + startClientY: 0, + offset: { + x: 0, + y: 0 + } + }; + dragStartThresholdPx = 4; + snapThresholdPx = 18; + suppressTokenClicksUntil = 0; + abortController = new AbortController(); + resizeObserver; + tokenTooltip; + tooltipTranslationRequestId = 0; + intervalIdleChecker; + checkerUnsubscribe = null; + edgePunctuationTrimRe = /(?:^[\p{P}\p{S}]+|[\p{P}\p{S}]+$)/gu; + strTokens = ""; + strTranslatedTokens = ""; + passedStateKey = null; + passedThresholds = []; + normalizeTokenTextForTranslation(raw) { + return raw.trim().replace(this.edgePunctuationTrimRe, ""); + } + bottomInsetCachedPx = 0; + safeAreaBottomInsetCachedPx = 0; + containerPaddingBottomCachedPx = 0; + insetCacheReady = false; + bottomInsetByMode = { + normal: { + ratio: .1, + minPx: 56, + maxPx: 220, + gapPx: 10 + }, + fullscreen: { + ratio: .07, + minPx: 44, + maxPx: 140, + gapPx: 9 + } + }; + safeAreaProbeEl = null; + guidesLayer = null; + verticalGuide = null; + horizontalGuide = null; + onPointerDownBound; + onPointerUpBound; + onPointerMoveBound; + onPlaybackStateChangeBound; + onVisualViewportChangeBound; + constructor(video, container, intervalIdleChecker) { + this.video = video; + this.container = container; + this.fullscreenLayerController = new FullscreenLayerController({ container }); + this.intervalIdleChecker = intervalIdleChecker; + this.useVideoFrameCallbacks = !!this.video && typeof this.video.requestVideoFrameCallback === "function"; + this.onPointerDownBound = (event) => this.onPointerDown(event); + this.onPointerUpBound = (event) => this.onPointerUp(event); + this.onPointerMoveBound = (event) => this.onPointerMove(event); + this.onPlaybackStateChangeBound = () => this.handlePlaybackStateChange(); + this.onVisualViewportChangeBound = () => this.scheduleReposition(); + this.checkerUnsubscribe = this.intervalIdleChecker.subscribe(() => { + this.onCheckerTick(); + }); + this.bindEvents(); + } + updateMount({ container }) { + const containerChanged = this.container !== container; + this.container = container; + this.fullscreenLayerController.updateContainer(container); + this.syncWidgetMount(); + if (containerChanged) { + const parentElement = this.getTokenTooltipParentElement(); + this.tokenTooltip?.updateMount({ + parentElement, + layoutRoot: this.tooltipMount?.host + }); + } + if (this.subtitles) { + this.insetCacheReady = false; + this.lastAppliedLeftPct = null; + this.lastAppliedTopPct = null; + this.updateContainerRect(); + this.requestUpdate(); + } + } + resetTranslationContext(releaseTooltip = false) { + this.strTranslatedTokens = ""; + if (releaseTooltip) this.releaseTooltip(); + } + resetSegmentationMemo() { + this.tokenProcessingMemo = null; + this.tokenPrecomputeMemo = null; + this.lineMeasureMemo = null; + this.lastSegmentIndex = 0; + } + resetWrapMemo() { + this.setBreakAfterTokenIndices([]); + this.lastWrapKey = null; + } + resetRenderMemo() { + this.lastRenderKey = null; + } + computeAnchorBoxLayout(layout) { + const fallback = { + left: 0, + top: 0, + w: layout.w, + h: layout.h + }; + const video = this.video; + if (!video) return fallback; + const videoRect = video.getBoundingClientRect(); + if (!(videoRect.width > 0 && videoRect.height > 0)) return fallback; + const containerRect = layout.rect; + if (!(videoRect.right > containerRect.left && videoRect.left < containerRect.right && videoRect.bottom > containerRect.top && videoRect.top < containerRect.bottom)) return fallback; + const w = videoRect.width / layout.scaleX; + const h = videoRect.height / layout.scaleY; + if (!(w > 0 && h > 0)) return fallback; + const rawLeft = (videoRect.left - containerRect.left) / layout.scaleX; + const rawTop = (videoRect.top - containerRect.top) / layout.scaleY; + const maxLeft = layout.w - w; + const maxTop = layout.h - h; + return { + left: maxLeft >= 0 ? clampToRange(rawLeft, 0, maxLeft) : (layout.w - w) / 2, + top: maxTop >= 0 ? clampToRange(rawTop, 0, maxTop) : (layout.h - h) / 2, + w, + h + }; + } + readSmartCssMetrics() { + const block = this.subtitlesBlock; + if (!block) return null; + const cs = getComputedStyle(block); + const fontSizePx = Number.parseFloat(cs.fontSize); + const maxWidthRawPx = Number.parseFloat(cs.maxWidth); + if (!Number.isFinite(fontSizePx) || !Number.isFinite(maxWidthRawPx) || fontSizePx <= 0 || maxWidthRawPx <= 0) return null; + this.subtitleMaxWidthPx = maxWidthRawPx; + const paddingLeft = Number.parseFloat(cs.paddingLeft) || 0; + const paddingRight = Number.parseFloat(cs.paddingRight) || 0; + const maxWidthPx = Math.max(0, maxWidthRawPx - paddingLeft - paddingRight); + if (maxWidthPx <= 0) return null; + return { + fontSizePx, + maxWidthPx + }; + } + ensureSmartLayout(anchorBox) { + if (!this.smartLayoutEnabled) return null; + const cssMetrics = this.readSmartCssMetrics(); + const nextFontSizePx = cssMetrics?.fontSizePx ?? this.smartFontSizePx; + const next = computeSmartLayoutForBox(anchorBox, cssMetrics); + const nextMaxWidthPx = next.maxWidthPx ?? this.smartMaxWidthPx; + const nextKey = `${Math.round(nextFontSizePx)}|${Math.round(nextMaxWidthPx)}|${Math.round(next.maxWidthPx ?? 0)}`; + const fontChanged = Math.abs(nextFontSizePx - this.smartFontSizePx) > .5; + const widthChanged = Math.abs(nextMaxWidthPx - this.smartMaxWidthPx) > .5; + if (nextKey !== this.lastSmartLayoutKey) { + this.lastSmartLayoutKey = nextKey; + this.smartFontSizePx = nextFontSizePx; + this.smartMaxWidthPx = nextMaxWidthPx; + this.resetRenderMemo(); + } + this.setSubtitlesContainerVar("--vot-subtitles-max-width", next.maxWidthPx && next.maxWidthPx > 0 ? `${next.maxWidthPx}px` : null); + if ((fontChanged || widthChanged) && this.lastWrapTokens) { + this.lastWrapKey = null; + this.resetSegmentationMemo(); + this.scheduleWrapRecompute(); + } + return next; + } + scheduleReposition() { + if (this.abortController.signal.aborted) return; + if (!this.subtitles) return; + this.repositionPending = true; + this.intervalIdleChecker.markActivity("subtitles-reposition"); + this.intervalIdleChecker.requestImmediateTick(); + } + setSubtitlesContainerVar(name, value) { + const container = this.subtitlesContainer; + if (!container) return; + if (value === null) { + container.style.removeProperty(name); + return; + } + container.style.setProperty(name, value); + } + applyOpacityStyle() { + this.setSubtitlesContainerVar("--vot-subtitles-opacity", this.opacity); + } + applyManualFontSizeStyle() { + if (!this.smartLayoutEnabled && this.fontSizeOverridden) { + this.setSubtitlesContainerVar("--vot-subtitles-font-size", `${this.fontSize}px`); + return; + } + this.setSubtitlesContainerVar("--vot-subtitles-font-size", null); + } + applyFontFamilyStyle() { + const fontFamily = this.fontFamily; + this.setSubtitlesContainerVar("--vot-subtitles-font-family-custom", getSubtitleFontFamilyCssValue(fontFamily)); + ensureGoogleSubtitleFontLoaded(fontFamily, { + forceGmXhr: true, + onLoaded: () => { + if (this.fontFamily !== fontFamily) return; + this.lastWrapKey = null; + this.resetSegmentationMemo(); + this.scheduleWrapRecompute(); + this.scheduleReposition(); + } + }); + } + syncVisualStyleVars() { + this.applyOpacityStyle(); + this.applyManualFontSizeStyle(); + this.applyFontFamilyStyle(); + } + ensureGuidesLayer() { + if (this.guidesLayer) return this.guidesLayer; + const layer = document.createElement("vot-block"); + layer.classList.add("vot-subtitles-guides"); + const verticalGuide = document.createElement("vot-block"); + verticalGuide.classList.add("vot-subtitles-guide", "vot-subtitles-guide--vertical"); + const horizontalGuide = document.createElement("vot-block"); + horizontalGuide.classList.add("vot-subtitles-guide", "vot-subtitles-guide--horizontal"); + layer.append(verticalGuide, horizontalGuide); + this.guidesLayer = layer; + this.verticalGuide = verticalGuide; + this.horizontalGuide = horizontalGuide; + this.hideSnapGuides(); + return layer; + } + hideSnapGuides() { + this.verticalGuide?.removeAttribute("data-visible"); + this.horizontalGuide?.removeAttribute("data-visible"); + } + updateSnapGuides(anchorBox, options) { + const { showVerticalCenter = false, showHorizontalCenter = false } = options; + if (!this.ensureGuidesLayer().isConnected) this.syncGuideLayerMount(); + if (this.verticalGuide) { + this.verticalGuide.style.left = `${anchorBox.left + anchorBox.w / 2}px`; + this.verticalGuide.style.top = `${anchorBox.top}px`; + this.verticalGuide.style.height = `${anchorBox.h}px`; + if (showVerticalCenter) this.verticalGuide.dataset.visible = "true"; + else delete this.verticalGuide.dataset.visible; + } + if (this.horizontalGuide) { + this.horizontalGuide.style.left = `${anchorBox.left}px`; + this.horizontalGuide.style.top = `${anchorBox.top + anchorBox.h / 2}px`; + this.horizontalGuide.style.width = `${anchorBox.w}px`; + if (showHorizontalCenter) this.horizontalGuide.dataset.visible = "true"; + else delete this.horizontalGuide.dataset.visible; + } + } + syncGuideLayerMount() { + const guidesLayer = this.ensureGuidesLayer(); + if (guidesLayer.parentElement !== this.container) this.container.appendChild(guidesLayer); + } + syncWidgetMount() { + this.fullscreenLayerController.syncWidgetContainer(null); + if (this.subtitlesContainer && this.subtitlesContainer.parentElement !== this.container) this.container.appendChild(this.subtitlesContainer); + if (this.tooltipMount) reparentShadowMount(this.tooltipMount, this.container); + this.syncGuideLayerMount(); + } + ensureTooltipMount() { + if (!this.tooltipMount) this.tooltipMount = createShadowMount({ + parent: this.container, + rootClasses: ["vot-portal-local"], + hostStyles: { + position: "absolute", + inset: "0", + display: "block", + "pointer-events": "none" + }, + rootStyles: { + position: "relative", + display: "block", + width: "100%", + height: "100%", + "pointer-events": "none" + } + }); + else reparentShadowMount(this.tooltipMount, this.container); + return this.tooltipMount; + } + getTokenTooltipParentElement() { + return this.ensureTooltipMount().root; + } + createSubtitlesContainer() { + if (this.subtitlesContainer) return this.subtitlesContainer; + const container = document.createElement("vot-block"); + container.classList.add("vot-subtitles-widget"); + this.subtitlesContainer = container; + this.syncWidgetMount(); + container.addEventListener("pointerdown", this.onPointerDownBound, { + signal: this.abortController.signal, + passive: false, + capture: true + }); + this.syncVisualStyleVars(); + this.insetCacheReady = false; + this.updateContainerRect(); + return container; + } + bindEvents() { + const { signal } = this.abortController; + const opts = { signal }; + this.video?.addEventListener("play", this.onPlaybackStateChangeBound, opts); + this.video?.addEventListener("pause", this.onPlaybackStateChangeBound, opts); + this.video?.addEventListener("seeking", this.onPlaybackStateChangeBound, opts); + this.video?.addEventListener("seeked", this.onPlaybackStateChangeBound, opts); + this.video?.addEventListener("ended", this.onPlaybackStateChangeBound, opts); + this.resizeObserver = new ResizeObserver(() => this.onResize()); + this.resizeObserver.observe(this.container); + if (this.video) this.resizeObserver.observe(this.video); + globalThis.visualViewport?.addEventListener("resize", this.onVisualViewportChangeBound, opts); + globalThis.visualViewport?.addEventListener("scroll", this.onVisualViewportChangeBound, opts); + } + getUpdateMinIntervalMs() { + return this.highlightWords ? this.updateMinIntervalHighlightMs : this.updateMinIntervalMs; + } + requestUpdate(playbackTimeMs, now = performance.now()) { + if (this.abortController.signal.aborted) return; + if (!this.subtitles) return; + if (typeof playbackTimeMs === "number" && Number.isFinite(playbackTimeMs)) this.lastPlaybackTimeMs = Math.max(0, playbackTimeMs); + else if (this.video) this.lastPlaybackTimeMs = Math.max(0, this.video.currentTime * 1e3); + const minInterval = this.getUpdateMinIntervalMs(); + if (now - this.lastUpdateRequestTs < minInterval) return; + this.lastUpdateRequestTs = now; + this.updatePending = true; + this.intervalIdleChecker.requestImmediateTick(); + } + resolvePlaybackTimeMs() { + if (typeof this.lastPlaybackTimeMs === "number" && Number.isFinite(this.lastPlaybackTimeMs)) return this.lastPlaybackTimeMs; + return this.video ? Math.max(0, this.video.currentTime * 1e3) : 0; + } + handlePlaybackStateChange() { + if (!this.subtitles) { + this.stopVideoFrameLoop(); + return; + } + this.scheduleReposition(); + this.requestUpdate(this.video ? Math.max(0, this.video.currentTime * 1e3) : 0); + this.syncVideoFrameLoop(); + } + syncVideoFrameLoop() { + if (!this.useVideoFrameCallbacks) return; + const video = this.video; + if (!video) return; + if (!this.subtitles || video.paused || video.ended) { + this.stopVideoFrameLoop(); + return; + } + this.startVideoFrameLoop(); + } + startVideoFrameLoop() { + if (!this.useVideoFrameCallbacks) return; + const video = this.video; + if (!video) return; + if (this.videoFrameRequestId !== null) return; + this.videoFrameRequestId = video.requestVideoFrameCallback(this.onVideoFrame); + } + stopVideoFrameLoop() { + if (!this.useVideoFrameCallbacks) return; + const video = this.video; + if (!video) return; + if (this.videoFrameRequestId === null) return; + try { + video.cancelVideoFrameCallback(this.videoFrameRequestId); + } catch {} + this.videoFrameRequestId = null; + } + onVideoFrame = (now, metadata) => { + this.videoFrameRequestId = null; + if (this.abortController.signal.aborted) return; + const video = this.video; + if (!video || video.paused || video.ended) return; + if (!this.subtitles) return; + const playbackTimeMs = typeof metadata.mediaTime === "number" && Number.isFinite(metadata.mediaTime) ? metadata.mediaTime * 1e3 : void 0; + this.requestUpdate(playbackTimeMs, now); + this.startVideoFrameLoop(); + }; + onCheckerTick() { + if (this.abortController.signal.aborted) return; + if (this.repositionPending) { + this.repositionPending = false; + this.updateContainerRect(); + this.updatePending = true; + } + if (this.wrapPending) { + this.wrapPending = false; + this.recomputeWrapNow(); + } + if (this.positionRefreshPending) { + this.positionRefreshPending = false; + this.applySubtitlePosition(); + } + if (this.updatePending) { + this.updatePending = false; + this.update(); + } + } + attachDragDocumentListeners() { + if (this.dragDocListenersAttached) return; + this.dragDocListenersAttached = true; + document.addEventListener("pointermove", this.onPointerMoveBound, { + passive: false, + capture: true + }); + document.addEventListener("pointerup", this.onPointerUpBound, true); + document.addEventListener("pointercancel", this.onPointerUpBound, true); + } + detachDragDocumentListeners() { + if (!this.dragDocListenersAttached) return; + this.dragDocListenersAttached = false; + document.removeEventListener("pointermove", this.onPointerMoveBound, true); + document.removeEventListener("pointerup", this.onPointerUpBound, true); + document.removeEventListener("pointercancel", this.onPointerUpBound, true); + } + onResize() { + this.syncWidgetMount(); + this.scheduleReposition(); + } + updateContainerRect() { + const layout = this.getLayoutSize(); + if (!layout.w || !layout.h) return; + const anchorBox = this.computeAnchorBoxLayout(layout); + if (!anchorBox.w || !anchorBox.h) return; + this.refreshBottomInsetNow(layout, anchorBox); + this.applySubtitlePositionWithLayout(layout, anchorBox); + } + getLayoutSize() { + const layoutRoot = this.fullscreenLayerController.getLayoutRootElement(); + const rect = layoutRoot.getBoundingClientRect(); + const w = layoutRoot.clientWidth || rect.width; + const h = layoutRoot.clientHeight || rect.height; + return { + w, + h, + rect, + scaleX: rect.width && w ? rect.width / w : 1, + scaleY: rect.height && h ? rect.height / h : 1 + }; + } + ensureSafeAreaProbe() { + if (this.safeAreaProbeEl) return; + const el = document.createElement("div"); + el.style.position = "fixed"; + el.style.left = "0"; + el.style.right = "0"; + el.style.bottom = "0"; + el.style.height = "env(safe-area-inset-bottom, 0px)"; + el.style.pointerEvents = "none"; + el.style.opacity = "0"; + el.style.zIndex = "-1"; + document.documentElement.appendChild(el); + this.safeAreaProbeEl = el; + } + getSafeAreaBottomInsetPx() { + this.ensureSafeAreaProbe(); + if (!this.safeAreaProbeEl) return 0; + return this.safeAreaProbeEl.offsetHeight || 0; + } + refreshInsetCache() { + const layoutRoot = this.fullscreenLayerController.getLayoutRootElement(); + this.safeAreaBottomInsetCachedPx = this.getSafeAreaBottomInsetPx(); + this.containerPaddingBottomCachedPx = Number.parseFloat(getComputedStyle(layoutRoot).paddingBottom || "0") || 0; + this.insetCacheReady = true; + } + isMobileViewport() { + if (typeof globalThis.matchMedia !== "function") return false; + return globalThis.matchMedia("(max-width: 900px) and (pointer: coarse)").matches; + } + getBottomInsetPreset() { + const doc = document; + const fullscreenEl = doc.fullscreenElement ?? doc.webkitFullscreenElement; + if (!(fullscreenEl instanceof Element)) return this.bottomInsetByMode.normal; + const { container, video } = this; + if (fullscreenEl === container || fullscreenEl.contains(container) || container.contains(fullscreenEl)) return this.bottomInsetByMode.fullscreen; + if (video && (fullscreenEl === video || fullscreenEl.contains(video) || video.contains(fullscreenEl))) return this.bottomInsetByMode.fullscreen; + return this.bottomInsetByMode.normal; + } + computeReservedBottomInsetPx(anchorBoxH, preset = this.getBottomInsetPreset()) { + return clampToRange(anchorBoxH * preset.ratio, preset.minPx, preset.maxPx); + } + refreshBottomInsetNow(layout, anchorBox) { + this.refreshInsetCache(); + const anchorH = anchorBox?.h ?? this.computeAnchorBoxLayout(layout ?? this.getLayoutSize()).h; + if (!anchorH) { + this.bottomInsetCachedPx = 0; + return; + } + const preset = this.getBottomInsetPreset(); + this.bottomInsetCachedPx = this.computeReservedBottomInsetPx(anchorH, preset); + } + getBottomInsetPx(layout, anchorBox) { + if (!this.insetCacheReady) this.refreshInsetCache(); + const preset = this.getBottomInsetPreset(); + const safeAreaBottom = this.safeAreaBottomInsetCachedPx; + const paddingBottom = this.containerPaddingBottomCachedPx; + if (this.isMobileViewport()) return Math.max(paddingBottom, safeAreaBottom); + const anchorH = anchorBox?.h ?? this.computeAnchorBoxLayout(layout ?? this.getLayoutSize()).h; + const reserved = anchorH ? this.computeReservedBottomInsetPx(anchorH, preset) : preset.minPx; + const stableInset = Math.max(this.bottomInsetCachedPx, reserved); + return Math.max(paddingBottom, safeAreaBottom, stableInset) + preset.gapPx; + } + onPointerDown(event) { + const subtitlesContainer = this.subtitlesContainer; + if (!subtitlesContainer) return; + const target = event.target; + if (!(target instanceof Node) || !subtitlesContainer.contains(target)) return; + if (!event.isPrimary) return; + if (event.pointerType === "mouse" && event.button !== 0) return; + event.stopPropagation(); + const layout = this.getLayoutSize(); + const { rect: containerRect, w, h, scaleX, scaleY } = layout; + if (!w || !h) return; + const anchorBox = this.computeAnchorBoxLayout(layout); + if (!anchorBox.w || !anchorBox.h) return; + this.lastPositionRefreshTs = performance.now(); + const subRect = subtitlesContainer.getBoundingClientRect(); + const pointerX = (event.clientX - containerRect.left) / scaleX - anchorBox.left; + const pointerY = (event.clientY - containerRect.top) / scaleY - anchorBox.top; + const anchorX = (subRect.left - containerRect.left + subRect.width / 2) / scaleX - anchorBox.left; + const anchorY = (subRect.top - containerRect.top + subRect.height) / scaleY - anchorBox.top; + this.dragging.pointerId = event.pointerId; + this.dragging.candidate = true; + this.dragging.active = false; + this.dragging.moved = false; + this.dragging.startClientX = event.clientX; + this.dragging.startClientY = event.clientY; + this.dragging.offset.x = anchorX - pointerX; + this.dragging.offset.y = anchorY - pointerY; + this.hideSnapGuides(); + this.attachDragDocumentListeners(); + } + onPointerUp(event) { + if (this.dragging.pointerId === null) return; + if (event.pointerId !== this.dragging.pointerId) return; + if (this.dragging.moved) this.suppressTokenClicksUntil = performance.now() + 450; + this.dragging.pointerId = null; + this.dragging.candidate = false; + this.dragging.active = false; + this.dragging.moved = false; + this.hideSnapGuides(); + this.detachDragDocumentListeners(); + } + onPointerMove(event) { + if (!this.dragging.candidate || this.dragging.pointerId === null) return; + if (event.pointerId !== this.dragging.pointerId) return; + if (!this.dragging.active) { + if (!hasDragThresholdBeenExceeded(this.dragging.startClientX, this.dragging.startClientY, event.clientX, event.clientY, this.dragStartThresholdPx)) return; + this.dragging.active = true; + this.dragging.moved = true; + this.suppressTokenClicksUntil = performance.now() + 450; + this.releaseTooltip(); + try { + this.subtitlesContainer?.setPointerCapture(event.pointerId); + } catch {} + } else this.dragging.moved = true; + event.preventDefault(); + event.stopPropagation(); + const layout = this.getLayoutSize(); + const { rect: containerRect, w, h, scaleX, scaleY } = layout; + if (!w || !h) return; + const anchorBox = this.computeAnchorBoxLayout(layout); + if (!anchorBox.w || !anchorBox.h) return; + const pointerX = (event.clientX - containerRect.left) / scaleX - anchorBox.left; + const pointerY = (event.clientY - containerRect.top) / scaleY - anchorBox.top; + let anchorX = pointerX + this.dragging.offset.x; + let anchorY = pointerY + this.dragging.offset.y; + const elW = this.subtitlesContainer?.offsetWidth ?? 0; + const elH = this.subtitlesContainer?.offsetHeight ?? 0; + const bottomInset = this.getBottomInsetPx(layout, anchorBox); + const snappedX = snapValueToNearestCandidate({ + current: anchorX, + candidates: [anchorBox.w / 2], + thresholdPx: this.snapThresholdPx + }); + if (snappedX.snapped) anchorX = snappedX.value; + const verticalCenterAnchor = anchorBox.h / 2 + elH / 2; + const snappedY = snapValueToNearestCandidate({ + current: anchorY, + candidates: [verticalCenterAnchor], + thresholdPx: this.snapThresholdPx + }); + if (snappedY.snapped) anchorY = snappedY.value; + ({anchorX, anchorY} = clampAnchorWithinBox({ + anchorX, + anchorY, + elementWidth: elW, + elementHeight: elH, + boxWidth: anchorBox.w, + boxHeight: anchorBox.h, + bottomInset + })); + this.positionPreset = "custom"; + this.customVerticalAnchorState = captureCustomVerticalAnchorState({ + anchorY, + elementHeight: elH, + boxHeight: anchorBox.h, + bottomInset + }); + this.position.left = anchorX / anchorBox.w * 100; + this.position.top = anchorY / anchorBox.h * 100; + this.updateSnapGuides(anchorBox, { + showVerticalCenter: snappedX.snapped, + showHorizontalCenter: snappedY.snapped + }); + this.applySubtitlePositionWithLayout(layout, anchorBox); + } + applySubtitlePosition() { + if (!this.subtitlesContainer) return; + const layout = this.getLayoutSize(); + if (!layout.w || !layout.h) return; + const anchorBox = this.computeAnchorBoxLayout(layout); + if (!anchorBox.w || !anchorBox.h) return; + this.applySubtitlePositionWithLayout(layout, anchorBox); + } + applySubtitlePositionWithLayout(layout, anchorBox) { + const subtitlesContainer = this.subtitlesContainer; + if (!subtitlesContainer) return; + this.applyScaleCompensation(subtitlesContainer, layout); + this.syncAnchorDimensions(subtitlesContainer, anchorBox); + if (this.smartLayoutEnabled) this.ensureSmartLayout(anchorBox); + const elW = subtitlesContainer.offsetWidth; + const elH = subtitlesContainer.offsetHeight; + const bottomInset = this.getBottomInsetPx(layout, anchorBox); + const anchorPosition = this.resolveCurrentAnchorPosition(anchorBox, elW, elH, bottomInset); + const containerPosition = this.clampContainerPosition(anchorBox, anchorPosition.anchorX, anchorPosition.anchorY, elW, elH, bottomInset); + const anchorX = containerPosition.anchorX; + const anchorY = containerPosition.anchorY; + const containerAnchorX = anchorBox.left + anchorX; + const containerAnchorY = anchorBox.top + anchorY; + const leftPct = containerAnchorX / layout.w * 100; + const topPct = containerAnchorY / layout.h * 100; + this.updateContainerPosition(subtitlesContainer, leftPct, topPct); + this.tokenTooltip?.updatePos(); + } + applyScaleCompensation(subtitlesContainer, layout) { + const visualScale = Math.min(layout.scaleX || 1, layout.scaleY || 1); + const compensate = visualScale > 0 && visualScale < .999 ? Math.min(1 / visualScale, 3) : 1; + if (Math.abs(compensate - 1) < .001) { + subtitlesContainer.style.removeProperty("--vot-subtitles-scale-compensation"); + return; + } + subtitlesContainer.style.setProperty("--vot-subtitles-scale-compensation", compensate.toFixed(3)); + } + syncAnchorDimensions(subtitlesContainer, anchorBox) { + const anchorWidthPx = Math.max(1, Math.round(anchorBox.w)); + const anchorHeightPx = Math.max(1, Math.round(anchorBox.h)); + if (!(anchorWidthPx !== this.smartAnchorWidthPx || anchorHeightPx !== this.smartAnchorHeightPx)) return; + this.smartAnchorWidthPx = anchorWidthPx; + this.smartAnchorHeightPx = anchorHeightPx; + subtitlesContainer.style.setProperty("--vot-subtitles-anchor-width", `${anchorWidthPx}px`); + subtitlesContainer.style.setProperty("--vot-subtitles-anchor-height", `${anchorHeightPx}px`); + if (this.lastWrapTokens) { + this.lastWrapKey = null; + this.resetSegmentationMemo(); + this.scheduleWrapRecompute(); + } + } + resolveCurrentAnchorPosition(anchorBox, elementWidth, elementHeight, bottomInset) { + let anchorX = this.position.left / 100 * anchorBox.w; + let anchorY = this.position.top / 100 * anchorBox.h; + if (this.positionPreset === "custom") { + anchorY = resolveCustomVerticalAnchor({ + state: this.customVerticalAnchorState, + elementHeight, + boxHeight: anchorBox.h, + bottomInset + }); + return { + anchorX, + anchorY + }; + } + const presetPosition = this.resolvePresetAnchorPosition({ + preset: this.positionPreset, + anchorBox, + elementWidth, + elementHeight, + bottomInset + }); + anchorX = presetPosition.anchorX; + anchorY = presetPosition.anchorY; + if (anchorBox.w > 0) this.position.left = anchorX / anchorBox.w * 100; + if (anchorBox.h > 0) this.position.top = anchorY / anchorBox.h * 100; + return { + anchorX, + anchorY + }; + } + clampContainerPosition(anchorBox, anchorX, anchorY, elementWidth, elementHeight, bottomInset) { + let leftPx = anchorX - elementWidth / 2; + let topPx = anchorY - elementHeight; + const maxLeftPx = anchorBox.w - elementWidth; + const maxTopPx = anchorBox.h - bottomInset - elementHeight; + leftPx = maxLeftPx >= 0 ? clampToRange(leftPx, 0, maxLeftPx) : maxLeftPx / 2; + topPx = maxTopPx >= 0 ? clampToRange(topPx, 0, maxTopPx) : 0; + return { + anchorX: leftPx + elementWidth / 2, + anchorY: topPx + elementHeight + }; + } + updateContainerPosition(subtitlesContainer, leftPct, topPct) { + if (this.lastAppliedLeftPct === null || Math.abs(leftPct - this.lastAppliedLeftPct) >= .01) { + subtitlesContainer.style.left = `${leftPct}%`; + this.lastAppliedLeftPct = leftPct; + } + if (this.lastAppliedTopPct === null || Math.abs(topPct - this.lastAppliedTopPct) >= .01) { + subtitlesContainer.style.top = `${topPct}%`; + this.lastAppliedTopPct = topPct; + } + } + resolvePresetAnchorPosition({ preset, anchorBox, elementWidth, elementHeight, bottomInset }) { + let anchorX = anchorBox.w / 2; + let anchorY = anchorBox.h - bottomInset; + switch (preset) { + case "top-center": + anchorY = elementHeight; + break; + case "center": + anchorY = anchorBox.h / 2 + elementHeight / 2; + break; + case "bottom-left": + anchorX = elementWidth / 2; + break; + case "bottom-right": + anchorX = anchorBox.w - elementWidth / 2; + break; + case "bottom-center": + case "custom": break; + } + return clampAnchorWithinBox({ + anchorX, + anchorY, + elementWidth, + elementHeight, + boxWidth: anchorBox.w, + boxHeight: anchorBox.h, + bottomInset + }); + } + applyPositionAfterContentRender() { + const layout = this.getLayoutSize(); + if (layout.w && layout.h) { + const anchorBox = this.computeAnchorBoxLayout(layout); + if (anchorBox.w && anchorBox.h) { + this.refreshBottomInsetNow(layout, anchorBox); + this.applySubtitlePositionWithLayout(layout, anchorBox); + return; + } + this.refreshBottomInsetNow(layout); + this.applySubtitlePosition(); + return; + } + this.refreshBottomInsetNow(); + this.applySubtitlePosition(); + } + trimEdgeWhitespaceTokens(tokens) { + if (!tokens.length) return tokens; + let s = 0; + let e = tokens.length; + while (s < e && !tokens[s]?.text.trim()) s += 1; + while (e > s && !tokens[e - 1]?.text.trim()) e -= 1; + if (s === 0 && e === tokens.length) return tokens; + return s >= e ? [] : tokens.slice(s, e); + } + selectTokensByMaxLength(tokens, time) { + if (!tokens.length) return tokens; + let start = 0; + let length = 0; + let overflowed = false; + let chosenStart = 0; + let chosenEnd = tokens.length; + let hasChosenRange = false; + let matchedByTime = false; + const considerRange = (rangeStart, rangeEnd) => { + if (rangeEnd <= rangeStart) return; + if (!hasChosenRange) { + chosenStart = rangeStart; + chosenEnd = rangeEnd; + hasChosenRange = true; + } + if (matchedByTime) return; + const first = tokens[rangeStart]; + const last = tokens[rangeEnd - 1]; + if (!first || !last) return; + const endMs = (rangeEnd < tokens.length ? tokens[rangeEnd]?.startMs : void 0) ?? last.startMs + (last.durationMs ?? 0); + if (first.startMs <= time && time < endMs) { + chosenStart = rangeStart; + chosenEnd = rangeEnd; + matchedByTime = true; + } + }; + for (const [index, token] of tokens.entries()) { + const nextLength = length + token.text.length; + if (nextLength > this.maxLength && index > start) { + overflowed = true; + considerRange(start, index); + start = index; + length = token.text.length; + continue; + } + length = nextLength; + } + if (!overflowed) return this.trimEdgeWhitespaceTokens(tokens); + considerRange(start, tokens.length); + return this.trimEdgeWhitespaceTokens(tokens.slice(chosenStart, chosenEnd)); + } + buildTokenPrecomputeInput(tokens) { + const cached = this.tokenPrecomputeMemo; + if (cached?.tokens === tokens) return cached.value; + const { slices, key } = buildWordSlices(tokens); + const value = { + wordSlices: slices, + normalizedWordsKey: key + }; + this.tokenPrecomputeMemo = { + tokens, + value + }; + return value; + } + getTokenLayoutInputs(ctx) { + const block = this.subtitlesBlock; + if (block) { + const cs = getComputedStyle(block); + const fontKey = `${cs.fontStyle} ${cs.fontVariant} ${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`; + ctx.font = fontKey; + const cssMaxWidth = Number.parseFloat(cs.maxWidth); + const paddingLeft = Number.parseFloat(cs.paddingLeft) || 0; + const paddingRight = Number.parseFloat(cs.paddingRight) || 0; + const baseMaxWidth = Number.isFinite(cssMaxWidth) ? cssMaxWidth : this.subtitleMaxWidthPx || globalThis.innerWidth * .8; + if (Number.isFinite(baseMaxWidth) && baseMaxWidth > 0) this.subtitleMaxWidthPx = baseMaxWidth; + return { + fontKey, + maxWidthPx: Math.max(0, baseMaxWidth - paddingLeft - paddingRight) + }; + } + const remPx = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16; + const baseMaxWidth = Math.min(remPx * 52, this.subtitleMaxWidthPx || globalThis.innerWidth * .8); + const fontSizePx = this.fontSizeOverridden ? this.fontSize : Math.min(24, Math.max(14, globalThis.innerWidth * .016)); + const fontKey = `normal normal 500 ${fontSizePx}px ${getSubtitleFontFamilyCssValue(this.fontFamily)}`; + ctx.font = fontKey; + return { + fontKey, + maxWidthPx: Math.max(0, baseMaxWidth - fontSizePx) + }; + } + getActiveLineKey(tokens) { + if (this.lastActiveLineKey !== null) return this.lastActiveLineKey; + return `${tokens[0]?.startMs ?? 0}:${tokens[0]?.durationMs ?? 0}:${tokens.length}`; + } + getLineMeasureMemo(tokens, activeLineKey) { + const { wordSlices, normalizedWordsKey } = this.buildTokenPrecomputeInput(tokens); + if (!wordSlices.length) return null; + const ctx = this.getMeasureContext(); + if (!ctx) return null; + const { fontKey, maxWidthPx } = this.getTokenLayoutInputs(ctx); + if (!Number.isFinite(maxWidthPx) || maxWidthPx < 24) return null; + const key = `${activeLineKey}|${fontKey}|${Math.round(maxWidthPx)}|${normalizedWordsKey}`; + if (this.lineMeasureMemo?.key === key) return this.lineMeasureMemo; + const memo = { + key, + metrics: measureWordSlices(wordSlices, (text) => ctx.measureText(text).width), + maxWidthPx + }; + this.lineMeasureMemo = memo; + return memo; + } + buildTokenProcessingMemo(tokens, activeLineKey) { + const lineMeasure = this.getLineMeasureMemo(tokens, activeLineKey); + if (!lineMeasure) return null; + const memoKey = `${lineMeasure.key}|${this.maxLength}`; + if (this.tokenProcessingMemo?.key === memoKey) return this.tokenProcessingMemo; + const safeMaxWidthPx = applyWrapWidthGuard(lineMeasure.maxWidthPx); + const memo = { + key: memoKey, + segmentRanges: computeTwoLineSegments(tokens, lineMeasure.metrics, safeMaxWidthPx, this.maxLength) + }; + this.tokenProcessingMemo = memo; + this.lastSegmentIndex = 0; + return memo; + } + selectSegmentIndexFromRanges(segmentRanges, time) { + if (!segmentRanges.length) return -1; + let idx = this.lastSegmentIndex; + if (idx >= segmentRanges.length) idx = 0; + while (idx < segmentRanges.length - 1 && time >= segmentRanges[idx].endMs) idx += 1; + while (idx > 0 && time < segmentRanges[idx].startMs) idx -= 1; + if (!(time >= segmentRanges[idx].startMs && time < segmentRanges[idx].endMs)) { + const found = segmentRanges.findIndex((s) => time >= s.startMs && time < s.endMs); + if (found >= 0) idx = found; + else idx = time < segmentRanges[0].startMs ? 0 : segmentRanges.length - 1; + } + this.lastSegmentIndex = idx; + return idx; + } + processTokens(tokens, time) { + if (!tokens.length) return tokens; + const activeLineKey = this.getActiveLineKey(tokens); + const memo = this.buildTokenProcessingMemo(tokens, activeLineKey); + if (!memo) return this.selectTokensByMaxLength(tokens, time); + const { segmentRanges } = memo; + if (!segmentRanges.length) return this.trimEdgeWhitespaceTokens(tokens); + const segmentIndex = this.selectSegmentIndexFromRanges(segmentRanges, time); + if (segmentIndex < 0) return this.trimEdgeWhitespaceTokens(tokens); + const seg = segmentRanges[segmentIndex]; + return this.trimEdgeWhitespaceTokens(tokens.slice(seg.startToken, seg.endToken)); + } + async translateStrTokens(text) { + const fromLang = this.subtitleLang ?? ""; + const toLang = localizationProvider.lang; + if (this.strTranslatedTokens) { + const translated = await translate(text, fromLang, toLang); + return [this.strTranslatedTokens, typeof translated === "string" ? translated : ""]; + } + const translated = await translate([this.strTokens, text], fromLang, toLang); + const pair = Array.isArray(translated) ? translated : [translated, translated]; + const context = typeof pair[0] === "string" ? pair[0] : ""; + const current = typeof pair[1] === "string" ? pair[1] : ""; + this.strTranslatedTokens = context; + return [context, current]; + } + isTokenSpanElement(el) { + return el instanceof HTMLSpanElement && el.dataset.votToken === "1"; + } + findTokenSpanInPath(path, root) { + for (const node of path) if (this.isTokenSpanElement(node) && root.contains(node)) return node; + return null; + } + findTokenSpanByPoint(x, y, root) { + const hit = document.elementFromPoint(x, y); + if (this.isTokenSpanElement(hit) && root.contains(hit)) return hit; + if (!(hit instanceof Element)) return null; + const closest = hit.closest("span[data-vot-token=\"1\"]"); + if (closest instanceof HTMLSpanElement && root.contains(closest)) return closest; + return null; + } + resolveTokenSpanFromClick(event) { + const root = this.subtitlesBlock ?? this.subtitlesContainer; + if (!root) return null; + if (this.isTokenSpanElement(event.target) && root.contains(event.target)) return event.target; + const path = typeof event.composedPath === "function" ? event.composedPath() : []; + const fromPath = this.findTokenSpanInPath(path, root); + if (fromPath) return fromPath; + const x = event.clientX; + const y = event.clientY; + if (Number.isFinite(x) && Number.isFinite(y)) return this.findTokenSpanByPoint(x, y, root); + return null; + } + releaseTooltip() { + this.tooltipTranslationRequestId += 1; + if (this.tokenTooltip?.target) this.tokenTooltip.target.classList.remove("selected"); + this.tokenTooltip?.release(); + this.tokenTooltip = void 0; + destroyShadowMount(this.tooltipMount); + this.tooltipMount = void 0; + return this; + } + clearPendingSchedulerState() { + this.repositionPending = false; + this.updatePending = false; + this.wrapPending = false; + this.positionRefreshPending = false; + } + clearRenderedContent({ releaseTooltip = false } = {}) { + if (releaseTooltip) this.releaseTooltip(); + this.resetRenderMemo(); + this.lastActiveLineKey = null; + this.strTokens = ""; + this.resetTranslationContext(); + this.subtitlesBlock = null; + this.renderedHighlightEls = []; + this.resetWrapMemo(); + this.lastWrapTokens = null; + this.subtitleMaxWidthPx = 0; + this.smartAnchorWidthPx = 0; + this.smartAnchorHeightPx = 0; + this.smartFontSizePx = 0; + this.smartMaxWidthPx = 0; + this.lastAppliedLeftPct = null; + this.lastAppliedTopPct = null; + this.passedStateKey = null; + this.passedThresholds.length = 0; + this.insetCacheReady = false; + this.hideSnapGuides(); + this.resetSegmentationMemo(); + this.clearPendingSchedulerState(); + if (this.subtitlesContainer) D(null, this.subtitlesContainer); + } + onClick = async (event) => { + if (performance.now() < this.suppressTokenClicksUntil) { + event.preventDefault(); + event.stopPropagation(); + return; + } + const target = this.resolveTokenSpanFromClick(event); + if (!target) return; + if (this.toggleCurrentTooltipTarget(target)) return; + this.releaseTooltip(); + const requestId = this.tooltipTranslationRequestId; + const text = this.normalizeTokenTextForTranslation(target.textContent ?? ""); + if (!text) return; + const service = await votStorage.get("translationService", defaultTranslationService); + if (requestId !== this.tooltipTranslationRequestId) return; + target.classList.add("selected"); + const subtitlesInfo = UI.createSubtitleInfo(text, this.strTranslatedTokens || this.strTokens, service); + const tooltip = this.createTokenTooltip(target, subtitlesInfo.container); + this.tokenTooltip = tooltip; + tooltip.onClick(); + const strTokens = this.strTokens; + const translated = await this.translateStrTokens(text); + if (requestId !== this.tooltipTranslationRequestId) return; + if (this.shouldSkipTooltipUpdate(requestId, tooltip, target, strTokens)) return; + subtitlesInfo.header.textContent = translated[1]; + subtitlesInfo.context.textContent = translated[0]; + tooltip.setContent(subtitlesInfo.container); + }; + toggleCurrentTooltipTarget(target) { + if (this.tokenTooltip?.target !== target || !this.tokenTooltip?.container) return false; + if (this.tokenTooltip.showed) target.classList.add("selected"); + else target.classList.remove("selected"); + return true; + } + createTokenTooltip(target, content) { + const tooltipMaxWidth = Math.max(this.subtitleMaxWidthPx, this.subtitlesContainer?.offsetWidth ?? 0, this.subtitlesBlock?.offsetWidth ?? 0, Math.min(globalThis.innerWidth * .6, 320)); + const tooltipMount = this.ensureTooltipMount(); + return new Tooltip({ + target, + anchor: this.subtitlesBlock ?? target, + content, + parentElement: tooltipMount.root, + layoutRoot: tooltipMount.host, + offset: { + x: 4, + y: 12 + }, + maxWidth: tooltipMaxWidth, + borderRadius: 12, + bordered: false, + position: "top", + trigger: "click" + }); + } + shouldSkipTooltipUpdate(requestId, tooltip, target, strTokens) { + return requestId !== this.tooltipTranslationRequestId || strTokens !== this.strTokens || this.tokenTooltip !== tooltip || tooltip.target !== target || !tooltip.showed; + } + buildPassedState(tokens, time, stateKey) { + if (this.passedStateKey !== stateKey) { + this.passedStateKey = stateKey; + this.passedThresholds.length = 0; + for (const token of tokens) { + if (!token.isWordLike) continue; + const halfway = token.startMs + token.durationMs / 2; + const earlyPassThreshold = Math.max(token.startMs - 100, halfway - 275); + this.passedThresholds.push(Math.min(halfway, earlyPassThreshold)); + } + } + const flags = this.passedFlagsBuffer; + const thresholds = this.passedThresholds; + for (let i = 0; i < thresholds.length; i += 1) flags[i] = time > thresholds[i]; + flags.length = thresholds.length; + return flags; + } + renderTokens(tokens) { + return buildSubtitleRenderPlan(tokens, tokens.length - 1, this.breakAfterTokenIndexSet).map((part) => this.renderPlanPart(part)); + } + renderStyledSpan(text, style, isWordToken = false, highlightIndex) { + if (!style && !isWordToken && highlightIndex === void 0) return text; + return b`${text}`; + } + renderPlanPart(part) { + if (part.kind === "break") return b`
`; + return this.renderStyledSpan(part.text, part.style, part.kind === "word", part.highlightIndex); + } + updatePassedClasses(passedFlags) { + for (const tokenEl of this.renderedHighlightEls) { + const highlightIndex = Number.parseInt(tokenEl.dataset.votHighlightIndex ?? "", 10); + const isPassed = Number.isInteger(highlightIndex) && highlightIndex >= 0 && highlightIndex < passedFlags.length ? passedFlags[highlightIndex] : false; + tokenEl.classList.toggle("passed", isPassed); + } + } + clearPassedClasses() { + for (const tokenEl of this.renderedHighlightEls) tokenEl.classList.remove("passed"); + } + setBreakAfterTokenIndices(indices) { + this.breakAfterTokenIndices = indices; + this.breakAfterTokenIndexSet = indices.length ? new Set(indices) : null; + } + scheduleWrapRecompute(tokens = null) { + if (tokens) this.lastWrapTokens = tokens; + const shouldRequestTick = !this.wrapPending; + this.wrapPending = true; + if (shouldRequestTick) this.intervalIdleChecker.requestImmediateTick(); + } + maybeRefreshPosition(force = false) { + if (this.abortController.signal.aborted) return; + if (!this.subtitlesContainer) return; + const now = performance.now(); + if (!force && now - this.lastPositionRefreshTs < this.positionRefreshIntervalMs) return; + this.lastPositionRefreshTs = now; + this.positionRefreshPending = true; + this.intervalIdleChecker.requestImmediateTick(); + } + getMeasureContext(font) { + if (!this.measureCanvas) { + this.measureCanvas = document.createElement("canvas"); + this.measureCanvas.width = 1; + this.measureCanvas.height = 1; + } + if (!this.measureCtx) this.measureCtx = this.measureCanvas.getContext("2d", { alpha: false }) ?? this.measureCanvas.getContext("2d"); + if (!this.measureCtx) return null; + if (typeof font === "string" && font) this.measureCtx.font = font; + return this.measureCtx; + } + arraysEqual(a, b) { + if (a === b) return true; + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false; + return true; + } + recomputeWrapNow() { + const tokens = this.lastWrapTokens; + const block = this.subtitlesBlock; + if (!tokens || !block) return; + const ctx = this.getMeasureContext(); + if (!ctx) return; + const { fontKey, maxWidthPx } = this.getTokenLayoutInputs(ctx); + if (!Number.isFinite(maxWidthPx) || maxWidthPx < 50) return; + const safeMaxWidthPx = applyWrapWidthGuard(maxWidthPx); + if (safeMaxWidthPx < 50) return; + const wrapKey = `${this.getActiveLineKey(tokens)}|${fontKey}|${Math.round(safeMaxWidthPx)}|${this.stringifyTokens(tokens)}`; + if (wrapKey === this.lastWrapKey) return; + this.lastWrapKey = wrapKey; + const next = computeTokenWrapPlan(tokens, (text) => ctx.measureText(text).width, safeMaxWidthPx); + if (!this.arraysEqual(next.breakAfterTokenIndices, this.breakAfterTokenIndices)) { + this.setBreakAfterTokenIndices(next.breakAfterTokenIndices); + this.resetRenderMemo(); + this.update(); + } + } + setContent(subtitles, lang = void 0) { + this.releaseTooltip(); + this.subtitleLang = lang; + if (!subtitles || !this.video) { + this.clearRenderedContent(); + this.subtitles = null; + this.maxActiveCueLookbackMs = 0; + this.lastPlaybackTimeMs = null; + this.clearPendingSchedulerState(); + this.stopVideoFrameLoop(); + this.detachDragDocumentListeners(); + return; + } + this.createSubtitlesContainer(); + this.subtitles = subtitles; + this.maxActiveCueLookbackMs = subtitles.subtitles.reduce((maxDurationMs, line) => Math.max(maxDurationMs, Math.max(0, line.durationMs)), 0); + this.lastPlaybackTimeMs = Math.max(0, this.video.currentTime * 1e3); + this.lastActiveLineKey = null; + this.syncVideoFrameLoop(); + this.updateContainerRect(); + this.update(); + this.intervalIdleChecker.requestImmediateTick(); + } + setMaxLength(len) { + if (typeof len === "number" && len > 0) { + this.maxLength = len; + this.resetSegmentationMemo(); + this.update(); + this.scheduleReposition(); + } + } + setHighlightWords(value) { + const wasEnabled = this.highlightWords; + this.highlightWords = Boolean(value); + if (wasEnabled && !this.highlightWords) this.clearPassedClasses(); + this.update(); + } + setSmartLayout(enabled) { + const next = enabled !== false; + if (next === this.smartLayoutEnabled) return; + this.smartLayoutEnabled = next; + this.subtitlesContainer?.style.removeProperty("--vot-subtitles-max-width"); + this.lastSmartLayoutKey = null; + this.resetWrapMemo(); + this.resetRenderMemo(); + this.resetSegmentationMemo(); + this.applyManualFontSizeStyle(); + this.update(); + this.scheduleWrapRecompute(); + this.scheduleReposition(); + } + setFontSize(size) { + this.fontSize = size; + this.fontSizeOverridden = true; + if (!this.smartLayoutEnabled) { + this.applyManualFontSizeStyle(); + this.lastWrapKey = null; + this.resetSegmentationMemo(); + this.scheduleWrapRecompute(); + this.scheduleReposition(); + } + } + setFontFamily(fontFamily) { + this.fontFamily = fontFamily; + this.applyFontFamilyStyle(); + this.lastWrapKey = null; + this.resetSegmentationMemo(); + this.scheduleWrapRecompute(); + this.scheduleReposition(); + } + setOpacity(rate) { + const numericRate = Number(rate); + this.opacity = ((100 - (Number.isFinite(numericRate) ? clampToRange(numericRate, 0, 100) : 0)) / 100).toFixed(2); + this.applyOpacityStyle(); + } + stringifyTokens(tokens) { + let out = ""; + for (const token of tokens) out += token.text; + return out; + } + resolveActiveLine(time, subtitlesList) { + return buildActiveSubtitleRenderLine(time, subtitlesList, this.maxActiveCueLookbackMs); + } + clearInactiveLineState() { + this.lastActiveLineKey = null; + if (this.subtitlesBlock || this.lastRenderKey !== null || this.strTokens) { + this.clearRenderedContent({ releaseTooltip: true }); + return; + } + this.releaseTooltip(); + } + refreshSmartLayoutIfNeeded() { + if (!this.smartLayoutEnabled) return; + const now = performance.now(); + if (this.lastSmartLayoutKey !== null && now - this.lastSmartLayoutCheckTs <= 500) return; + this.lastSmartLayoutCheckTs = now; + const layout = this.getLayoutSize(); + if (!layout.w || !layout.h) return; + const anchorBox = this.computeAnchorBoxLayout(layout); + if (anchorBox.w && anchorBox.h) this.ensureSmartLayout(anchorBox); + } + getRenderState(line, activeLineKey, time) { + const tokens = this.processTokens(line.tokens, time); + this.lastWrapTokens = tokens; + const strTokens = this.stringifyTokens(tokens); + const tokensChanged = strTokens !== this.strTokens; + if (tokensChanged) { + this.releaseTooltip(); + this.strTokens = strTokens; + this.resetTranslationContext(); + this.resetWrapMemo(); + } + const passedStateKey = `${activeLineKey}:${strTokens}`; + return { + tokens, + tokensChanged, + passedFlags: this.highlightWords ? this.buildPassedState(tokens, time, passedStateKey) : null, + renderKey: `${activeLineKey}:${strTokens}:${this.breakAfterTokenIndices.join(",")}` + }; + } + syncRenderedTokens(tokens) { + this.subtitlesContainer = this.subtitlesContainer ?? this.createSubtitlesContainer(); + D(b` + ${this.renderTokens(tokens)} + `, this.subtitlesContainer); + const firstChild = this.subtitlesContainer.firstElementChild; + this.subtitlesBlock = firstChild instanceof HTMLElement && firstChild.classList.contains("vot-subtitles") ? firstChild : null; + this.renderedHighlightEls = this.subtitlesBlock ? Array.from(this.subtitlesBlock.querySelectorAll("span[data-vot-highlight-index]")) : []; + } + update() { + if (!this.video || !this.subtitles) return; + const time = this.resolvePlaybackTimeMs(); + const subtitlesList = this.subtitles.subtitles; + const activeLine = this.resolveActiveLine(time, subtitlesList); + if (!activeLine) { + this.clearInactiveLineState(); + return; + } + this.lastActiveLineKey = activeLine.lineKey; + this.refreshSmartLayoutIfNeeded(); + const { tokens, tokensChanged, passedFlags, renderKey } = this.getRenderState(activeLine.line, activeLine.lineKey, time); + if (renderKey === this.lastRenderKey) { + if (this.highlightWords && !tokensChanged && passedFlags) this.updatePassedClasses(passedFlags); + this.maybeRefreshPosition(); + return; + } + this.lastRenderKey = renderKey; + this.syncRenderedTokens(tokens); + if (this.highlightWords && passedFlags) this.updatePassedClasses(passedFlags); + if (tokensChanged) { + this.applyPositionAfterContentRender(); + this.scheduleWrapRecompute(tokens); + this.scheduleReposition(); + } else this.maybeRefreshPosition(); + } + release() { + this.detachDragDocumentListeners(); + this.stopVideoFrameLoop(); + this.abortController.abort(); + this.resizeObserver?.disconnect(); + this.clearPendingSchedulerState(); + this.checkerUnsubscribe?.(); + this.checkerUnsubscribe = null; + this.releaseTooltip(); + if (this.subtitlesContainer) { + this.subtitlesContainer.remove(); + this.subtitlesContainer = null; + } + destroyShadowMount(this.tooltipMount); + this.tooltipMount = void 0; + this.fullscreenLayerController.release(); + if (this.safeAreaProbeEl) { + this.safeAreaProbeEl.remove(); + this.safeAreaProbeEl = null; + } + if (this.guidesLayer) { + this.guidesLayer.remove(); + this.guidesLayer = null; + this.verticalGuide = null; + this.horizontalGuide = null; + } + this.measureCtx = null; + this.measureCanvas = null; + this.lastAppliedLeftPct = null; + this.lastAppliedTopPct = null; + this.passedStateKey = null; + this.passedThresholds.length = 0; + this.insetCacheReady = false; + } + }; + //#endregion + //#region src/subtitles/displayModel.ts + var HTML_TAG_RE = /^<\s*(\/?)\s*([a-z0-9]+)([^>]*)>/iu; + var ASS_OVERRIDE_RE = /^\{([^}]*)\}/u; + var LEADING_SPEAKER_MARKER_RE = /^(\s*)>>\s*/u; + var ATTACHED_TIME_WORD_RE = /(\d{1,2}:\d{2}(?::\d{2})?)(?=[\p{L}\p{M}])/gu; + var GLUED_WORD_NUMBER_RE = /([\p{L}\p{M}]+)(\d+)|(\d+)([\p{L}\p{M}]+)/gu; + var ASS_DIRECTIVE_RE = /\\[^\\]+/gu; + var ASS_STYLE_TOGGLE_RE = /^\\([ibu])([01])$/u; + var ASS_PRIMARY_COLOR_RE = /^\\(?:1?c|c)&H([0-9a-f]{6,8})&$/iu; + var ASS_STYLE_RESET_RE = /^\\r(?:[^\\}]*)?$/u; + var cloneMutableInlineStyle = (style) => ({ + italic: style.italic, + bold: style.bold, + underline: style.underline, + color: style.color, + classes: [...style.classes] + }); + var assignMutableInlineStyle = (target, source) => { + target.italic = source.italic; + target.bold = source.bold; + target.underline = source.underline; + target.color = source.color; + target.classes = [...source.classes]; + }; + var resetMutableInlineStyle = (style) => { + style.italic = false; + style.bold = false; + style.underline = false; + style.color = void 0; + style.classes = []; + }; + var toTokenStyle = (style) => normalizeSubtitleInlineStyle({ + italic: style.italic, + bold: style.bold, + underline: style.underline, + color: style.color, + classes: style.classes + }); + var pushSegment = (segments, text, style) => { + if (!text) return; + const tokenStyle = toTokenStyle(style); + const previous = segments.at(-1); + if (previous && subtitleInlineStylesEqual(previous.style, tokenStyle)) { + previous.text += text; + return; + } + segments.push({ + text, + style: tokenStyle + }); + }; + var parseAssColorToCssHex = (value) => { + const normalized = value.trim(); + if (!/^[0-9a-f]{6,8}$/iu.test(normalized)) return; + const bgr = normalized.slice(-6); + const blue = bgr.slice(0, 2); + const green = bgr.slice(2, 4); + return normalizeCssColorValue(`#${bgr.slice(4, 6)}${green}${blue}`); + }; + var applyAssStyleDirective = (directive, style) => { + const toggleMatch = ASS_STYLE_TOGGLE_RE.exec(directive.trim()); + if (toggleMatch) { + const enabled = toggleMatch[2] === "1"; + if (toggleMatch[1] === "i") { + style.italic = enabled; + return; + } + if (toggleMatch[1] === "b") { + style.bold = enabled; + return; + } + if (toggleMatch[1] === "u") { + style.underline = enabled; + return; + } + } + if (ASS_STYLE_RESET_RE.test(directive.trim())) { + resetMutableInlineStyle(style); + return; + } + const colorMatch = ASS_PRIMARY_COLOR_RE.exec(directive.trim()); + if (colorMatch) style.color = parseAssColorToCssHex(colorMatch[1]); + }; + var applyAssOverrideBlock = (rawDirectives, style) => { + const directives = rawDirectives.match(ASS_DIRECTIVE_RE) ?? []; + for (const directive of directives) applyAssStyleDirective(directive, style); + }; + var normalizeLeadingSpeakerMarker = (segments) => { + for (const segment of segments) { + if (!segment.text) continue; + const normalized = segment.text.replace(LEADING_SPEAKER_MARKER_RE, "$1"); + segment.text = normalized; + if (normalized.length > 0) break; + } + while (segments[0]?.text === "") segments.shift(); + }; + var normalizeAttachedTimeExpressions = (segments) => { + for (const segment of segments) { + if (!segment.text) continue; + segment.text = segment.text.replaceAll(ATTACHED_TIME_WORD_RE, "$1 "); + } + }; + var normalizeAttachedWordNumberExpressions = (segments) => { + for (const segment of segments) { + if (!segment.text) continue; + segment.text = segment.text.replaceAll(GLUED_WORD_NUMBER_RE, (match, leftLetters, leftDigits, rightDigits, rightLetters) => { + const letters = leftLetters ?? rightLetters ?? ""; + const digits = leftDigits ?? rightDigits ?? ""; + if (/^[A-Za-z]{1,3}$/u.test(letters) || letters.length === 1 && letters === letters.toLocaleUpperCase() && letters !== letters.toLocaleLowerCase()) return match; + return leftLetters ? `${letters} ${digits}` : `${digits} ${letters}`; + }); + } + }; + var extractHtmlTagClasses = (attrsRaw) => { + const normalized = attrsRaw.trim(); + if (!normalized.startsWith(".")) return; + const classNames = normalized.split(/\s+/u, 1)[0].split(".").filter(Boolean); + return classNames.length ? classNames : void 0; + }; + var extractHtmlFontColor = (attrsRaw) => { + const match = /\bcolor\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+))/iu.exec(attrsRaw); + const rawColor = match?.[1] ?? match?.[2] ?? match?.[3]; + return rawColor ? normalizeCssColorValue(rawColor) : void 0; + }; + var popHtmlStyleFrame = (tagName, stack, activeStyle) => { + for (let i = stack.length - 1; i >= 0; i -= 1) { + if (stack[i].tagName !== tagName) continue; + const [frame] = stack.splice(i, 1); + if (!frame) return; + assignMutableInlineStyle(activeStyle, frame.previousStyle); + return; + } + if (tagName === "b") { + activeStyle.bold = false; + return; + } + if (tagName === "i") { + activeStyle.italic = false; + return; + } + if (tagName === "u") { + activeStyle.underline = false; + return; + } + if (tagName === "font") { + activeStyle.color = void 0; + return; + } + if (tagName === "c") activeStyle.classes = []; + }; + var applyHtmlTagStyle = (htmlMatch, segments, activeStyle, styleStack) => { + const isClosing = htmlMatch[1] === "/"; + const tagName = htmlMatch[2].toLowerCase(); + const attrsRaw = htmlMatch[3] ?? ""; + if (tagName === "br") { + pushSegment(segments, "\n", activeStyle); + return; + } + if (isClosing) { + popHtmlStyleFrame(tagName, styleStack, activeStyle); + return; + } + if (![ + "b", + "i", + "u", + "font", + "c" + ].includes(tagName)) return; + styleStack.push({ + tagName, + previousStyle: cloneMutableInlineStyle(activeStyle) + }); + if (tagName === "b") { + activeStyle.bold = true; + return; + } + if (tagName === "i") { + activeStyle.italic = true; + return; + } + if (tagName === "u") { + activeStyle.underline = true; + return; + } + if (tagName === "font") { + const color = extractHtmlFontColor(attrsRaw); + if (color) activeStyle.color = color; + return; + } + activeStyle.classes = extractHtmlTagClasses(attrsRaw) ?? []; + }; + var consumeDisplayControlToken = (rawText, cursor, segments, activeStyle, styleStack) => { + const remainder = rawText.slice(cursor); + if (remainder.startsWith("\\N") || remainder.startsWith("\\n")) { + pushSegment(segments, "\n", activeStyle); + return cursor + 2; + } + if (remainder.startsWith("\\h")) { + pushSegment(segments, " ", activeStyle); + return cursor + 2; + } + if (remainder[0] === "\n") { + pushSegment(segments, "\n", activeStyle); + return cursor + 1; + } + const assMatch = ASS_OVERRIDE_RE.exec(remainder); + if (assMatch) { + applyAssOverrideBlock(assMatch[1], activeStyle); + return cursor + assMatch[0].length; + } + const htmlMatch = HTML_TAG_RE.exec(remainder); + if (!htmlMatch) return null; + applyHtmlTagStyle(htmlMatch, segments, activeStyle, styleStack); + return cursor + htmlMatch[0].length; + }; + var buildStyledSpans = (segments) => { + const styledSpans = []; + let text = ""; + for (const segment of segments) { + if (!segment.text) continue; + const start = text.length; + text += segment.text; + styledSpans.push({ + start, + end: text.length, + style: segment.style + }); + } + return { + text, + styledSpans + }; + }; + var trimStyledDisplayResult = (text, styledSpans) => { + const normalizedText = text.replaceAll("\xA0", " "); + const leadingTrim = /^\s*/u.exec(normalizedText)?.[0].length ?? 0; + const trailingTrim = /\s*$/u.exec(normalizedText)?.[0].length ?? 0; + const trimmedEnd = Math.max(leadingTrim, normalizedText.length - trailingTrim); + const finalText = normalizedText.slice(leadingTrim, trimmedEnd); + return { + text: finalText, + styledSpans: styledSpans.map((span) => ({ + start: Math.max(0, span.start - leadingTrim), + end: Math.max(0, span.end - leadingTrim), + style: span.style + })).filter((span) => span.end > span.start && span.start < finalText.length).map((span) => ({ + ...span, + end: Math.min(span.end, finalText.length) + })) + }; + }; + var buildStyledDisplayModel = (rawText) => { + const segments = []; + const activeStyle = { + italic: false, + bold: false, + underline: false, + color: void 0, + classes: [] + }; + const styleStack = []; + let cursor = 0; + while (cursor < rawText.length) { + const nextCursor = consumeDisplayControlToken(rawText, cursor, segments, activeStyle, styleStack); + if (nextCursor !== null) { + cursor = nextCursor; + continue; + } + pushSegment(segments, rawText[cursor], activeStyle); + cursor += 1; + } + normalizeLeadingSpeakerMarker(segments); + normalizeAttachedTimeExpressions(segments); + normalizeAttachedWordNumberExpressions(segments); + const built = buildStyledSpans(segments); + return trimStyledDisplayResult(built.text, built.styledSpans); + }; + var getStyleForRange = (styledSpans, start, end) => { + if (!styledSpans?.length || end <= start) return; + return styledSpans.find((span) => start < span.end && end > span.start && span.style)?.style; + }; + //#endregion + //#region src/subtitles/standards.ts + var BOM = ""; + var ASS_OVERRIDE_TAG_RE = /\{[^}]*\}/gu; + var SRT_TIMING_RE = /^\s*(?\d{1,2}:\d{2}:\d{2}[,.]\d{1,3})\s*-->\s*(?\d{1,2}:\d{2}:\d{2}[,.]\d{1,3})\s*$/u; + var VTT_TIMING_RE = /^(?(?:\d{2}:)?\d{2}:\d{2}\.\d{3})\s+-->\s+(?(?:\d{2}:)?\d{2}:\d{2}\.\d{3})(?(?:[ \t]+.+)?)$/u; + var normalizeNewlines = (value) => value.replace(BOM, "").replaceAll(/\r\n?/gu, "\n"); + var padMilliseconds = (value) => value.length >= 3 ? value.slice(0, 3) : value.padEnd(3, "0"); + var parseClockTime = (value, millisecondsLength) => { + const parts = value.trim().split(":"); + if (parts.length < 2 || parts.length > 3) return null; + const [hoursRaw, minutesRaw, secondsRaw] = parts.length === 2 ? ["00", ...parts] : parts; + const [secondsPart, millisecondsPart = "0"] = secondsRaw.split(/[.,]/u); + if (!/^\d+$/u.test(hoursRaw) || !/^\d{2}$/u.test(minutesRaw) || !/^\d{2}$/u.test(secondsPart) || !/^\d+$/u.test(millisecondsPart)) return null; + const hours = Number(hoursRaw); + const minutes = Number(minutesRaw); + const seconds = Number(secondsPart); + const milliseconds = Number(padMilliseconds(millisecondsPart).slice(0, millisecondsLength)); + if (!Number.isFinite(hours) || !Number.isFinite(minutes) || !Number.isFinite(seconds) || minutes > 59 || seconds > 59) return null; + return ((hours * 60 + minutes) * 60 + seconds) * 1e3 + milliseconds; + }; + var formatClockTime = (totalMs, { delimiter, allowOptionalHours, fractionDigits }) => { + const { hours, minutes, seconds, milliseconds } = splitTimestampParts(totalMs, Math.round); + const fraction = milliseconds.toString().padStart(3, "0").slice(0, fractionDigits); + return `${allowOptionalHours && hours === 0 ? "" : `${hours.toString().padStart(2, "0")}:`}${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}${delimiter}${fraction}`; + }; + var splitTimestampParts = (totalMs, normalizeMs) => { + const safeMs = Math.max(0, normalizeMs(totalMs)); + return { + hours: Math.floor(safeMs / 36e5), + minutes: Math.floor(safeMs % 36e5 / 6e4), + seconds: Math.floor(safeMs % 6e4 / 1e3), + milliseconds: safeMs % 1e3 + }; + }; + var formatAssTime = (totalMs) => { + const { hours, minutes, seconds, milliseconds } = splitTimestampParts(totalMs, Math.round); + const centiseconds = Math.floor(milliseconds / 10); + return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}.${centiseconds.toString().padStart(2, "0")}`; + }; + var parseAssTime = (value) => { + const match = /^(?\d+):(?\d{2}):(?\d{2})\.(?\d{2})$/u.exec(value.trim()); + if (!match?.groups) return null; + const hours = Number(match.groups.hours); + const minutes = Number(match.groups.minutes); + const seconds = Number(match.groups.seconds); + const centiseconds = Number(match.groups.centiseconds); + if (minutes > 59 || seconds > 59 || !Number.isFinite(hours) || !Number.isFinite(centiseconds)) return null; + return ((hours * 60 + minutes) * 60 + seconds) * 1e3 + centiseconds * 10; + }; + var normalizeSubtitleTextForDisplay = (value) => buildStyledDisplayModel(value).text; + var getSubtitleLineEndMs = (line) => line.startMs + Math.max(0, line.durationMs); + var getCueDurationMs = (startMs, endMs) => Math.max(0, endMs - startMs); + var toComparableSubtitleOrder = (subtitles) => subtitles.sort((left, right) => { + const startDiff = left.line.startMs - right.line.startMs; + if (startDiff !== 0) return startDiff; + const endDiff = getSubtitleLineEndMs(left.line) - getSubtitleLineEndMs(right.line); + if (endDiff !== 0) return endDiff; + return left.index - right.index; + }).map(({ line }) => line); + var trimEmptyBoundaryLines = (lines) => { + let start = 0; + let end = lines.length; + while (start < end && lines[start] === "") start += 1; + while (end > start && lines[end - 1] === "") end -= 1; + return lines.slice(start, end); + }; + var parseCueSettings = (rawSettings) => { + const raw = rawSettings.trim(); + if (!raw) return void 0; + const values = {}; + for (const token of raw.split(/\s+/u)) { + const separatorIndex = token.indexOf(":"); + if (separatorIndex <= 0) continue; + values[token.slice(0, separatorIndex)] = token.slice(separatorIndex + 1); + } + return { + raw, + values + }; + }; + var extractVttVoice = (payload) => { + const voice = (/^\s*]+)?(?:\s+([^>]*?))?>/iu.exec(payload) ?? /^\s*]*?)>/iu.exec(payload))?.[1]?.trim(); + return voice ? voice : void 0; + }; + var isSrtCueStart = (lines, index) => { + const current = lines[index]?.trim() ?? ""; + const next = lines[index + 1]?.trim() ?? ""; + return SRT_TIMING_RE.test(current) || /^\d+$/u.test(current) && SRT_TIMING_RE.test(next); + }; + var getSrtTimingLineIndex = (lines, cursor) => /^\d+$/u.test(lines[cursor]?.trim() ?? "") && SRT_TIMING_RE.test(lines[cursor + 1]?.trim() ?? "") ? cursor + 1 : cursor; + var parseSrtTiming = (lines, timingLineIndex) => { + const timingMatch = SRT_TIMING_RE.exec(lines[timingLineIndex]?.trim() ?? ""); + if (!timingMatch?.groups) return null; + const startMs = parseClockTime(timingMatch.groups.start, 3); + const endMs = parseClockTime(timingMatch.groups.end, 3); + return startMs == null || endMs == null || endMs < startMs ? null : { + startMs, + endMs + }; + }; + var readSrtPayload = (lines, startCursor) => { + let cursor = startCursor; + const payloadLines = []; + while (cursor < lines.length) { + if (lines[cursor].trim() === "") { + if (isSrtCueStart(lines, cursor + 1)) break; + cursor += 1; + continue; + } + if (payloadLines.length > 0 && isSrtCueStart(lines, cursor)) break; + payloadLines.push(lines[cursor]); + cursor += 1; + } + return { + rawText: trimEmptyBoundaryLines(payloadLines).join("\n"), + nextCursor: cursor + }; + }; + var createStyledCueDraft = (index, { rawText, startMs, endMs, speakerId, displayModel, metadata }) => ({ + index, + line: { + text: displayModel.text, + startMs, + durationMs: getCueDurationMs(startMs, endMs), + speakerId, + tokens: [], + metadata: { + rawText, + styledSpans: displayModel.styledSpans, + ...metadata + } + } + }); + var createEmptyVttResult = () => ({ + format: "vtt", + subtitles: [], + metadata: { vtt: { + headerText: "", + blocks: [] + } } + }); + var isWebVttDocumentBlock = (line) => line.startsWith("NOTE") || line === "STYLE" || line === "REGION"; + var readVttBlockLines = (lines, startCursor) => { + const blockLines = []; + let cursor = startCursor; + while (cursor < lines.length && lines[cursor].trim() !== "") { + blockLines.push(lines[cursor]); + cursor += 1; + } + return { + blockLines, + nextCursor: cursor + }; + }; + var resolveVttCueIdentity = (lines, cursor) => { + if (!VTT_TIMING_RE.test(lines[cursor] ?? "") && VTT_TIMING_RE.test(lines[cursor + 1] ?? "")) return { + cueId: lines[cursor], + timingCursor: cursor + 1 + }; + return { + cueId: void 0, + timingCursor: cursor + }; + }; + var parseVttTiming = (line) => { + const timingMatch = VTT_TIMING_RE.exec(line); + if (!timingMatch?.groups) return null; + const startMs = parseClockTime(timingMatch.groups.start, 3); + const endMs = parseClockTime(timingMatch.groups.end, 3); + if (startMs == null || endMs == null || endMs < startMs) return null; + return { + startMs, + endMs, + settingsRaw: timingMatch.groups.settings ?? "" + }; + }; + var readVttPayloadLines = (lines, startCursor) => { + const payloadLines = []; + let cursor = startCursor; + while (cursor < lines.length && lines[cursor].trim() !== "") { + payloadLines.push(lines[cursor]); + cursor += 1; + } + return { + payloadLines, + nextCursor: cursor + }; + }; + var parseAssEventFormatFields = (formatLine) => formatLine.slice(7).split(",").map((field) => field.trim()); + var ensureAssEventFields = (eventFields, metadata) => eventFields.length || !metadata.eventFormat ? eventFields : parseAssEventFormatFields(metadata.eventFormat); + var buildAssEventRecord = (eventFields, value) => { + const values = splitAssFields(value, eventFields.length); + return Object.fromEntries(eventFields.map((field, fieldIndex) => [field, values[fieldIndex] ?? ""])); + }; + var applyAssStyleSectionLine = (metadata, line) => { + if (line.startsWith("Format:")) { + metadata.styleFormat = line; + return; + } + if (line.startsWith("Style:")) { + metadata.styleLines.push(line); + return; + } + metadata.preEventLines.push(line); + }; + var createAssCueDraft = (index, event) => { + const startMs = parseAssTime(event.Start ?? ""); + const endMs = parseAssTime(event.End ?? ""); + if (startMs == null || endMs == null || endMs < startMs) return null; + const rawText = event.Text ?? ""; + const displayModel = buildStyledDisplayModel(rawText); + const assMetadata = { + kind: "dialogue", + layer: event.Layer ?? "0", + style: event.Style ?? "Default", + name: event.Name ?? "", + marginL: event.MarginL ?? "0", + marginR: event.MarginR ?? "0", + marginV: event.MarginV ?? "0", + effect: event.Effect ?? "", + rawText, + overrideTags: rawText.match(ASS_OVERRIDE_TAG_RE) ?? [] + }; + return { + index, + line: createStyledCueDraft(index, { + rawText, + startMs, + endMs, + speakerId: assMetadata.name || "0", + displayModel, + metadata: { ass: assMetadata } + }).line + }; + }; + var processAssEventLine = (metadata, line, index, eventFields) => { + if (line.startsWith("Format:")) return { + eventFields: parseAssEventFormatFields(line), + cue: null + }; + if (!line.includes(":")) { + metadata.preEventLines.push(line); + return { + eventFields, + cue: null + }; + } + const separatorIndex = line.indexOf(":"); + const kind = line.slice(0, separatorIndex).trim(); + const value = line.slice(separatorIndex + 1).trim(); + const resolvedEventFields = ensureAssEventFields(eventFields, metadata); + const event = buildAssEventRecord(resolvedEventFields, value); + if (kind === "Comment") { + metadata.commentLines.push(line); + return { + eventFields: resolvedEventFields, + cue: null + }; + } + if (kind !== "Dialogue") { + metadata.preEventLines.push(line); + return { + eventFields: resolvedEventFields, + cue: null + }; + } + return { + eventFields: resolvedEventFields, + cue: createAssCueDraft(index, event) + }; + }; + var parseSrt = (text) => { + const lines = normalizeNewlines(text).split("\n"); + const cues = []; + let cursor = 0; + let cueIndex = 0; + while (cursor < lines.length) { + while (cursor < lines.length && lines[cursor].trim() === "") cursor += 1; + if (cursor >= lines.length) break; + const timingLineIndex = getSrtTimingLineIndex(lines, cursor); + const timing = parseSrtTiming(lines, timingLineIndex); + if (!timing) { + cursor += 1; + continue; + } + const payload = readSrtPayload(lines, timingLineIndex + 1); + cursor = payload.nextCursor; + const rawText = payload.rawText; + const displayModel = buildStyledDisplayModel(rawText); + cues.push(createStyledCueDraft(cueIndex, { + rawText, + startMs: timing.startMs, + endMs: timing.endMs, + speakerId: "0", + displayModel + })); + cueIndex += 1; + } + return { + format: "srt", + subtitles: toComparableSubtitleOrder(cues) + }; + }; + var resolveSerializedText = (processed, line, format) => { + if (processed.format === format) return line.metadata?.rawText ?? line.text; + if (format === "ass") return line.text.replaceAll("\n", "\\N"); + return line.text; + }; + var serializeSrt = (processed) => processed.subtitles.map((line, index) => { + const rawText = resolveSerializedText(processed, line, "srt"); + const endMs = getSubtitleLineEndMs(line); + return [ + String(index + 1), + `${formatClockTime(line.startMs, { + delimiter: ",", + allowOptionalHours: false, + fractionDigits: 3 + })} --> ${formatClockTime(endMs, { + delimiter: ",", + allowOptionalHours: false, + fractionDigits: 3 + })}`, + rawText + ].join("\n"); + }).join("\n\n"); + var pushWebVttBlock = (blocks, cueIndex, lines) => { + blocks.push({ + cueIndex, + lines + }); + }; + var parseVtt = (text) => { + const lines = normalizeNewlines(text).split("\n"); + const headerLine = lines[0] ?? ""; + if (!headerLine.startsWith("WEBVTT")) return createEmptyVttResult(); + const metadata = { + headerText: headerLine.slice(6).trim(), + blocks: [] + }; + const cues = []; + let cursor = 1; + while (cursor < lines.length) { + while (cursor < lines.length && lines[cursor].trim() === "") cursor += 1; + if (cursor >= lines.length) break; + if (isWebVttDocumentBlock(lines[cursor])) { + const block = readVttBlockLines(lines, cursor); + cursor = block.nextCursor; + pushWebVttBlock(metadata.blocks, cues.length, block.blockLines); + continue; + } + const identity = resolveVttCueIdentity(lines, cursor); + const timing = parseVttTiming(lines[identity.timingCursor] ?? ""); + if (!timing) { + cursor += 1; + continue; + } + const payload = readVttPayloadLines(lines, identity.timingCursor + 1); + cursor = payload.nextCursor; + const payloadLines = payload.payloadLines; + const rawText = payloadLines.join("\n"); + const displayModel = buildStyledDisplayModel(rawText); + const voice = extractVttVoice(rawText); + cues.push({ + index: cues.length, + line: createStyledCueDraft(cues.length, { + rawText, + startMs: timing.startMs, + endMs: timing.endMs, + speakerId: voice ?? "0", + displayModel, + metadata: { vtt: { + cueId: identity.cueId, + settings: parseCueSettings(timing.settingsRaw), + voice, + rawPayload: payloadLines + } } + }).line + }); + } + return { + format: "vtt", + subtitles: toComparableSubtitleOrder(cues), + metadata: { vtt: metadata } + }; + }; + var serializeVttTiming = (line) => { + const endMs = getSubtitleLineEndMs(line); + const settings = line.metadata?.vtt?.settings?.raw; + const settingsSuffix = settings ? ` ${settings}` : ""; + return `${formatClockTime(line.startMs, { + delimiter: ".", + allowOptionalHours: true, + fractionDigits: 3 + })} --> ${formatClockTime(endMs, { + delimiter: ".", + allowOptionalHours: true, + fractionDigits: 3 + })}${settingsSuffix}`; + }; + var serializeVtt = (processed) => { + const metadata = processed.metadata?.vtt; + const sections = [`WEBVTT${metadata?.headerText ? ` ${metadata.headerText}` : ""}`]; + const blocksByIndex = /* @__PURE__ */ new Map(); + for (const block of metadata?.blocks ?? []) { + const existing = blocksByIndex.get(block.cueIndex) ?? []; + existing.push(block.lines); + blocksByIndex.set(block.cueIndex, existing); + } + const emitBlocks = (cueIndex) => { + for (const lines of blocksByIndex.get(cueIndex) ?? []) sections.push(lines.join("\n")); + }; + emitBlocks(0); + processed.subtitles.forEach((line, index) => { + const cueId = line.metadata?.vtt?.cueId; + const cueSections = [ + ...cueId ? [cueId] : [], + serializeVttTiming(line), + (processed.format === "vtt" ? line.metadata?.vtt?.rawPayload : line.text.split("\n"))?.join("\n") ?? line.text + ]; + sections.push(cueSections.join("\n")); + emitBlocks(index + 1); + }); + return sections.filter(Boolean).join("\n\n"); + }; + var splitAssFields = (value, fieldCount) => { + if (fieldCount <= 1) return [value]; + const fields = []; + let cursor = 0; + for (let i = 0; i < fieldCount - 1; i += 1) { + const separatorIndex = value.indexOf(",", cursor); + if (separatorIndex < 0) { + fields.push(value.slice(cursor).trim()); + cursor = value.length; + break; + } + fields.push(value.slice(cursor, separatorIndex).trim()); + cursor = separatorIndex + 1; + } + fields.push(value.slice(cursor).trim()); + return fields; + }; + var createEmptyAssMetadata = () => ({ + scriptInfoLines: [], + styleFormat: "", + styleLines: [], + eventFormat: "", + preEventLines: [], + commentLines: [] + }); + var createDefaultAssMetadata = (title = "Exported subtitles") => ({ + scriptInfoLines: [ + `Title: ${title}`, + "ScriptType: v4.00+", + "WrapStyle: 0", + "ScaledBorderAndShadow: yes" + ], + styleFormat: "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", + styleLines: ["Style: Default,Arial,42,&H00FFFFFF,&H000000FF,&H00000000,&H64000000,0,0,0,0,100,100,0,0,1,2,0,2,20,20,20,1"], + eventFormat: "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", + preEventLines: [], + commentLines: [] + }); + var parseAss = (text) => { + const lines = normalizeNewlines(text).split("\n"); + const metadata = createEmptyAssMetadata(); + const cues = []; + let currentSection = ""; + let eventFields = []; + lines.forEach((line, index) => { + const trimmed = line.trim(); + if (!trimmed) return; + const sectionMatch = /^\[(.+)\]$/u.exec(trimmed); + if (sectionMatch) { + currentSection = sectionMatch[1]; + return; + } + if (currentSection === "Script Info") { + metadata.scriptInfoLines.push(line); + return; + } + if (currentSection === "V4+ Styles" || currentSection === "V4 Styles") { + applyAssStyleSectionLine(metadata, line); + return; + } + if (currentSection === "Events") { + if (line.startsWith("Format:")) metadata.eventFormat = line; + const result = processAssEventLine(metadata, line, index, eventFields); + eventFields = result.eventFields; + if (result.cue) cues.push(result.cue); + } + }); + return { + format: "ass", + subtitles: toComparableSubtitleOrder(cues), + metadata: { ass: metadata } + }; + }; + var serializeAssDialogue = (line) => { + const ass = line.metadata?.ass; + const endMs = getSubtitleLineEndMs(line); + const rawText = ass?.rawText ?? line.metadata?.rawText ?? line.text.replaceAll("\n", "\\N"); + return [ + ass?.kind === "comment" ? "Comment" : "Dialogue", + ": ", + [ + ass?.layer ?? "0", + formatAssTime(line.startMs), + formatAssTime(endMs), + ass?.style ?? "Default", + ass?.name ?? "", + ass?.marginL ?? "0", + ass?.marginR ?? "0", + ass?.marginV ?? "0", + ass?.effect ?? "", + rawText + ].join(",") + ].join(""); + }; + var withAssTitle = (metadata, assTitle) => { + if (!assTitle) return metadata; + const titleLine = `Title: ${assTitle}`; + const scriptInfoLines = [...metadata.scriptInfoLines]; + const existingIndex = scriptInfoLines.findIndex((line) => line.startsWith("Title:")); + if (existingIndex >= 0) { + if (scriptInfoLines[existingIndex] === "Title: Exported subtitles") scriptInfoLines[existingIndex] = titleLine; + } else scriptInfoLines.unshift(titleLine); + return { + ...metadata, + scriptInfoLines + }; + }; + var serializeAss = (processed, options) => { + const sourceMetadata = processed.metadata?.ass; + const metadata = withAssTitle(sourceMetadata && sourceMetadata.scriptInfoLines.length > 0 && sourceMetadata.styleFormat && sourceMetadata.styleLines.length > 0 && sourceMetadata.eventFormat ? sourceMetadata : createDefaultAssMetadata(options?.assTitle), options?.assTitle); + return [ + "[Script Info]", + ...metadata.scriptInfoLines, + "", + "[V4+ Styles]", + metadata.styleFormat, + ...metadata.styleLines, + ...metadata.preEventLines, + "", + "[Events]", + metadata.eventFormat, + ...metadata.commentLines, + ...processed.subtitles.map((line) => serializeAssDialogue({ + ...line, + metadata: processed.format === "ass" ? line.metadata : { + ...line.metadata, + rawText: resolveSerializedText(processed, line, "ass") + } + })) + ].join("\n").trim(); + }; + var parseSubtitleText = (text, format) => { + if (format === "srt") return parseSrt(text); + if (format === "vtt") return parseVtt(text); + return parseAss(text); + }; + var sortProcessedSubtitles = (processed) => ({ + ...processed, + subtitles: toComparableSubtitleOrder(processed.subtitles.map((line, index) => ({ + index, + line + }))) + }); + var toSubtitlesData = (processed) => { + const subtitles = processed.subtitles.map((line) => ({ + text: line.text, + startMs: line.startMs, + durationMs: line.durationMs, + speakerId: line.speakerId, + tokens: line.tokens.map((token) => ({ + text: token.text, + startMs: token.startMs, + durationMs: token.durationMs + })) + })); + return { + containsTokens: subtitles.some((line) => line.tokens.length > 0), + subtitles + }; + }; + var serializeProcessedSubtitles = (processed, format, options) => { + if (format === "json") return toSubtitlesData(processed); + if (format === "srt") return serializeSrt(processed); + if (format === "vtt") return serializeVtt(processed); + return serializeAss(processed, options); + }; + //#endregion + //#region src/utils/download.ts + function toUint32BE(value) { + return new Uint8Array([ + value >>> 24 & 255, + value >>> 16 & 255, + value >>> 8 & 255, + value & 255 + ]); + } + function toSynchsafeInt(value) { + return new Uint8Array([ + value >>> 21 & 127, + value >>> 14 & 127, + value >>> 7 & 127, + value & 127 + ]); + } + function addTitleId3Tag(mp3Buffer, title) { + const titleBytes = new TextEncoder().encode(title); + const frameData = new Uint8Array(titleBytes.length + 1); + frameData[0] = 3; + frameData.set(titleBytes, 1); + const frame = new Uint8Array(10 + frameData.length); + frame.set([ + 84, + 73, + 84, + 50 + ], 0); + frame.set(toUint32BE(frameData.length), 4); + frame.set(frameData, 10); + const header = new Uint8Array(10); + header.set([ + 73, + 68, + 51, + 3, + 0, + 0 + ], 0); + header.set(toSynchsafeInt(frame.length), 6); + const audioBytes = new Uint8Array(mp3Buffer); + const out = new Uint8Array(header.length + frame.length + audioBytes.length); + out.set(header, 0); + out.set(frame, header.length); + out.set(audioBytes, header.length + frame.length); + return new Blob([out], { type: "audio/mpeg" }); + } + function appendChunkToOutputBuffer(out, value, loaded) { + const needed = loaded + value.byteLength; + let nextOut = out; + if (needed > nextOut.length) { + const grown = new Uint8Array(Math.max(needed, nextOut.length * 2)); + grown.set(nextOut.subarray(0, loaded)); + nextOut = grown; + } + nextOut.set(value, loaded); + return { + out: nextOut, + loaded: needed + }; + } + function mergeChunks(chunks, loaded) { + const merged = new Uint8Array(loaded); + let offset = 0; + for (const chunk of chunks) { + merged.set(chunk, offset); + offset += chunk.byteLength; + } + return merged.buffer; + } + async function readResponseArrayBuffer(res, onProgress) { + const total = Number(res.headers.get("Content-Length") ?? 0); + if (!res.body) return res.arrayBuffer(); + const reader = res.body.getReader(); + let loaded = 0; + let out = total > 0 ? new Uint8Array(total) : null; + const chunks = []; + while (true) { + const { done, value } = await reader.read(); + if (done) break; + if (!value || value.byteLength === 0) continue; + if (out) { + const appended = appendChunkToOutputBuffer(out, value, loaded); + out = appended.out; + loaded = appended.loaded; + } else { + chunks.push(value); + loaded += value.byteLength; + } + if (total > 0) onProgress(clamp(Math.round(loaded / total * 100))); + } + if (out) return out.buffer.slice(0, loaded); + return mergeChunks(chunks, loaded); + } + /** + * Downloads a translation file and saves it as an MP3 file with metadata, + * tracking progress when Content-Length is available. + */ + async function downloadTranslation(res, filename, onProgress = () => {}, saveOptions = {}) { + return await downloadBlob(await buildTranslationBlob(res, filename, onProgress), `${filename}.mp3`, saveOptions); + } + async function buildTranslationBlob(res, filename, onProgress = () => {}) { + const arrayBuffer = await readResponseArrayBuffer(res, onProgress); + onProgress(100); + return addTitleId3Tag(arrayBuffer, filename); + } + //#endregion + //#region src/ui/mount.ts + /** + * Compare overlay mount points by DOM identity. + * + * Mount updates should only run when one of the attachment roots actually + * changes (root/portal/tooltip layout root). + */ + function isSameOverlayMount(previous, next) { + return previous.root === next.root && previous.portalContainer === next.portalContainer && previous.subtitlesMountContainer === next.subtitlesMountContainer; + } + /** + * Runs `onChanged` only when mount targets are actually different. + * Returns the mount that should become current state. + */ + function applyOverlayMountUpdate(previous, next, onChanged) { + if (isSameOverlayMount(previous, next)) return previous; + onChanged(next); + return next; + } + //#endregion + //#region src/ui/translationCommands.ts + function isAbortError(error) { + return error instanceof Error && error.name === "AbortError"; + } + async function getVideoDataForTranslation(videoHandler) { + if (!videoHandler.videoData?.videoId) throw new VOTLocalizedError("VOTNoVideoIDFound"); + if (shouldRefreshVideoDataBeforeTranslation(videoHandler)) videoHandler.videoData = await videoHandler.getVideoData(); + if (!videoHandler.videoData?.videoId) throw new VOTLocalizedError("VOTNoVideoIDFound"); + return videoHandler.videoData; + } + function shouldRefreshVideoDataBeforeTranslation(videoHandler) { + return videoHandler.site.host === "vk" && videoHandler.site.additionalData === "clips" || videoHandler.site.host === "douyin"; + } + async function handleTranslationButtonCommand(deps) { + const videoHandler = deps.videoHandler; + if (!videoHandler) return; + debug.log("[handleTranslationBtnClick] click translationBtn"); + if (videoHandler.hasActiveSource()) { + debug.log("[handleTranslationBtnClick] video has active source"); + await videoHandler.stopTranslation(); + return; + } + if (deps.currentStatus === "error" && !deps.currentLoading) deps.transformBtn("none", localizationProvider.get("translateVideo")); + if (deps.currentStatus !== "none" || deps.currentLoading) { + debug.log("[handleTranslationBtnClick] translationBtn isn't in none state"); + videoHandler.actionsAbortController.abort(); + await videoHandler.stopTranslation(); + return; + } + try { + debug.log("[handleTranslationBtnClick] trying execute translation"); + const videoData = await getVideoDataForTranslation(videoHandler); + await videoHandler.videoManager.ensureDetectedLanguageForTranslation(videoData); + debug.log("[handleTranslationBtnClick] Run translateFunc", videoData.videoId); + await videoHandler.translateFunc(videoData.videoId, videoData.isStream, videoData.detectedLanguage, videoData.responseLanguage, videoData.translationHelp); + } catch (err) { + if (isAbortError(err)) { + deps.transformBtn("none", localizationProvider.get("translateVideo")); + return; + } + console.error("[VOT]", err); + if (!(err instanceof Error)) { + deps.transformBtn("error", String(err)); + return; + } + const message = err.name === "VOTLocalizedError" ? err.localizedMessage : err.message; + deps.transformBtn("error", message); + } + } + //#endregion + //#region src/ui/icons.ts + var TRANSLATE_ICON_SVG = w` + + + +`; + var PIP_ICON_SVG = w` + +`; + var MENU_ICON = w` + +`; + var DOWNLOAD_ICON = w` + + +`; + var SUBTITLES_ICON = w` + +`; + var SETTINGS_ICON = w` + +`; + var CHEVRON_ICON = w` + +`; + var ARROW_RIGHT_ICON = w` + +`; + var CLOSE_ICON = w` + +`; + var WARNING_ICON = w` + + + +`; + var HELP_ICON = w` + + + +`; + var REFRESH_ICON = w` + + + + +`; + var KEY_ICON = w` + + `; + //#endregion + //#region src/ui/components/componentShared.ts + function addComponentEventListener(events, type, listener) { + events[type].addListener(listener); + } + function removeComponentEventListener(events, type, listener) { + events[type].removeListener(listener); + } + function setHiddenState(element, isHidden) { + element.hidden = isHidden; + } + function getHiddenState(element) { + return element.hidden; + } + //#endregion + //#region src/ui/components/downloadButton.ts + var DownloadButton = class { + button; + loaderMain; + loaderCircle; + onClick = new EventImpl(); + events = { click: this.onClick }; + _progress = 0; + constructor() { + const elements = this.createElements(); + this.button = elements.button; + this.loaderMain = elements.loaderMain; + this.loaderCircle = elements.loaderCircle; + this.progress = 0; + } + createElements() { + const button = UI.createIconButton(DOWNLOAD_ICON, { ariaLabel: "Download translation" }); + const loaderMain = button.querySelector(".vot-loader-main"); + if (!loaderMain) throw new Error("[VOT] DownloadButton loader main element not found"); + const loaderCircle = button.querySelector(".vot-loader-progress"); + if (!loaderCircle) throw new Error("[VOT] DownloadButton loader circle element not found"); + button.addEventListener("click", () => { + this.onClick.dispatch(); + }); + return { + button, + loaderMain, + loaderCircle + }; + } + addEventListener(_type, listener) { + addComponentEventListener(this.events, "click", listener); + return this; + } + removeEventListener(_type, listener) { + removeComponentEventListener(this.events, "click", listener); + return this; + } + get progress() { + return this._progress; + } + set progress(value) { + const normalized = clampProgress(value); + this._progress = normalized; + const circumference = this.getCircleCircumference(); + this.loaderCircle.style.strokeDasharray = `${circumference}`; + const offset = circumference * (1 - normalized / 100); + this.loaderCircle.style.strokeDashoffset = `${offset}`; + this.loaderMain.style.opacity = normalized === 0 ? "1" : "0"; + this.loaderCircle.style.opacity = normalized === 0 ? "0" : "1"; + } + getCircleCircumference() { + const radius = this.loaderCircle.r?.baseVal?.value ?? 0; + return 2 * Math.PI * radius; + } + set hidden(isHidden) { + setHiddenState(this.button, isHidden); + } + get hidden() { + return getHiddenState(this.button); + } + }; + function clampProgress(value) { + if (!Number.isFinite(value)) return 0; + const asPercent = value < 1 ? value * 100 : value; + return Math.max(0, Math.min(100, Math.round(asPercent))); + } + //#endregion + //#region src/ui/components/label.ts + var Label = class { + container; + icon; + text; + _labelText; + _icon; + constructor({ labelText, icon }) { + this._labelText = labelText; + this._icon = icon; + const elements = this.createElements(); + this.container = elements.container; + this.icon = elements.icon; + this.text = elements.text; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-label"]); + const text = UI.createEl("span", ["vot-label-text"]); + text.textContent = this._labelText; + const icon = UI.createEl("span", ["vot-label-icon"]); + if (this._icon) D(this._icon, icon); + else icon.hidden = true; + container.append(text, icon); + return { + container, + icon, + text + }; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + }; + //#endregion + //#region src/ui/components/dialog.ts + var Dialog = class { + container; + backdrop; + box; + contentWrapper; + headerContainer; + titleContainer; + title; + closeButton; + bodyContainer; + footerContainer; + onClose = new EventImpl(); + events = { close: this.onClose }; + previouslyFocused = null; + keydownListener; + adaptiveAlignObserver; + adaptiveAlignRaf = null; + handleViewportChange = () => { + this.scheduleAdaptiveVerticalAlign(); + }; + titleId = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `vot-dialog-title-${Math.random().toString(36).slice(2)}`; + _titleHtml; + _isTemp; + constructor({ titleHtml, isTemp = false }) { + this._titleHtml = titleHtml; + this._isTemp = isTemp; + const elements = this.createElements(); + this.container = elements.container; + this.backdrop = elements.backdrop; + this.box = elements.box; + this.contentWrapper = elements.contentWrapper; + this.headerContainer = elements.headerContainer; + this.titleContainer = elements.titleContainer; + this.title = elements.title; + this.closeButton = elements.closeButton; + this.bodyContainer = elements.bodyContainer; + this.footerContainer = elements.footerContainer; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-dialog-container"]); + if (this._isTemp) container.classList.add("vot-dialog-temp"); + container.hidden = !this._isTemp; + container.setAttribute("aria-hidden", container.hidden ? "true" : "false"); + container.toggleAttribute("inert", container.hidden); + const backdrop = UI.createEl("vot-block", ["vot-dialog-backdrop"]); + const box = UI.createEl("vot-block", ["vot-dialog"]); + box.dataset.verticalAlign = "center"; + box.setAttribute("role", "dialog"); + box.setAttribute("aria-modal", "true"); + box.tabIndex = -1; + const contentWrapper = UI.createEl("vot-block", ["vot-dialog-content-wrapper"]); + const headerContainer = UI.createEl("vot-block", ["vot-dialog-header-container"]); + const titleContainer = UI.createEl("vot-block", ["vot-dialog-title-container"]); + const title = UI.createEl("vot-block", ["vot-dialog-title"]); + title.id = this.titleId; + title.append(this._titleHtml); + titleContainer.appendChild(title); + box.setAttribute("aria-labelledby", this.titleId); + const closeButton = UI.createIconButton(CLOSE_ICON, { ariaLabel: "Close" }); + closeButton.classList.add("vot-dialog-close-button"); + backdrop.addEventListener("click", () => { + this.close(); + }); + closeButton.addEventListener("click", () => { + this.close(); + }); + headerContainer.append(titleContainer, closeButton); + const bodyContainer = UI.createEl("vot-block", ["vot-dialog-body-container"]); + const footerContainer = UI.createEl("vot-block", ["vot-dialog-footer-container"]); + contentWrapper.append(headerContainer, bodyContainer, footerContainer); + box.appendChild(contentWrapper); + container.append(backdrop, box); + box.addEventListener("click", (e) => { + e.stopPropagation(); + }); + return { + container, + backdrop, + box, + contentWrapper, + headerContainer, + titleContainer, + title, + closeButton, + bodyContainer, + footerContainer + }; + } + addEventListener(_type, listener) { + addComponentEventListener(this.events, "close", listener); + return this; + } + removeEventListener(_type, listener) { + removeComponentEventListener(this.events, "close", listener); + return this; + } + open() { + this.previouslyFocused ??= getDeepActiveElement(document); + this.hidden = false; + this.attachKeydownTrap(); + this.attachAdaptiveVerticalAlign(); + queueMicrotask(() => this.focusFirst()); + return this; + } + remove() { + this.detachAdaptiveVerticalAlign(); + this.detachKeydownTrap(); + this.container.remove(); + this.restoreFocus(); + this.onClose.dispatch(); + return this; + } + close() { + if (this._isTemp) return this.remove(); + this.detachAdaptiveVerticalAlign(); + this.detachKeydownTrap(); + this.hidden = true; + this.restoreFocus(); + this.onClose.dispatch(); + return this; + } + attachAdaptiveVerticalAlign() { + if (this.adaptiveAlignObserver) { + this.scheduleAdaptiveVerticalAlign(); + return; + } + if (typeof ResizeObserver !== "undefined") { + this.adaptiveAlignObserver = new ResizeObserver(() => { + this.scheduleAdaptiveVerticalAlign(); + }); + this.adaptiveAlignObserver.observe(this.contentWrapper); + } + globalThis.addEventListener("resize", this.handleViewportChange, { passive: true }); + if (globalThis.visualViewport) { + globalThis.visualViewport.addEventListener("resize", this.handleViewportChange, { passive: true }); + globalThis.visualViewport.addEventListener("scroll", this.handleViewportChange, { passive: true }); + } + this.scheduleAdaptiveVerticalAlign(); + } + detachAdaptiveVerticalAlign() { + if (this.adaptiveAlignObserver) { + this.adaptiveAlignObserver.disconnect(); + this.adaptiveAlignObserver = void 0; + } + globalThis.removeEventListener("resize", this.handleViewportChange); + globalThis.visualViewport?.removeEventListener("resize", this.handleViewportChange); + globalThis.visualViewport?.removeEventListener("scroll", this.handleViewportChange); + if (this.adaptiveAlignRaf !== null) { + cancelAnimationFrame(this.adaptiveAlignRaf); + this.adaptiveAlignRaf = null; + } + } + scheduleAdaptiveVerticalAlign() { + if (this.adaptiveAlignRaf !== null) cancelAnimationFrame(this.adaptiveAlignRaf); + this.adaptiveAlignRaf = requestAnimationFrame(() => { + this.adaptiveAlignRaf = null; + this.updateAdaptiveVerticalAlign(); + }); + } + updateAdaptiveVerticalAlign() { + const viewportHeight = globalThis.visualViewport?.height ?? globalThis.innerHeight; + if (!viewportHeight || viewportHeight <= 0) return; + const marginPx = 16; + const centerMaxPx = Math.max(160, Math.round(viewportHeight * .75)); + const topMaxPx = Math.max(160, Math.round(viewportHeight - marginPx * 2)); + const contentHeightPx = this.contentWrapper.scrollHeight; + const currentlyTop = this.box.dataset.verticalAlign === "top"; + const enterTopThresholdPx = centerMaxPx - 8; + const exitTopThresholdPx = Math.round(viewportHeight * .6); + if (currentlyTop ? contentHeightPx > exitTopThresholdPx : contentHeightPx >= enterTopThresholdPx) { + this.box.dataset.verticalAlign = "top"; + this.box.style.setProperty("--vot-dialog-max-height", `${topMaxPx}px`); + } else { + this.box.dataset.verticalAlign = "center"; + this.box.style.setProperty("--vot-dialog-max-height", `${centerMaxPx}px`); + } + } + restoreFocus() { + const el = this.previouslyFocused; + this.previouslyFocused = null; + if (el && el instanceof HTMLElement && document.contains(el)) el.focus(); + } + getFocusableElements() { + return Array.from(this.container.querySelectorAll([ + "button:not([disabled])", + "[href]", + "input:not([disabled])", + "select:not([disabled])", + "textarea:not([disabled])", + "[tabindex]:not([tabindex='-1'])", + "[role='button']:not([aria-disabled='true'])" + ].join(","))).filter((el) => !el.hidden && el.getClientRects().length > 0); + } + focusFirst() { + (this.getFocusableElements()[0] ?? this.closeButton ?? this.box).focus?.(); + } + attachKeydownTrap() { + if (this.keydownListener) return; + this.keydownListener = (e) => { + if (e.key === "Escape") { + e.preventDefault(); + this.close(); + return; + } + if (e.key !== "Tab") return; + const focusables = this.getFocusableElements(); + if (!focusables.length) { + e.preventDefault(); + this.box.focus(); + return; + } + const first = focusables[0]; + const last = focusables.at(-1) ?? first; + const active = getDeepActiveElement(this.container.getRootNode()); + if (e.shiftKey) { + if (active === first || active === this.box) { + e.preventDefault(); + last.focus(); + } + } else if (active === last) { + e.preventDefault(); + first.focus(); + } + }; + this.container.addEventListener("keydown", this.keydownListener); + } + detachKeydownTrap() { + if (!this.keydownListener) return; + this.container.removeEventListener("keydown", this.keydownListener); + this.keydownListener = void 0; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + this.container.setAttribute("aria-hidden", isHidden ? "true" : "false"); + this.container.toggleAttribute("inert", isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + get isDialogOpen() { + return !this.container.hidden; + } + }; + //#endregion + //#region src/ui/components/textfield.ts + var Textfield = class { + container; + input; + label; + onInput = new EventImpl(); + onChange = new EventImpl(); + events = { + input: this.onInput, + change: this.onChange + }; + _labelHtml; + _multiline; + _placeholder; + _value; + constructor({ labelHtml = "", placeholder = "", value = "", multiline = false }) { + this._labelHtml = labelHtml; + this._multiline = multiline; + this._placeholder = placeholder; + this._value = value; + const elements = this.createElements(); + this.container = elements.container; + this.input = elements.input; + this.label = elements.label; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-textfield"]); + const input = document.createElement(this._multiline ? "textarea" : "input"); + if (!this._labelHtml) input.classList.add("vot-show-placeholer", "vot-show-placeholder"); + input.placeholder = this._placeholder; + input.value = this._value; + const label = UI.createEl("span"); + label.append(this._labelHtml); + container.append(input, label); + input.addEventListener("input", () => { + this._value = this.input.value; + this.onInput.dispatch(this._value); + }); + input.addEventListener("change", () => { + this._value = this.input.value; + this.onChange.dispatch(this._value); + }); + return { + container, + label, + input + }; + } + addEventListener(type, listener) { + addComponentEventListener(this.events, type, listener); + return this; + } + removeEventListener(type, listener) { + removeComponentEventListener(this.events, type, listener); + return this; + } + get value() { + return this._value; + } + /** + * If you set a different new value, it will trigger the change event + */ + set value(val) { + if (this._value === val) return; + this.input.value = this._value = val; + this.onChange.dispatch(this._value); + } + get placeholder() { + return this._placeholder; + } + set placeholder(text) { + this.input.placeholder = this._placeholder = text; + } + get disabled() { + return this.input.disabled; + } + set disabled(isDisabled) { + this.input.disabled = isDisabled; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + }; + //#endregion + //#region src/ui/components/select.ts + var Select = class { + container; + outer; + arrowIcon; + title; + dialogParent; + labelElement; + _selectTitle; + _dialogTitle; + multiSelect; + baseItems; + _items; + searchItemsProvider; + isLoading = false; + isDialogOpen = false; + searchRequestId = 0; + onSelectItem = new EventImpl(); + onBeforeOpen = new EventImpl(); + events = { + selectItem: this.onSelectItem, + beforeOpen: this.onBeforeOpen + }; + contentList; + contentItemSearchDatasetKey = "votSearchLabel"; + contentItemIndexDatasetKey = "votIndex"; + selectedItems = []; + selectedValues; + constructor({ selectTitle, dialogTitle, items, searchItemsProvider, labelElement, dialogParent = document.documentElement, multiSelect }) { + this._selectTitle = selectTitle; + this._dialogTitle = dialogTitle; + this.baseItems = this.cloneItems(items); + this._items = this.cloneItems(items); + this.searchItemsProvider = searchItemsProvider; + this.multiSelect = multiSelect ?? false; + this.labelElement = labelElement; + this.dialogParent = dialogParent; + this.selectedValues = this.calcSelectedValues(); + const elements = this.createElements(); + this.container = elements.container; + this.outer = elements.outer; + this.arrowIcon = elements.arrowIcon; + this.title = elements.title; + } + cloneItems(items) { + return items.map((item) => ({ ...item })); + } + static genLanguageItems(langs, conditionString) { + return langs.map((lang) => { + const phrase = `langs.${lang}`; + const label = localizationProvider.get(phrase); + return { + label: label === phrase ? lang.toUpperCase() : label, + value: lang, + selected: conditionString === lang + }; + }); + } + multiSelectItemHandle = (item) => { + const value = item.value; + if (this.selectedValues.has(value) && this.selectedValues.size > 1) this.selectedValues.delete(value); + else this.selectedValues.add(value); + this.syncItemsSelectionState(); + this.syncItemsSelectionState(this.baseItems); + this.updateSelectedState(); + this.onSelectItem.dispatch(Array.from(this.selectedValues)); + }; + singleSelectItemHandle = (item) => { + const value = item.value; + this.selectedValues = new Set([value]); + this.syncItemsSelectionState(); + this.syncItemsSelectionState(this.baseItems); + this.updateSelectedState(); + this.onSelectItem.dispatch(value); + }; + onContentItemClick = (event) => { + if (!(event.target instanceof HTMLElement)) return; + const contentItem = event.target.closest(".vot-select-content-item"); + if (!contentItem || contentItem.inert || !this.contentList?.contains(contentItem)) return; + const rawIndex = contentItem.dataset[this.contentItemIndexDatasetKey]; + if (!rawIndex) return; + const item = this._items[Number(rawIndex)]; + if (!item) return; + if (this.multiSelect) { + this.multiSelectItemHandle(item); + return; + } + this.singleSelectItemHandle(item); + }; + syncItemsSelectionState(items = this._items) { + for (const item of items) item.selected = this.selectedValues.has(item.value); + } + restoreBaseItems() { + this._items = this.cloneItems(this.baseItems); + this.syncItemsSelectionState(); + this.updateSelectedState(); + } + createDialogContentList() { + const contentList = UI.createEl("vot-block", ["vot-select-content-list"]); + for (const [index, item] of this._items.entries()) { + const contentItem = UI.createEl("vot-block", ["vot-select-content-item"]); + contentItem.textContent = item.label; + contentItem.dataset.votSelected = item.selected === true ? "true" : "false"; + contentItem.dataset.votValue = item.value; + contentItem.dataset[this.contentItemSearchDatasetKey] = item.label.toLowerCase(); + contentItem.dataset[this.contentItemIndexDatasetKey] = String(index); + if (item.disabled) contentItem.inert = true; + contentList.appendChild(contentItem); + } + contentList.addEventListener("click", this.onContentItemClick); + this.selectedItems = Array.from(contentList.children); + return contentList; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-select"]); + if (this.labelElement) { + container.classList.add("vot-select--labeled"); + container.append(this.labelElement); + } else container.classList.add("vot-select--control-only"); + const outer = UI.createEl("vot-block", ["vot-select-outer"]); + UI.makeButtonLike(outer); + outer.setAttribute("aria-haspopup", "dialog"); + outer.setAttribute("aria-expanded", "false"); + const title = UI.createEl("vot-block", ["vot-select-title"]); + title.textContent = this.visibleText; + const arrowIcon = UI.createEl("vot-block", ["vot-select-arrow-icon"]); + D(CHEVRON_ICON, arrowIcon); + outer.append(title, arrowIcon); + outer.addEventListener("click", () => { + if (this.disabled) return; + if (this.isLoading || this.isDialogOpen) return; + try { + this.isLoading = true; + const tempDialog = new Dialog({ + titleHtml: this._dialogTitle, + isTemp: true + }); + this.onBeforeOpen.dispatch(tempDialog); + this.dialogParent.appendChild(tempDialog.container); + this.isDialogOpen = true; + outer.setAttribute("aria-expanded", "true"); + const votSearchLangTextfield = new Textfield({ labelHtml: localizationProvider.get("searchField") }); + votSearchLangTextfield.addEventListener("input", async (searchText) => { + const requestId = ++this.searchRequestId; + if (this.searchItemsProvider) { + const providedItems = await this.searchItemsProvider(searchText); + if (requestId !== this.searchRequestId) return; + this.updateItems(providedItems, { persist: false }); + } + const normalizedSearchText = searchText.toLowerCase(); + for (const contentItem of this.selectedItems) contentItem.hidden = !(contentItem.dataset[this.contentItemSearchDatasetKey] ?? "").includes(normalizedSearchText); + }); + this.contentList = this.createDialogContentList(); + tempDialog.bodyContainer.append(votSearchLangTextfield.container, this.contentList); + tempDialog.addEventListener("close", () => { + this.isDialogOpen = false; + this.restoreBaseItems(); + this.selectedItems = []; + this.contentList = void 0; + outer.setAttribute("aria-expanded", "false"); + }); + tempDialog.open(); + } finally { + this.isLoading = false; + } + }); + container.appendChild(outer); + return { + container, + outer, + arrowIcon, + title + }; + } + calcSelectedValues() { + return new Set(this._items.filter((item) => item.selected).map((item) => item.value)); + } + addEventListener(type, listener) { + addComponentEventListener(this.events, type, listener); + return this; + } + removeEventListener(type, listener) { + removeComponentEventListener(this.events, type, listener); + return this; + } + updateTitle() { + this.title.textContent = this.visibleText; + return this; + } + updateSelectedState() { + if (this.selectedItems.length > 0) for (const item of this.selectedItems) { + const val = item.dataset.votValue; + if (val === void 0) continue; + item.dataset.votSelected = this.selectedValues.has(val).toString(); + } + this.updateTitle(); + return this; + } + setSelectedValue(value) { + const values = Array.isArray(value) ? value : [value]; + let selectedValues; + if (this.multiSelect) selectedValues = values; + else selectedValues = values.length > 0 ? [values[0]] : []; + this.selectedValues = new Set(selectedValues); + this.syncItemsSelectionState(); + this.syncItemsSelectionState(this.baseItems); + this.updateSelectedState(); + return this; + } + /** + * @warning Use chaining with this method or reassign to variable to get the updated type of instance + */ + updateItems(newItems, options = {}) { + const { persist = true } = options; + const nextItems = this.cloneItems(newItems); + if (persist) this.baseItems = this.cloneItems(nextItems); + this._items = nextItems; + this.selectedValues = this.calcSelectedValues(); + this.updateSelectedState(); + const dialogContainer = this.contentList?.parentElement; + if (!this.contentList || !dialogContainer) return this; + const oldContentList = this.contentList; + this.contentList = this.createDialogContentList(); + dialogContainer.replaceChild(this.contentList, oldContentList); + return this; + } + get visibleText() { + if (!this.multiSelect) return this._items.find((item) => item.selected)?.label ?? this._selectTitle; + return this._items.filter((item) => this.selectedValues.has(item.value)).map((item) => item.label).join(", ") || this._selectTitle; + } + set selectTitle(title) { + this._selectTitle = title; + this.updateTitle(); + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + get disabled() { + return this.outer.getAttribute("disabled") === "true" || this.outer.getAttribute("aria-disabled") === "true"; + } + set disabled(isDisabled) { + if (isDisabled) { + this.outer.setAttribute("disabled", "true"); + return; + } + this.outer.removeAttribute("disabled"); + } + }; + //#endregion + //#region src/ui/components/languagePairSelect.ts + var LanguagePairSelect = class { + container; + fromSelect; + directionIcon; + toSelect; + dialogParent; + _fromSelectTitle; + _fromDialogTitle; + _fromItems; + _toSelectTitle; + _toDialogTitle; + _toItems; + constructor({ from: { selectTitle: fromSelectTitle = localizationProvider.get("videoLanguage"), dialogTitle: fromDialogTitle = localizationProvider.get("videoLanguage"), items: fromItems }, to: { selectTitle: toSelectTitle = localizationProvider.get("translationLanguage"), dialogTitle: toDialogTitle = localizationProvider.get("translationLanguage"), items: toItems }, dialogParent = document.documentElement }) { + this._fromSelectTitle = fromSelectTitle; + this._fromDialogTitle = fromDialogTitle; + this._fromItems = fromItems; + this._toSelectTitle = toSelectTitle; + this._toDialogTitle = toDialogTitle; + this._toItems = toItems; + this.dialogParent = dialogParent; + const elements = this.createElements(); + this.container = elements.container; + this.fromSelect = elements.fromSelect; + this.directionIcon = elements.directionIcon; + this.toSelect = elements.toSelect; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-lang-select"]); + const fromSelect = new Select({ + selectTitle: this._fromSelectTitle, + dialogTitle: this._fromDialogTitle, + items: this._fromItems, + dialogParent: this.dialogParent + }); + const directionIcon = UI.createEl("vot-block", ["vot-lang-select-icon"]); + D(ARROW_RIGHT_ICON, directionIcon); + const toSelect = new Select({ + selectTitle: this._toSelectTitle, + dialogTitle: this._toDialogTitle, + items: this._toItems, + dialogParent: this.dialogParent + }); + container.append(fromSelect.container, directionIcon, toSelect.container); + return { + container, + fromSelect, + directionIcon, + toSelect + }; + } + setSelectedValues(from, to) { + this.fromSelect.setSelectedValue(from); + this.toSelect.setSelectedValue(to); + return this; + } + updateItems(fromItems, toItems) { + this._fromItems = fromItems; + this._toItems = toItems; + this.fromSelect = this.fromSelect.updateItems(fromItems); + this.toSelect = this.toSelect.updateItems(toItems); + return this; + } + }; + //#endregion + //#region src/ui/components/slider.ts + var Slider = class { + container; + input; + label; + onInput = new EventImpl(); + _labelHtml; + _value; + _min; + _max; + _step; + constructor({ labelHtml, value = 50, min = 0, max = 100, step = 1 }) { + this._labelHtml = labelHtml; + this._value = value; + this._min = min; + this._max = max; + this._step = step; + const elements = this.createElements(); + this.container = elements.container; + this.input = elements.input; + this.label = elements.label; + this.update(); + } + updateProgress() { + const range = this._max - this._min; + const raw = range <= 0 ? 0 : (this._value - this._min) / range; + const progress = Math.max(0, Math.min(1, raw)); + this.container.style.setProperty("--vot-progress", progress.toString()); + return this; + } + update() { + this._value = this.input.valueAsNumber; + this._min = +this.input.min; + this._max = +this.input.max; + this.updateProgress(); + return this; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-slider"]); + const input = document.createElement("input"); + input.type = "range"; + input.min = this._min.toString(); + input.max = this._max.toString(); + input.step = this._step.toString(); + input.value = this._value.toString(); + const label = UI.createEl("span"); + D(this._labelHtml, label); + container.append(input, label); + input.addEventListener("input", () => { + this.update(); + this.onInput.dispatch(this._value, false); + }); + return { + container, + label, + input + }; + } + addEventListener(_type, listener) { + this.onInput.addListener(listener); + return this; + } + removeEventListener(_type, listener) { + this.onInput.removeListener(listener); + return this; + } + get value() { + return this._value; + } + /** + * If you set a different new value, it will trigger the input event + */ + set value(val) { + this._value = clampNumber(val, this._min, this._max); + this.input.value = this._value.toString(); + this.updateProgress(); + this.onInput.dispatch(this._value, true); + } + get min() { + return this._min; + } + set min(val) { + this._min = val; + this.input.min = this._min.toString(); + this._value = clampNumber(this._value, this._min, this._max); + this.input.value = this._value.toString(); + this.updateProgress(); + } + get max() { + return this._max; + } + set max(val) { + this._max = val; + this.input.max = this._max.toString(); + this._value = clampNumber(this._value, this._min, this._max); + this.input.value = this._value.toString(); + this.updateProgress(); + } + get step() { + return this._step; + } + set step(val) { + this._step = val; + this.input.step = this._step.toString(); + } + get disabled() { + return this.input.disabled; + } + set disabled(isDisabled) { + this.input.disabled = isDisabled; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + }; + function clampNumber(value, min, max) { + if (!Number.isFinite(value)) return min; + if (max < min) return min; + return Math.max(min, Math.min(max, value)); + } + //#endregion + //#region src/ui/components/sliderLabel.ts + var SliderLabel = class { + container; + strong; + text; + _labelText; + _labelEOL; + _value; + _symbol; + constructor({ labelText, labelEOL = "", value = 50, symbol = "%" }) { + this._labelText = labelText; + this._labelEOL = labelEOL; + this._value = value; + this._symbol = symbol; + const elements = this.createElements(); + this.container = elements.container; + this.strong = elements.strong; + this.text = elements.text; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-slider-label"]); + const text = UI.createEl("span", ["vot-slider-label-text"]); + text.textContent = this.labelText; + const strong = UI.createEl("span", ["vot-slider-label-value"]); + strong.textContent = this.valueText; + container.append(text, strong); + return { + container, + strong, + text + }; + } + get labelText() { + return `${this._labelText}${this._labelEOL}`; + } + get valueText() { + return `${this._value}${this._symbol}`; + } + get value() { + return this._value; + } + set value(val) { + this._value = val; + this.strong.textContent = this.valueText; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + }; + //#endregion + //#region src/ui/components/votButton.ts + var VOTButton = class { + container; + translateButton; + separator; + pipButton; + separator2; + menuButton; + label; + _opacity = 1; + _position; + _direction; + _status; + /** Text shown next to the translate icon (plain text, not HTML). */ + _labelText; + constructor({ position = "default", direction = "default", status = "none", labelHtml = "" }) { + this._position = position; + this._direction = direction; + this._status = status; + this._labelText = labelHtml; + const elements = this.createElements(); + this.container = elements.container; + this.translateButton = elements.translateButton; + this.separator = elements.separator; + this.pipButton = elements.pipButton; + this.separator2 = elements.separator2; + this.menuButton = elements.menuButton; + this.label = elements.label; + } + static calcPosition(percentX, isBigContainer) { + if (!isBigContainer) return "default"; + if (percentX <= 44) return "left"; + if (percentX >= 66) return "right"; + return "default"; + } + static calcDirection(position) { + return ["default", "top"].includes(position) ? "row" : "column"; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-segmented-button"]); + container.dataset.position = this._position; + container.dataset.direction = this._direction; + container.dataset.status = this._status; + const translateButton = UI.createEl("vot-block", ["vot-segment", "vot-translate-button"]); + translateButton.setAttribute("role", "button"); + translateButton.tabIndex = 0; + translateButton.setAttribute("aria-label", this._labelText || "Translate"); + D(TRANSLATE_ICON_SVG, translateButton); + const label = UI.createEl("span", ["vot-segment-label"]); + label.textContent = this._labelText; + translateButton.appendChild(label); + const separator = UI.createEl("vot-block", ["vot-separator"]); + const pipButton = UI.createEl("vot-block", ["vot-segment-only-icon"]); + pipButton.setAttribute("role", "button"); + pipButton.tabIndex = 0; + pipButton.setAttribute("aria-label", "Picture in picture"); + D(PIP_ICON_SVG, pipButton); + const separator2 = UI.createEl("vot-block", ["vot-separator"]); + const menuButton = UI.createEl("vot-block", ["vot-segment-only-icon"]); + menuButton.setAttribute("role", "button"); + menuButton.tabIndex = 0; + menuButton.setAttribute("aria-label", "Menu"); + menuButton.setAttribute("aria-haspopup", "dialog"); + menuButton.setAttribute("aria-expanded", "false"); + D(MENU_ICON, menuButton); + container.append(translateButton, separator, pipButton, separator2, menuButton); + return { + container, + translateButton, + separator, + pipButton, + separator2, + menuButton, + label + }; + } + showPiPButton(visible) { + this.separator2.hidden = this.pipButton.hidden = !visible; + return this; + } + setText(labelText) { + this._labelText = labelText; + this.label.textContent = labelText; + this.translateButton.setAttribute("aria-label", labelText || "Translate"); + return this; + } + remove() { + this.container.remove(); + return this; + } + get tooltipPos() { + switch (this.position) { + case "left": return "right"; + case "right": return "left"; + default: return "bottom"; + } + } + set status(status) { + this._status = this.container.dataset.status = status; + } + get status() { + return this._status; + } + set loading(isLoading) { + this.container.dataset.loading = isLoading.toString(); + } + get loading() { + return this.container.dataset.loading === "true"; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + get position() { + return this._position; + } + set position(position) { + this._position = this.container.dataset.position = position; + } + get direction() { + return this._direction; + } + set direction(direction) { + this._direction = this.container.dataset.direction = direction; + } + set opacity(opacity) { + const o = Number.isFinite(opacity) ? opacity : 1; + this._opacity = o; + const isHidden = o <= .01; + this.container.classList.toggle("vot-segmented-button--hidden", isHidden); + } + get opacity() { + return this._opacity; + } + }; + //#endregion + //#region src/ui/components/votMenu.ts + var VOTMenu = class { + container; + contentWrapper; + headerContainer; + bodyContainer; + footerContainer; + titleContainer; + title; + _position; + _titleHtml; + menuId = typeof crypto !== "undefined" && "randomUUID" in crypto ? `vot-menu-${crypto.randomUUID()}` : `vot-menu-${Math.random().toString(36).slice(2)}`; + titleId = typeof crypto !== "undefined" && "randomUUID" in crypto ? `vot-menu-title-${crypto.randomUUID()}` : `vot-menu-title-${Math.random().toString(36).slice(2)}`; + constructor({ position = "default", titleHtml = "" }) { + this._position = position; + this._titleHtml = titleHtml; + const elements = this.createElements(); + this.container = elements.container; + this.contentWrapper = elements.contentWrapper; + this.headerContainer = elements.headerContainer; + this.bodyContainer = elements.bodyContainer; + this.footerContainer = elements.footerContainer; + this.titleContainer = elements.titleContainer; + this.title = elements.title; + } + createElements() { + const container = UI.createEl("vot-block", ["vot-menu"]); + container.hidden = true; + container.id = this.menuId; + container.dataset.position = this._position; + container.setAttribute("role", "dialog"); + container.setAttribute("aria-modal", "false"); + container.setAttribute("aria-hidden", "true"); + container.toggleAttribute("inert", true); + const contentWrapper = UI.createEl("vot-block", ["vot-menu-content-wrapper"]); + container.appendChild(contentWrapper); + const headerContainer = UI.createEl("vot-block", ["vot-menu-header-container"]); + const titleContainer = UI.createEl("vot-block", ["vot-menu-title-container"]); + headerContainer.appendChild(titleContainer); + const title = UI.createEl("vot-block", ["vot-menu-title"]); + title.id = this.titleId; + title.append(this._titleHtml); + titleContainer.appendChild(title); + container.setAttribute("aria-labelledby", this.titleId); + const bodyContainer = UI.createEl("vot-block", ["vot-menu-body-container"]); + const footerContainer = UI.createEl("vot-block", ["vot-menu-footer-container"]); + contentWrapper.append(headerContainer, bodyContainer, footerContainer); + return { + container, + contentWrapper, + headerContainer, + bodyContainer, + footerContainer, + titleContainer, + title + }; + } + setText(titleText) { + this._titleHtml = this.title.textContent = titleText; + return this; + } + remove() { + this.container.remove(); + return this; + } + set hidden(isHidden) { + setHiddenState(this.container, isHidden); + this.container.setAttribute("aria-hidden", isHidden ? "true" : "false"); + this.container.toggleAttribute("inert", isHidden); + } + get hidden() { + return getHiddenState(this.container); + } + get position() { + return this._position; + } + set position(position) { + this._position = this.container.dataset.position = position; + } + }; + //#endregion + //#region src/ui/views/overlay.ts + var OverlayView = class OverlayView { + static BIG_CONTAINER_WIDTH_PX = 550; + mount; + globalPortal; + abortController = null; + defaultVolumePersistTimer; + defaultVolumePersistDelayMs = 250; + dragging = false; + dragCandidate = false; + dragDirty = false; + dragStartX = 0; + dragStartY = 0; + currentClientX = 0; + activePointerId = null; + dragThresholdPx = 6; + containerRect = null; + dragIsBigContainer = null; + checkerUnsubscribe = null; + initialized = false; + data; + videoHandler; + intervalIdleChecker; + overlayMount; + events = { + "click:settings": new EventImpl(), + "click:pip": new EventImpl(), + "click:downloadTranslation": new EventImpl(), + "click:downloadSubtitles": new EventImpl(), + "click:translate": new EventImpl(), + "input:videoVolume": new EventImpl(), + "input:translationVolume": new EventImpl(), + "select:fromLanguage": new EventImpl(), + "select:toLanguage": new EventImpl(), + "select:subtitles": new EventImpl() + }; + votButton; + votButtonTooltip; + votMenu; + downloadTranslationButton; + downloadSubtitlesButton; + openSettingsButton; + languagePairSelect; + subtitlesSelectLabel; + subtitlesSelect; + videoVolumeSliderLabel; + videoVolumeSlider; + translationVolumeSliderLabel; + translationVolumeSlider; + constructor({ mount, globalPortal, data = {}, videoHandler, intervalIdleChecker }) { + this.mount = mount; + this.globalPortal = globalPortal; + this.data = data; + this.videoHandler = videoHandler; + this.intervalIdleChecker = intervalIdleChecker; + } + get root() { + return this.overlayMount?.root ?? this.mount.root; + } + get portalContainer() { + return this.mount.portalContainer; + } + /** + * Update mount points when the player container changes. + * Moves already-mounted UI nodes and rebinds root-bound listeners (dragging). + */ + updateMount(nextMount) { + const prevRoot = this.mount.root; + const nextRoot = nextMount.root; + this.mount = nextMount; + if (!this.isInitialized()) return this; + if (prevRoot !== nextRoot) if (this.overlayMount) reparentShadowMount(this.overlayMount, nextRoot); + else { + if (this.votButton) nextRoot.appendChild(this.votButton.container); + if (this.votMenu) nextRoot.appendChild(this.votMenu.container); + } + if (this.votButtonTooltip && prevRoot !== nextRoot) this.votButtonTooltip.updateMount({ + parentElement: this.root, + layoutRoot: this.overlayMount?.host + }); + return this; + } + isInitialized() { + return this.initialized; + } + calcButtonLayout(position) { + if (this.isBigContainer && isSidePosition(position)) return { + direction: "column", + position + }; + return { + direction: "row", + position: "default" + }; + } + addEventListener(type, listener) { + this.events[type].addListener(listener); + return this; + } + removeEventListener(type, listener) { + this.events[type].removeListener(listener); + return this; + } + scheduleDefaultVolumePersist() { + if (this.defaultVolumePersistTimer !== void 0) globalThis.clearTimeout(this.defaultVolumePersistTimer); + this.defaultVolumePersistTimer = globalThis.setTimeout(() => { + this.defaultVolumePersistTimer = void 0; + this.flushDefaultVolumePersist(); + }, this.defaultVolumePersistDelayMs); + } + flushDefaultVolumePersist() { + if (this.defaultVolumePersistTimer !== void 0) { + globalThis.clearTimeout(this.defaultVolumePersistTimer); + this.defaultVolumePersistTimer = void 0; + } + if (typeof this.data.defaultVolume !== "number") return; + votStorage.set("defaultVolume", this.data.defaultVolume); + } + initUI(buttonPosition = "default") { + if (this.isInitialized()) throw new Error("[VOT] OverlayView is already initialized"); + this.initialized = true; + this.overlayMount = createShadowMount({ + parent: this.mount.root, + rootClasses: ["vot-overlay-root"], + hostStyles: { + position: "absolute", + inset: "0", + display: "block", + "pointer-events": "none" + }, + rootStyles: { + position: "relative", + display: "block", + width: "100%", + height: "100%", + "pointer-events": "none" + } + }); + const { position, direction } = this.calcButtonLayout(buttonPosition); + this.votButton = new VOTButton({ + position, + direction, + status: "none", + labelHtml: localizationProvider.get("translateVideo") + }); + this.votButton.opacity = 0; + if (!this.pipButtonVisible) this.votButton.showPiPButton(false); + this.root.appendChild(this.votButton.container); + this.votButtonTooltip = new Tooltip({ + target: this.votButton.translateButton, + content: localizationProvider.get("translateVideo"), + position: this.votButton.tooltipPos, + autoLayout: false, + hidden: direction === "row", + bordered: false, + parentElement: this.root, + layoutRoot: this.overlayMount.host + }); + this.votMenu = new VOTMenu({ + titleHtml: localizationProvider.get("VOTSettings"), + position + }); + this.root.appendChild(this.votMenu.container); + this.votButton.menuButton.setAttribute("aria-controls", this.votMenu.container.id); + this.downloadTranslationButton = new DownloadButton(); + this.downloadTranslationButton.hidden = true; + this.downloadSubtitlesButton = UI.createIconButton(SUBTITLES_ICON, { ariaLabel: "Download subtitles" }); + this.downloadSubtitlesButton.hidden = true; + this.openSettingsButton = UI.createIconButton(SETTINGS_ICON, { ariaLabel: localizationProvider.get("VOTSettings") }); + this.votMenu.headerContainer.append(this.downloadTranslationButton.button, this.downloadSubtitlesButton, this.openSettingsButton); + const detectedLanguage = this.videoHandler?.videoData?.detectedLanguage ?? "en"; + const responseLanguage = this.data.responseLanguage ?? "ru"; + this.languagePairSelect = new LanguagePairSelect({ + from: { + selectTitle: localizationProvider.get(`langs.${detectedLanguage}`), + items: Select.genLanguageItems(availableLangs, detectedLanguage) + }, + to: { + selectTitle: localizationProvider.get(`langs.${responseLanguage}`), + items: Select.genLanguageItems(availableTTS, responseLanguage) + }, + dialogParent: this.globalPortal + }); + this.subtitlesSelectLabel = new Label({ labelText: localizationProvider.get("VOTSubtitles") }); + this.subtitlesSelect = new Select({ + selectTitle: localizationProvider.get("VOTSubtitlesDisabled"), + dialogTitle: localizationProvider.get("VOTSubtitles"), + labelElement: this.subtitlesSelectLabel.container, + dialogParent: this.globalPortal, + items: [{ + label: localizationProvider.get("VOTSubtitlesDisabled"), + value: "disabled", + selected: true + }] + }); + const videoVolume = this.videoHandler ? this.videoHandler.getVideoVolume() * 100 : 100; + this.videoVolumeSliderLabel = new SliderLabel({ + labelText: localizationProvider.get("VOTVolume"), + value: videoVolume + }); + this.videoVolumeSlider = new Slider({ + labelHtml: this.videoVolumeSliderLabel.container, + value: videoVolume + }); + this.videoVolumeSlider.hidden = !this.data.showVideoSlider || this.votButton.status !== "success"; + const defaultVolume = this.data.defaultVolume ?? 100; + this.translationVolumeSliderLabel = new SliderLabel({ + labelText: localizationProvider.get("VOTVolumeTranslation"), + value: defaultVolume + }); + this.translationVolumeSlider = new Slider({ + labelHtml: this.translationVolumeSliderLabel.container, + value: defaultVolume, + max: this.data.audioBooster && !this.data.syncVolume ? 900 : 100 + }); + this.translationVolumeSlider.hidden = this.votButton.status !== "success"; + this.votMenu.bodyContainer.append(this.languagePairSelect.container, this.subtitlesSelect.container, this.videoVolumeSlider.container, this.translationVolumeSlider.container); + return this; + } + initUIEvents() { + if (!this.isInitialized()) throw new Error("[VOT] OverlayView isn't initialized"); + this.abortController = new AbortController(); + const signal = this.abortController.signal; + this.checkerUnsubscribe?.(); + this.checkerUnsubscribe = this.intervalIdleChecker.subscribe(() => { + this.onCheckerTick(); + }); + this.votButton.container.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); + }, { signal }); + const activateOnKey = (handler) => (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handler(); + } + }; + const isPrimaryActionPointer = (event) => event.isPrimary && event.button === 0; + const setMenuOpen = (open, { returnFocusToToggle = false } = {}) => { + if (!this.isInitialized()) return; + this.votMenu.hidden = !open; + this.votButton.menuButton.setAttribute("aria-expanded", open.toString()); + if (this.votButtonTooltip) this.votButtonTooltip.hidden = open || this.votButton.direction === "row"; + if (open) queueMicrotask(() => this.openSettingsButton?.focus?.()); + else if (returnFocusToToggle) queueMicrotask(() => this.votButton.menuButton.focus?.()); + else this.votButton.menuButton.blur(); + }; + const toggleMenu = () => setMenuOpen(this.votMenu.hidden); + const closeMenu = (returnFocusToToggle = false) => setMenuOpen(false, { returnFocusToToggle }); + this.votButton.translateButton.addEventListener("pointerdown", (event) => { + if (!isPrimaryActionPointer(event)) return; + closeMenu(); + this.events["click:translate"].dispatch(); + }, { signal }); + this.votButton.translateButton.addEventListener("keydown", activateOnKey(() => { + closeMenu(); + this.events["click:translate"].dispatch(); + }), { signal }); + this.votButton.pipButton.addEventListener("pointerdown", (event) => { + if (!isPrimaryActionPointer(event)) return; + closeMenu(); + this.events["click:pip"].dispatch(); + }, { signal }); + this.votButton.pipButton.addEventListener("keydown", activateOnKey(() => { + closeMenu(); + this.events["click:pip"].dispatch(); + }), { signal }); + this.votButton.menuButton.addEventListener("pointerdown", (e) => { + if (!isPrimaryActionPointer(e)) return; + e.preventDefault(); + toggleMenu(); + }, { signal }); + this.votButton.menuButton.addEventListener("keydown", activateOnKey(toggleMenu), { signal }); + const touchAction = "none"; + this.votButton.container.style.touchAction = touchAction; + this.votButton.translateButton.style.touchAction = touchAction; + this.votButton.pipButton.style.touchAction = touchAction; + this.votButton.menuButton.style.touchAction = touchAction; + this.votButton.container.addEventListener("pointerdown", this.onDragStart, { signal }); + this.votButton.container.addEventListener("pointermove", this.onPointerMove, { signal }); + this.votButton.container.addEventListener("pointerup", this.onDragEnd, { signal }); + this.votButton.container.addEventListener("pointercancel", this.onDragEnd, { signal }); + this.votButton.container.addEventListener("lostpointercapture", this.onDragEnd, { signal }); + this.votMenu.container.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + e.stopImmediatePropagation(); + }, { signal }); + for (const event of ["pointerdown", "mousedown"]) this.votMenu.container.addEventListener(event, (e) => { + e.stopImmediatePropagation(); + }, { signal }); + document.addEventListener("pointerdown", (e) => { + if (this.votMenu.hidden) return; + const target = e.target; + const path = typeof e.composedPath === "function" ? e.composedPath() : []; + const isInsideMenu = target && this.votMenu.container.contains(target) || path.includes(this.votMenu.container); + const isInsideToggle = target && this.votButton.menuButton.contains(target) || path.includes(this.votButton.menuButton); + const isInsideButton = target && this.votButton.container.contains(target) || path.includes(this.votButton.container); + const isInsideDialog = path.some((node) => node instanceof HTMLElement && node.classList.contains("vot-dialog-container")); + if (isInsideMenu || isInsideToggle || isInsideButton || isInsideDialog) return; + closeMenu(false); + }, { + signal, + capture: true, + passive: true + }); + this.votMenu.container.addEventListener("keydown", (e) => { + if (e.key !== "Escape") return; + const keyboardNav = document.documentElement.classList.contains("vot-keyboard-nav"); + e.preventDefault(); + e.stopPropagation(); + closeMenu(keyboardNav); + if (!(this.votButton.container.matches(":hover") || this.votMenu.container.matches(":hover"))) this.videoHandler?.overlayVisibility?.queueAutoHide?.(); + }, { signal }); + this.downloadTranslationButton.addEventListener("click", () => { + this.events["click:downloadTranslation"].dispatch(); + }); + this.downloadSubtitlesButton.addEventListener("click", () => { + this.events["click:downloadSubtitles"].dispatch(); + }, { signal }); + this.openSettingsButton.addEventListener("click", () => { + closeMenu(); + this.events["click:settings"].dispatch(); + }, { signal }); + this.languagePairSelect.fromSelect.addEventListener("selectItem", (language) => { + if (this.videoHandler?.videoData) { + this.videoHandler.videoData.detectedLanguage = language; + this.videoHandler.videoManager.rememberUserLanguageSelection(this.videoHandler.videoData.videoId, language); + } + this.events["select:fromLanguage"].dispatch(language); + }); + this.languagePairSelect.toSelect.addEventListener("selectItem", async (language) => { + if (this.videoHandler?.videoData) this.videoHandler.translateToLang = this.videoHandler.videoData.responseLanguage = language; + const prevResponseLanguage = this.data.responseLanguage; + if (prevResponseLanguage !== language) { + this.data.responseLanguage = language; + await votStorage.set("responseLanguage", this.data.responseLanguage); + } + if (this.data.enabledDontTranslateLanguages && Array.isArray(this.data.dontTranslateLanguages) && this.data.dontTranslateLanguages.length === 1 && prevResponseLanguage !== language && typeof prevResponseLanguage === "string" && this.data.dontTranslateLanguages[0] === prevResponseLanguage) { + this.data.dontTranslateLanguages = [language]; + await votStorage.set("dontTranslateLanguages", this.data.dontTranslateLanguages); + } + this.events["select:toLanguage"].dispatch(language); + }); + this.subtitlesSelect.addEventListener("beforeOpen", async (dialog) => { + if (!this.videoHandler?.videoData) return; + const subtitleLanguage = this.videoHandler.getPreferredSubtitlesLanguage(this.videoHandler.videoData.detectedLanguage, this.videoHandler.videoData.responseLanguage); + if (!subtitleLanguage) return; + const cacheKey = this.videoHandler.getSubtitlesCacheKey(this.videoHandler.videoData.videoId, this.videoHandler.videoData.detectedLanguage, subtitleLanguage); + if (this.videoHandler.subtitlesCacheKey === cacheKey) return; + if (this.videoHandler.cacheManager.getSubtitles(cacheKey) !== void 0) { + await this.videoHandler.ensureSubtitlesForCurrentLangPair(); + return; + } + const prevLoading = this.votButton?.loading ?? false; + if (this.votButton) this.votButton.loading = true; + const loadingEl = UI.createInlineLoader(); + loadingEl.style.margin = "0 auto"; + dialog.footerContainer.appendChild(loadingEl); + try { + await this.videoHandler.ensureSubtitlesForCurrentLangPair(); + } finally { + loadingEl.remove(); + if (this.votButton) this.votButton.loading = prevLoading; + } + }); + this.subtitlesSelect.addEventListener("selectItem", (data) => { + this.events["select:subtitles"].dispatch(data); + }); + this.videoVolumeSlider.addEventListener("input", (value, fromSetter) => { + if (this.videoVolumeSliderLabel) this.videoVolumeSliderLabel.value = value; + if (fromSetter) return; + this.events["input:videoVolume"].dispatch(value); + }); + this.translationVolumeSlider.addEventListener("input", (value, fromSetter) => { + if (this.translationVolumeSliderLabel) this.translationVolumeSliderLabel.value = value; + if (this.data.defaultVolume !== value) { + this.data.defaultVolume = value; + this.scheduleDefaultVolumePersist(); + } + if (fromSetter) return; + this.events["input:translationVolume"].dispatch(value); + }); + return this; + } + updateButtonLayout(position, direction) { + if (!this.isInitialized()) return this; + this.votMenu.position = position; + this.votButton.position = position; + this.votButton.direction = direction; + this.votButtonTooltip.hidden = direction === "row"; + this.votButtonTooltip.setPosition(this.votButton.tooltipPos); + return this; + } + moveButton(percentX) { + if (!this.isInitialized()) return this; + const isBigContainer = this.dragIsBigContainer ?? this.isBigContainer; + const position = VOTButton.calcPosition(percentX, isBigContainer); + if (position === this.votButton.position) return this; + const direction = VOTButton.calcDirection(position); + this.data.buttonPos = position; + this.updateButtonLayout(position, direction); + return this; + } + startDragSession(clientX, clientY, activitySource) { + this.dragCandidate = true; + this.dragging = false; + this.dragStartX = clientX; + this.dragStartY = clientY; + this.currentClientX = clientX; + this.containerRect = this.root.getBoundingClientRect(); + this.dragIsBigContainer = this.isBigContainer; + this.dragDirty = false; + this.intervalIdleChecker.markActivity(activitySource); + this.intervalIdleChecker.requestImmediateTick(); + } + queueDragTick(activitySource) { + if (this.dragDirty) return; + this.dragDirty = true; + this.intervalIdleChecker.markActivity(activitySource); + this.intervalIdleChecker.requestImmediateTick(); + } + updateDragFromMove(clientX, clientY, activitySource) { + this.currentClientX = clientX; + if (!this.dragCandidate) return; + if (!this.dragging) { + if (Math.abs(this.currentClientX - this.dragStartX) + Math.abs(clientY - this.dragStartY) >= this.dragThresholdPx) this.dragging = true; + } + if (!this.dragging) return; + this.queueDragTick(activitySource); + } + onDragStart = (event) => { + if (!event.isPrimary || event.button !== 0) return; + event.preventDefault(); + this.activePointerId = event.pointerId; + this.startDragSession(event.clientX, event.clientY, "overlay-pointer-down"); + }; + onPointerMove = (event) => { + if (this.activePointerId !== event.pointerId) return; + const wasDragging = this.dragging; + this.updateDragFromMove(event.clientX, event.clientY, "overlay-pointer-move"); + if (!wasDragging && this.dragging) try { + this.votButton?.container.setPointerCapture(event.pointerId); + } catch {} + if (this.dragging) event.preventDefault(); + }; + applyDragFromState = () => { + if (!this.dragging || !this.dragDirty || !this.containerRect) return; + const width = this.containerRect.width; + if (!(width > 0 && Number.isFinite(width))) return; + this.dragDirty = false; + const x = this.currentClientX - this.containerRect.left; + const percentX = Math.max(0, Math.min(x, width)) / width * 100; + this.moveButton(percentX); + }; + onCheckerTick = () => { + this.applyDragFromState(); + }; + onDragEnd = (event) => { + if (event && this.activePointerId !== null && event.pointerId !== this.activePointerId) return; + const pointerId = this.activePointerId; + if (pointerId !== null) try { + if (this.votButton?.container.hasPointerCapture(pointerId)) this.votButton.container.releasePointerCapture(pointerId); + } catch {} + this.applyDragFromState(); + const isBigContainer = this.dragIsBigContainer ?? this.isBigContainer; + if (this.dragging && isBigContainer && this.data.buttonPos) votStorage.set("buttonPos", this.data.buttonPos); + this.dragging = false; + this.dragCandidate = false; + this.dragDirty = false; + this.containerRect = null; + this.dragIsBigContainer = null; + this.activePointerId = null; + }; + updateButtonOpacity(opacity) { + if (!this.isInitialized() || !this.votMenu.hidden) return this; + if (Math.abs(this.votButton.opacity - opacity) > .01) this.votButton.opacity = opacity; + return this; + } + doReleaseUI() { + this.votButton?.remove(); + this.votMenu?.remove(); + this.votButtonTooltip?.release(); + destroyShadowMount(this.overlayMount); + this.overlayMount = void 0; + } + doReleaseUIEvents() { + this.abortController?.abort(); + this.abortController = null; + this.checkerUnsubscribe?.(); + this.checkerUnsubscribe = null; + this.onDragEnd(); + this.flushDefaultVolumePersist(); + for (const event of Object.values(this.events)) event.clear(); + } + release() { + if (!this.isInitialized()) return this; + this.doReleaseUIEvents(); + this.doReleaseUI(); + this.initialized = false; + return this; + } + get isBigContainer() { + const widthFromVideo = this.videoHandler?.video?.getBoundingClientRect?.().width; + if (typeof widthFromVideo === "number" && Number.isFinite(widthFromVideo)) return widthFromVideo > OverlayView.BIG_CONTAINER_WIDTH_PX; + const widthFromContainer = this.videoHandler?.container?.getBoundingClientRect?.().width; + if (typeof widthFromContainer === "number" && Number.isFinite(widthFromContainer)) return widthFromContainer > OverlayView.BIG_CONTAINER_WIDTH_PX; + return this.root.clientWidth > OverlayView.BIG_CONTAINER_WIDTH_PX; + } + get pipButtonVisible() { + return isPiPAvailable() && !!this.data.showPiPButton; + } + }; + function isSidePosition(position) { + return position === "left" || position === "right"; + } + //#endregion + //#region src/types/components/votButton.ts + var positions = [ + "default", + "top", + "left", + "right" + ]; + //#endregion //#region src/utils/environment.ts var UNKNOWN_VALUE = "unknown"; var joinParts = (...parts) => { @@ -20633,6 +29996,7 @@ var vot = (function(exports) { intervalIdleChecker; data; votGlobalPortal; + globalPortalMount; /** * Contains all elements over video player e.g. button, menu and etc */ @@ -20653,8 +30017,8 @@ var vot = (function(exports) { get portalContainer() { return this.mount.portalContainer; } - get tooltipLayoutRoot() { - return this.mount.tooltipLayoutRoot; + getSubtitlesMountContainer() { + return this.votOverlayView?.root ?? this.mount.subtitlesMountContainer; } isInitialized() { return this.initialized; @@ -20662,8 +30026,11 @@ var vot = (function(exports) { initUI() { if (this.isInitialized()) throw new Error("[VOT] UIManager is already initialized"); this.initialized = true; - this.votGlobalPortal = UI.createPortal(); - this.getGlobalPortalHost(this.mount).appendChild(this.votGlobalPortal); + this.globalPortalMount = createShadowMount({ + parent: this.getGlobalPortalHost(this.mount), + rootClasses: ["vot-portal"] + }); + this.votGlobalPortal = this.globalPortalMount.root; this.votOverlayView = new OverlayView({ mount: this.mount, globalPortal: this.votGlobalPortal, @@ -20678,24 +30045,21 @@ var vot = (function(exports) { videoHandler: this.videoHandler }); this.votSettingsView.initUI(); + this.videoHandler?.subtitlesWidget?.updateMount({ container: this.getSubtitlesMountContainer() }); return this; } updateMount(mount) { - const globalPortalHost = this.getGlobalPortalHost(mount); - if (this.votGlobalPortal?.parentElement !== globalPortalHost) globalPortalHost.appendChild(this.votGlobalPortal); + reparentShadowMount(this.globalPortalMount, this.getGlobalPortalHost(mount)); this.mount = applyOverlayMountUpdate(this.mount, mount, (nextMount) => { this.votOverlayView?.updateMount(nextMount); }); - this.videoHandler?.subtitlesWidget?.updateMount({ - container: mount.subtitlesMountContainer, - tooltipLayoutRoot: mount.tooltipLayoutRoot - }); + this.videoHandler?.subtitlesWidget?.updateMount({ container: this.getSubtitlesMountContainer() }); return this; } getGlobalPortalHost(mount) { const doc = document; const fullscreenEl = doc.fullscreenElement ?? doc.webkitFullscreenElement; - return Boolean(resolveScopedFullscreenElement(fullscreenEl, [mount.root], { allowDocumentViewport: true })) ? mount.root : document.documentElement; + return fullscreenEl instanceof HTMLElement && (fullscreenEl === mount.root || fullscreenEl.contains(mount.root) || mount.root.contains(fullscreenEl)) ? mount.root : document.documentElement; } initUIEvents() { if (!this.isInitialized()) throw new Error("[VOT] UIManager isn't initialized"); @@ -20712,7 +30076,8 @@ var vot = (function(exports) { }).addEventListener("click:pip", async () => { if (!this.videoHandler) return; try { - await (this.videoHandler.video === document.pictureInPictureElement ? document.exitPictureInPicture() : this.videoHandler.video.requestPictureInPicture()); + if (document.pictureInPictureElement != null) await document.exitPictureInPicture(); + else await this.videoHandler.video.requestPictureInPicture(); } catch (err) { debug.warn("[VOT] Failed to toggle Picture-in-Picture", err); } @@ -20956,7 +30321,9 @@ var vot = (function(exports) { if (!this.isInitialized()) return this; this.votOverlayView.release(); this.votSettingsView.release(); - this.votGlobalPortal.remove(); + destroyShadowMount(this.globalPortalMount); + this.globalPortalMount = void 0; + this.votGlobalPortal = void 0; this.initialized = false; return this; } @@ -21106,7 +30473,7 @@ var vot = (function(exports) { if (!relatedTarget && typeof event?.composedPath === "function") relatedTarget = event.composedPath()[1] ?? null; const relatedNode = relatedTarget instanceof Node ? relatedTarget : null; const currentNode = currentTarget instanceof Node ? currentTarget : null; - if (relatedNode && (currentNode?.contains(relatedNode) || this.deps.isInteractiveNode(relatedNode))) return; + if (relatedNode && (currentNode && containsCrossShadow(currentNode, relatedNode) || this.deps.isInteractiveNode(relatedNode))) return; this.queueAutoHide(); } onCheckerTick() { @@ -21114,7 +30481,7 @@ var vot = (function(exports) { if (this.nowMs() + 2 < this.hideDeadlineMs) return; this.hideArmed = false; let active = null; - if (typeof document !== "undefined" && typeof document.hasFocus === "function" && document.hasFocus()) active = document.activeElement; + if (typeof document !== "undefined" && typeof document.hasFocus === "function" && document.hasFocus()) active = getDeepActiveElement(document); if (active && this.deps.isInteractiveNode(active)) { debug.log("[OverlayVisibility] skip hide (focus inside overlay)"); return; @@ -23154,7 +32521,7 @@ var vot = (function(exports) { const keyboardEvent = event; if (keyboardEvent.repeat) return; userPressedKeys.add(keyboardEvent.code); - const activeElement = document.activeElement; + const activeElement = getDeepActiveElement(document); const activeTag = activeElement?.tagName?.toLowerCase?.() ?? ""; if (["input", "textarea"].includes(activeTag) || Boolean(activeElement?.isContentEditable)) return; const pressedParts = buildPressedHotkeyPartsSet(userPressedKeys); @@ -23294,7 +32661,7 @@ var vot = (function(exports) { const overlayView = this.uiManager?.votOverlayView; const buttonContainer = overlayView?.votButton?.container; const menuContainer = overlayView?.votMenu?.container; - return buttonContainer instanceof Node && buttonContainer.contains(node) || menuContainer instanceof Node && menuContainer.contains(node); + return buttonContainer instanceof Node && containsCrossShadow(buttonContainer, node) || menuContainer instanceof Node && containsCrossShadow(menuContainer, node); } function getAutoHideDelay() { const delay = this.data?.autoHideButtonDelay; @@ -24416,7 +33783,8 @@ var vot = (function(exports) { */ getFullscreenOverlayRoot() { const doc = document; - return resolveScopedFullscreenElement(doc.fullscreenElement ?? doc.webkitFullscreenElement, [this.container]); + const fullscreenEl = doc.fullscreenElement ?? doc.webkitFullscreenElement; + return fullscreenEl instanceof HTMLElement && (fullscreenEl === this.container || fullscreenEl.contains(this.container) || this.container.contains(fullscreenEl)) ? fullscreenEl : null; } getOverlayMountPoints(container = this.container) { const fullscreenRoot = this.getFullscreenOverlayRoot(); @@ -24448,12 +33816,11 @@ var vot = (function(exports) { }; } getOverlayMount(container = this.container) { - const { root, portalContainer, subtitlesMountContainer, fullscreenRoot } = this.getOverlayMountPoints(container); + const { root, portalContainer, subtitlesMountContainer } = this.getOverlayMountPoints(container); return { root, portalContainer, - subtitlesMountContainer, - tooltipLayoutRoot: fullscreenRoot ?? this.tooltipLayoutRoot + subtitlesMountContainer }; } /** @@ -24568,7 +33935,7 @@ var vot = (function(exports) { getSubtitlesWidget() { if (!this.subtitlesWidget) { const { subtitlesMountContainer } = this.getOverlayMountPoints(); - this.subtitlesWidget = new SubtitlesWidget(this.video, subtitlesMountContainer, this.interactionChecker, this.tooltipLayoutRoot); + this.subtitlesWidget = new SubtitlesWidget(this.video, this.uiManager.votOverlayView?.root ?? subtitlesMountContainer, this.interactionChecker); this.applySavedSubtitlesWidgetSettings(this.subtitlesWidget); } return this.subtitlesWidget; @@ -24610,17 +33977,6 @@ var vot = (function(exports) { return this.getOverlayMountPoints().portalContainer; } /** - * Determines the root element used for tooltip layout calculations. - * @returns {HTMLElement | undefined} - */ - get tooltipLayoutRoot() { - switch (this.site.host) { - case "kickstarter": return document.getElementById("react-project-header") ?? void 0; - case "custom": return; - default: return this.container; - } - } - /** * Returns the container element for event listeners. * @returns {HTMLElement} The event container. */ diff --git a/package.json b/package.json index bd7834d6..86b566bf 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,13 @@ "@toil/translate": "^1.0.8", "@types/bun": "^1.3.11", "@vot.js/core": "^2.4.12", - "sass": "^1.98.0", "crx3": "^2.0.0", - "lefthook": "^2.1.4", + "lefthook": "^2.1.5", "lightningcss": "^1.32.0", "npm-run-all2": "^8.0.4", + "sass": "^1.99.0", "typescript": "^5.9.3", - "vite": "^8.0.1", + "vite": "^8.0.5", "zip-a-folder": "^6.1.0" }, "scripts": { @@ -50,6 +50,7 @@ "@vot.js/shared": "^2.4.12", "bowser": "^2.14.1", "chaimu": "^1.0.6", + "lit": "^3.3.2", "lit-html": "^3.3.2" } } diff --git a/scripts/wiki-gen/SITES-EN.md b/scripts/wiki-gen/SITES-EN.md index ddd72694..3093f3ec 100644 --- a/scripts/wiki-gen/SITES-EN.md +++ b/scripts/wiki-gen/SITES-EN.md @@ -73,6 +73,14 @@ Limitations: - Doesn't work in the video preview - To ensure that the script works, you need to [enable the "Bypass Media CSP" setting](https://github.com/ilyhalight/voice-over-translation/wiki/%5BEN%5D-FAQ) in the extension or delete the CSP in another way +## Preservetube + +Status: [✅] Working + +Available (sub)domains: + +- `preservetube.com` + ## Zdf Status: [✅] Working @@ -510,6 +518,7 @@ Available (sub)domains: - `dailymotion.com` - `www.dailymotion.com` +- `player.dailymotion.com` - `geo*.dailymotion.com` (embedded player, on www.dailymotion.com it works) - `dai.ly` @@ -694,9 +703,7 @@ Status: [✅] Working Available (sub)domains: -- `kodik.info` -- `kodik.biz` -- `kodik.cc` +- `kodikplayer.com` ## Patreon @@ -829,6 +836,16 @@ Limitations: - You must be logged in to the site +## Datacamp + +Status: [✅] Working + +Available (sub)domains: + +- `datacamp.com` +- `campus.datacamp.com` +- `projector.datacamp.com` + ## Coursera Status: [✅] Working @@ -859,6 +876,15 @@ Available paths: - /video/VIDEO_ID/VIDEO_NAME - /embed/VIDEO_ID +## Jove + +Status: [✅] Working + +Available (sub)domains: + +- `app.jove.com` +- `www.jove.com` + ## Linkedin Status: [✅] Working @@ -905,6 +931,16 @@ Available paths: - /video/watch/VIDEO_ID +## Bunnystream + +Status: [✅] Working + +Available (sub)domains: + +- `video.bunnycdn.com` +- `iframe.mediadelivery.net` +- `*b-cdn.net` + ## Cloudflarestream Status: [✅] Working @@ -1108,6 +1144,15 @@ Available paths: - /content/i2cs/* +## Mediafile + +Status: [✅] Working + +Available (sub)domains: + +- `mediafile.cc` +- `www.mediafile.cc` + ## Direct link to MP4/WEBM Status: [✅] Working diff --git a/scripts/wiki-gen/SITES-RU.md b/scripts/wiki-gen/SITES-RU.md index 5872652f..b86cd5f2 100644 --- a/scripts/wiki-gen/SITES-RU.md +++ b/scripts/wiki-gen/SITES-RU.md @@ -73,6 +73,14 @@ - Не работает в предпросмотре видео - Для гарантированной работы скрипта необходимо [включить настройку "Обход Media CSP"](https://github.com/ilyhalight/voice-over-translation/wiki/%5BRU%5D-FAQ) в расширение или удалить CSP другим способом +## Preservetube + +Статус: [✅] Работает + +Доступные (под)домены: + +- `preservetube.com` + ## Zdf Статус: [✅] Работает @@ -510,6 +518,7 @@ - `dailymotion.com` - `www.dailymotion.com` +- `player.dailymotion.com` - `geo*.dailymotion.com` (встраиваемый плеер, на www.dailymotion.com работает) - `dai.ly` @@ -694,9 +703,7 @@ Доступные (под)домены: -- `kodik.info` -- `kodik.biz` -- `kodik.cc` +- `kodikplayer.com` ## Patreon @@ -829,6 +836,16 @@ - Необходимо быть авторизованным на сайте +## Datacamp + +Статус: [✅] Работает + +Доступные (под)домены: + +- `datacamp.com` +- `campus.datacamp.com` +- `projector.datacamp.com` + ## Coursera Статус: [✅] Работает @@ -859,6 +876,15 @@ - /video/VIDEO_ID/VIDEO_NAME - /embed/VIDEO_ID +## Jove + +Статус: [✅] Работает + +Доступные (под)домены: + +- `app.jove.com` +- `www.jove.com` + ## Linkedin Статус: [✅] Работает @@ -905,6 +931,16 @@ - /video/watch/VIDEO_ID +## Bunnystream + +Статус: [✅] Работает + +Доступные (под)домены: + +- `video.bunnycdn.com` +- `iframe.mediadelivery.net` +- `*b-cdn.net` + ## Cloudflarestream Статус: [✅] Работает @@ -1108,6 +1144,15 @@ - /content/i2cs/* +## Mediafile + +Статус: [✅] Работает + +Доступные (под)домены: + +- `mediafile.cc` +- `www.mediafile.cc` + ## Direct link to MP4/WEBM Статус: [✅] Работает diff --git a/scripts/wiki-gen/index.js b/scripts/wiki-gen/index.js index 7ad385e9..f779cb70 100644 --- a/scripts/wiki-gen/index.js +++ b/scripts/wiki-gen/index.js @@ -635,7 +635,7 @@ function getSupportedSites() { async function main() { const supportedSites = getSupportedSites(); const langs = ["ru", "en"]; - for await (const lang of langs) { + for (const lang of langs) { const mdText = `${genMarkdown(supportedSites, lang).join("\n\n")}\n`; await Bun.write( diff --git a/src/audioDownloader/ytAudio/README.md b/src/audioDownloader/ytAudio/README.md index 46aed3bf..22cf5640 100644 --- a/src/audioDownloader/ytAudio/README.md +++ b/src/audioDownloader/ytAudio/README.md @@ -16,8 +16,8 @@ Use `AudioDownloader.downloadAudioToUint8Array(...)`: const downloader = new AudioDownloader({ fetchImplementation }); const result = await downloader.downloadAudioToUint8Array({ videoId: "memM8flkwrA", - client: "ANDROID", - videoQuality: "bestefficiency", + client: "ANDROID_VR", + audioQuality: "bestefficiency", signal, }); @@ -27,6 +27,6 @@ const result = await downloader.downloadAudioToUint8Array({ The module is intended to run in browser context and returns audio bytes for further chunking/upload by the parent audio downloader strategy. -Supported `videoQuality` values: +Supported `audioQuality` values: - `best` - `bestefficiency` diff --git a/src/audioDownloader/ytAudio/index.ts b/src/audioDownloader/ytAudio/index.ts index f21b6cd1..a93d744e 100644 --- a/src/audioDownloader/ytAudio/index.ts +++ b/src/audioDownloader/ytAudio/index.ts @@ -10,5 +10,4 @@ export { AudioDownloader, buildClientAttemptOrder, extractVideoId, - YtWatchContextForbiddenError, } from "./src/AudioDownloader"; diff --git a/src/audioDownloader/ytAudio/src/AudioDownloader.ts b/src/audioDownloader/ytAudio/src/AudioDownloader.ts index e9144516..46e44a39 100644 --- a/src/audioDownloader/ytAudio/src/AudioDownloader.ts +++ b/src/audioDownloader/ytAudio/src/AudioDownloader.ts @@ -6,27 +6,13 @@ import { } from "./internal/format-selection"; export type AudioDownloadQuality = ProgressiveQuality; -export type AudioDownloadClient = - | "IOS" - | "WEB" - | "MWEB" - | "ANDROID" - | "ANDROID_VR" - | "YTMUSIC" - | "YTMUSIC_ANDROID" - | "YTSTUDIO_ANDROID" - | "TV" - | "TV_SIMPLY" - | "TV_EMBEDDED" - | "YTKIDS" - | "WEB_EMBEDDED" - | "WEB_CREATOR"; +export type AudioDownloadClient = "ANDROID_VR"; export interface AudioStreamRequest { videoId?: string; videoUrl?: string; client?: AudioDownloadClient; - videoQuality?: AudioDownloadQuality; + audioQuality?: AudioDownloadQuality; signal?: AbortSignal; } @@ -59,16 +45,6 @@ export interface AudioDownloaderOptions { fetchImplementation?: typeof fetch; } -export class YtWatchContextForbiddenError extends Error { - readonly status: number; - - constructor(status = 403) { - super(`Failed to load watch page: ${status}`); - this.name = "YtWatchContextForbiddenError"; - this.status = status; - } -} - interface WatchContext { apiKey: string; clientVersion: string; @@ -108,16 +84,8 @@ interface ResolvedPlayableFormat { const VIDEO_ID_PATTERN = /^[a-zA-Z0-9_-]{11}$/; const YT_BASE = "https://www.youtube.com"; -const ANDROID_CLIENT_VERSION = "19.44.38"; const ANDROID_VR_CLIENT_VERSION = "1.60.19"; -const IOS_CLIENT_VERSION = "19.45.4"; -const CLIENT_FALLBACK_ORDER: readonly AudioDownloadClient[] = [ - "ANDROID_VR", - "ANDROID", - "IOS", - "WEB", - "MWEB", -]; +const CLIENTS: readonly AudioDownloadClient[] = ["ANDROID_VR"]; const DEFAULT_HEADERS = { accept: "*/*", origin: YT_BASE, @@ -131,64 +99,21 @@ function withSignal(signal: AbortSignal | undefined): RequestInit { function resolveInnertubeClient( requestedClient: AudioDownloadClient | undefined, - watchContext: WatchContext, - videoId: string, ): Record { - switch (requestedClient) { - case "ANDROID": - case "YTMUSIC_ANDROID": - case "YTSTUDIO_ANDROID": - return { - clientName: "ANDROID", - clientVersion: ANDROID_CLIENT_VERSION, - hl: "en", - gl: "US", - androidSdkVersion: 34, - osName: "Android", - osVersion: "14", - platform: "MOBILE", - }; - case "ANDROID_VR": - return { - clientName: "ANDROID_VR", - clientVersion: ANDROID_VR_CLIENT_VERSION, - hl: "en", - gl: "US", - androidSdkVersion: 31, - osName: "Android", - osVersion: "12", - platform: "MOBILE", - }; - case "IOS": - return { - clientName: "IOS", - clientVersion: IOS_CLIENT_VERSION, - hl: "en", - gl: "US", - platform: "MOBILE", - osName: "iPhone", - osVersion: "18.0.0.22A3354", - deviceMake: "Apple", - deviceModel: "iPhone16,2", - }; - case "MWEB": - return { - clientName: "MWEB", - clientVersion: watchContext.clientVersion, - hl: "en", - gl: "US", - originalUrl: `${YT_BASE}/watch?v=${videoId}`, - }; - default: - return { - clientName: "WEB", - clientVersion: watchContext.clientVersion, - hl: "en", - gl: "US", - utcOffsetMinutes: 0, - originalUrl: `${YT_BASE}/watch?v=${videoId}`, - }; + if (requestedClient !== undefined && requestedClient !== "ANDROID_VR") { + throw new Error(`Unsupported Innertube client: ${requestedClient}`); } + + return { + clientName: "ANDROID_VR", + clientVersion: ANDROID_VR_CLIENT_VERSION, + hl: "en", + gl: "US", + androidSdkVersion: 31, + osName: "Android", + osVersion: "12", + platform: "MOBILE", + }; } export function extractVideoId(input: string): string { @@ -416,8 +341,8 @@ export function buildClientAttemptOrder( requestedClient: AudioDownloadClient | undefined, ): AudioDownloadClient[] { const ordered = requestedClient - ? [requestedClient, ...CLIENT_FALLBACK_ORDER] - : [...CLIENT_FALLBACK_ORDER]; + ? [requestedClient, ...CLIENTS] + : [...CLIENTS]; const seen = new Set(); return ordered.filter((client) => { @@ -507,7 +432,7 @@ export class AudioDownloader { return this.withResolvedPlayableAudioFormat( request, - request.videoQuality ?? "best", + request.audioQuality ?? "best", "Chunk mode requires an adaptive audio stream format", "Unable to resolve streamable format for chunk mode", async ({ resolved, signal }) => { @@ -577,7 +502,7 @@ export class AudioDownloader { ): Promise { return this.withResolvedPlayableAudioFormat( request, - request.videoQuality ?? "bestefficiency", + request.audioQuality ?? "bestefficiency", "Selected stream is not audio-only", "Unable to download playable stream format", async ({ resolved, signal }) => { @@ -673,10 +598,7 @@ export class AudioDownloader { quality, ); - const streamUrl = this.resolveFormatUrl( - chosenFormat, - watchContext.clientVersion, - ); + const streamUrl = this.resolveFormatUrl(chosenFormat); return { videoId, @@ -766,20 +688,12 @@ export class AudioDownloader { }; } - private resolveFormatUrl( - format: InnertubeFormat, - clientVersion: string, - ): string { + private resolveFormatUrl(format: InnertubeFormat): string { if (!format.url) { throw new Error("Selected format does not contain a direct stream URL"); } const streamUrl = new URL(format.url); - const client = streamUrl.searchParams.get("c"); - if (client === "WEB") { - streamUrl.searchParams.set("cver", clientVersion); - } - streamUrl.searchParams.set("cpn", makeCPN()); return streamUrl.toString(); } @@ -794,9 +708,6 @@ export class AudioDownloader { ...withSignal(signal), }); if (!response.ok) { - if (response.status === 403) { - throw new YtWatchContextForbiddenError(response.status); - } throw new Error(`Failed to load watch page: ${response.status}`); } @@ -847,11 +758,7 @@ export class AudioDownloader { requestedClient: AudioDownloadClient | undefined, signal?: AbortSignal, ): Promise { - const client = resolveInnertubeClient( - requestedClient, - watchContext, - videoId, - ); + const client = resolveInnertubeClient(requestedClient); if (watchContext.visitorData) { client.visitorData = watchContext.visitorData; } diff --git a/src/audioDownloader/ytAudio/strategy.ts b/src/audioDownloader/ytAudio/strategy.ts index e2dd450e..458e455f 100644 --- a/src/audioDownloader/ytAudio/strategy.ts +++ b/src/audioDownloader/ytAudio/strategy.ts @@ -8,7 +8,6 @@ import { type AudioChunkStreamResult, type AudioStreamRequest, AudioDownloader as YtAudioDownloader, - YtWatchContextForbiddenError, } from "./index"; const DEFAULT_YT_AUDIO_QUALITY = "bestefficiency"; @@ -54,17 +53,6 @@ function createYtAudioFetch({ }); } -function isWatchContextForbiddenError(error: unknown): boolean { - if (error instanceof YtWatchContextForbiddenError) { - return true; - } - - return ( - error instanceof Error && - /failed to load watch page:\s*403/i.test(error.message) - ); -} - export async function getAudioFromYtAudio( { videoId, signal }: GetAudioFromAPIOptions, deps: YtAudioStrategyDeps = {}, @@ -84,7 +72,7 @@ export async function getAudioFromYtAudio( const streamResult = await downloader.downloadAudioToChunkStream( { videoId, - videoQuality: DEFAULT_YT_AUDIO_QUALITY, + audioQuality: DEFAULT_YT_AUDIO_QUALITY, signal, }, { chunkSize }, @@ -101,13 +89,6 @@ export async function getAudioFromYtAudio( getMediaBuffers: streamResult.getMediaBuffers, }; } catch (error) { - if (isWatchContextForbiddenError(error)) { - // 403 on watch-page key fetch is not recoverable in current context. - // Skip buffered fallback so upper layer can immediately trigger - // fail-audio-js instead of spending time on redundant retries. - throw error; - } - console.warn( "[VOT] ytAudio streaming mode failed, falling back to buffered mode", error, @@ -116,7 +97,7 @@ export async function getAudioFromYtAudio( const result = await downloader.downloadAudioToUint8Array({ videoId, - videoQuality: DEFAULT_YT_AUDIO_QUALITY, + audioQuality: DEFAULT_YT_AUDIO_QUALITY, signal, }); diff --git a/src/extension/prelude.ts b/src/extension/prelude.ts index 89634461..2ce7ebfd 100644 --- a/src/extension/prelude.ts +++ b/src/extension/prelude.ts @@ -477,8 +477,29 @@ function handlePromiseResponse(data: AnyObject): boolean { pending.delete(id); clearTimeout(item.timeoutId); +<<<<<<< Updated upstream if (data.ok) item.resolve(data.result); else item.reject(new Error(toErrorMessage(data.error ?? "Bridge error"))); +======= + if (data.ok) { + debug.log("[VOT EXT][prelude] GM API response", { + requestId: id, + action: item.action, + ok: true, + resultType: Array.isArray(data.result) ? "array" : typeof data.result, + }); + item.resolve(data.result); + } else { + const errorMessage = toErrorMessage(data.error ?? "Bridge error"); + debug.warn("[VOT EXT][prelude] GM API response", { + requestId: id, + action: item.action, + ok: false, + error: errorMessage, + }); + item.reject(new Error(errorMessage)); + } +>>>>>>> Stashed changes return true; } diff --git a/src/headers.json b/src/headers.json index fc9a61c3..ca33c7df 100644 --- a/src/headers.json +++ b/src/headers.json @@ -1,7 +1,11 @@ { "name": "[VOT] - Voice Over Translation", "description": "A small extension that adds a Yandex Browser video translation to other browsers", +<<<<<<< Updated upstream "version": "1.11.4", +======= + "version": "1.11.5", +>>>>>>> Stashed changes "author": "Toil, SashaXser, MrSoczekXD, mynovelhost, sodapng", "namespace": "vot", "icon": "https://translate.yandex.ru/icons/favicon.ico", @@ -74,9 +78,7 @@ "*://*.archive.org/*", "*://*.patreon.com/*", "*://*.reddit.com/*", - "*://*.kodik.info/*", - "*://*.kodik.biz/*", - "*://*.kodik.cc/*", + "*://*.kodikplayer.com/*", "*://*.kick.com/*", "*://developer.apple.com/*", "*://dev.epicgames.com/*", diff --git a/src/index.ts b/src/index.ts index caf64e2f..8dd26792 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,7 +35,6 @@ import { UIManager } from "./ui/manager"; import { isSameOverlayMount } from "./ui/mount"; import { OverlayVisibilityController } from "./ui/overlayVisibilityController"; import debug from "./utils/debug"; -import { resolveScopedFullscreenElement } from "./utils/dom"; import { getEnvironmentInfo as getEnvironmentInfoImpl } from "./utils/environment"; import { GM_fetch, isSupportGMXhr } from "./utils/gm"; import { isIframe } from "./utils/iframeConnector"; @@ -83,6 +82,10 @@ import { enableSubtitlesForCurrentLangPair as enableSubtitlesForCurrentLangPairImpl, ensureSubtitlesForCurrentLangPair as ensureSubtitlesForCurrentLangPairImpl, loadSubtitles as loadSubtitlesImpl, +<<<<<<< Updated upstream +======= + refreshAutoSubtitlesForCurrentLangPair as refreshAutoSubtitlesForCurrentLangPairImpl, +>>>>>>> Stashed changes resolveSubtitlesLanguage, toggleSubtitlesForCurrentLangPair as toggleSubtitlesForCurrentLangPairImpl, updateSubtitlesLangSelect as updateSubtitlesLangSelectImpl, @@ -275,7 +278,12 @@ export class VideoHandler { private getFullscreenOverlayRoot(): HTMLElement | null { const doc = document as DocumentWithFullscreen; const fullscreenEl = doc.fullscreenElement ?? doc.webkitFullscreenElement; - return resolveScopedFullscreenElement(fullscreenEl, [this.container]); + return fullscreenEl instanceof HTMLElement && + (fullscreenEl === this.container || + fullscreenEl.contains(this.container) || + this.container.contains(fullscreenEl)) + ? fullscreenEl + : null; } private getOverlayMountPoints(container: HTMLElement = this.container): { @@ -322,13 +330,12 @@ export class VideoHandler { private getOverlayMount( container: HTMLElement = this.container, ): OverlayMount { - const { root, portalContainer, subtitlesMountContainer, fullscreenRoot } = + const { root, portalContainer, subtitlesMountContainer } = this.getOverlayMountPoints(container); return { root, portalContainer, subtitlesMountContainer, - tooltipLayoutRoot: fullscreenRoot ?? this.tooltipLayoutRoot, }; } @@ -520,9 +527,8 @@ export class VideoHandler { const { subtitlesMountContainer } = this.getOverlayMountPoints(); this.subtitlesWidget = new SubtitlesWidget( this.video, - subtitlesMountContainer, + this.uiManager.votOverlayView?.root ?? subtitlesMountContainer, this.interactionChecker, - this.tooltipLayoutRoot, ); this.applySavedSubtitlesWidgetSettings(this.subtitlesWidget); } @@ -590,24 +596,6 @@ export class VideoHandler { return this.getOverlayMountPoints().portalContainer; } - /** - * Determines the root element used for tooltip layout calculations. - * @returns {HTMLElement | undefined} - */ - get tooltipLayoutRoot() { - switch (this.site.host) { - case "kickstarter": { - return document.getElementById("react-project-header") ?? undefined; - } - case "custom": { - return undefined; - } - default: { - return this.container; - } - } - } - /** * Returns the container element for event listeners. * @returns {HTMLElement} The event container. @@ -897,6 +885,17 @@ export class VideoHandler { } /** +<<<<<<< Updated upstream +======= + * Re-evaluates the active subtitles track for the current language pair, + * but only when auto-subtitles are enabled. + */ + refreshAutoSubtitlesForCurrentLangPair() { + return this.callModuleAsync(refreshAutoSubtitlesForCurrentLangPairImpl); + } + + /** +>>>>>>> Stashed changes * Toggles subtitles for the current video. * * - If subtitles are enabled, this disables them. diff --git a/src/styles/main.scss b/src/styles/main.scss index 74c3185d..e3537d48 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -176,3 +176,15 @@ html.vot-keyboard-nav vot-block *:focus-visible { z-index: 2147483647; } } + +// The overlay mount itself stays click-through so host-page controls remain +// usable around the injected UI. Explicitly re-enable hit-testing for the +// actual interactive overlay surfaces inside the shadow root. +.vot-overlay-root { + pointer-events: none; + + & > .vot-segmented-button, + & > .vot-menu { + pointer-events: auto; + } +} diff --git a/src/subtitles/fullscreenLayerController.ts b/src/subtitles/fullscreenLayerController.ts index 91ba1423..d1fae477 100644 --- a/src/subtitles/fullscreenLayerController.ts +++ b/src/subtitles/fullscreenLayerController.ts @@ -1,21 +1,11 @@ -import { resolveScopedFullscreenElement } from "../utils/dom"; - -type DocumentWithFullscreenElement = Document & { - webkitFullscreenElement?: Element | null; -}; - type FullscreenLayerControllerOptions = { - video?: HTMLVideoElement; container: HTMLElement; }; export class FullscreenLayerController { - private readonly video?: HTMLVideoElement; private container: HTMLElement; - private fullscreenLayer: HTMLElement | null = null; - constructor({ video, container }: FullscreenLayerControllerOptions) { - this.video = video; + constructor({ container }: FullscreenLayerControllerOptions) { this.container = container; } @@ -24,93 +14,21 @@ export class FullscreenLayerController { } getWidgetParentElement(): HTMLElement { - return this.shouldUseFullscreenViewportLayer() - ? this.ensureFullscreenLayer() - : this.container; + return this.container; } getLayoutRootElement(): HTMLElement { - return this.fullscreenLayer?.isConnected - ? this.fullscreenLayer - : this.container; + return this.container; } syncWidgetContainer(widgetContainer: HTMLElement | null): void { - const widgetParent = this.getWidgetParentElement(); - - if ( - widgetParent === this.container && - getComputedStyle(this.container).position === "static" - ) { + if (getComputedStyle(this.container).position === "static") { this.container.style.position = "relative"; } - if (widgetContainer && widgetContainer.parentElement !== widgetParent) { - widgetParent.appendChild(widgetContainer); - } - - if ( - widgetParent === this.container && - this.fullscreenLayer?.parentElement - ) { - this.fullscreenLayer.remove(); - this.fullscreenLayer = null; + if (widgetContainer && widgetContainer.parentElement !== this.container) { + this.container.appendChild(widgetContainer); } } - - release(): void { - if (!this.fullscreenLayer) return; - this.fullscreenLayer.remove(); - this.fullscreenLayer = null; - } - - private getActiveFullscreenElement(): HTMLElement | null { - const doc = document as DocumentWithFullscreenElement; - const fullscreenEl = doc.fullscreenElement ?? doc.webkitFullscreenElement; - return resolveScopedFullscreenElement( - fullscreenEl, - [this.container, this.video], - { - allowDocumentViewport: true, - }, - ); - } - - private isCurrentVideoInFullscreenSession(): boolean { - const fullscreenEl = this.getActiveFullscreenElement(); - if (!fullscreenEl) return false; - - if ( - fullscreenEl === this.container || - fullscreenEl.contains(this.container) || - this.container.contains(fullscreenEl) - ) { - return true; - } - - return Boolean( - this.video && - (fullscreenEl === this.video || - fullscreenEl.contains(this.video) || - this.video.contains(fullscreenEl)), - ); - } - - private shouldUseFullscreenViewportLayer(): boolean { - return this.isCurrentVideoInFullscreenSession(); - } - - private ensureFullscreenLayer(): HTMLElement { - if (!this.fullscreenLayer) { - const layer = document.createElement("vot-block"); - layer.classList.add("vot-subtitles-layer"); - this.fullscreenLayer = layer; - } - - if (this.fullscreenLayer.parentElement !== this.container) { - this.container.appendChild(this.fullscreenLayer); - } - - return this.fullscreenLayer; - } + release(): void {} } diff --git a/src/subtitles/widget.ts b/src/subtitles/widget.ts index 7787ba36..eeabdc3a 100644 --- a/src/subtitles/widget.ts +++ b/src/subtitles/widget.ts @@ -11,6 +11,12 @@ import type { } from "../types/subtitles"; import UI from "../ui"; import Tooltip from "../ui/components/tooltip"; +import { + createShadowMount, + destroyShadowMount, + reparentShadowMount, + type ShadowMount, +} from "../ui/shadowMount"; import type { IntervalIdleChecker } from "../utils/intervalIdleChecker"; import { votStorage } from "../utils/storage"; import { translate } from "../utils/translateApis"; @@ -102,7 +108,7 @@ export class SubtitlesWidget { private readonly video?: HTMLVideoElement; private container: HTMLElement; private readonly fullscreenLayerController: FullscreenLayerController; - private tooltipLayoutRoot?: HTMLElement; + private tooltipMount?: ShadowMount; private subtitlesContainer: HTMLElement | null = null; private subtitlesBlock: HTMLElement | null = null; private renderedHighlightEls: HTMLSpanElement[] = []; @@ -218,16 +224,13 @@ export class SubtitlesWidget { video: HTMLVideoElement | undefined, container: HTMLElement, intervalIdleChecker: IntervalIdleChecker, - tooltipLayoutRoot: HTMLElement | undefined = undefined, ) { this.video = video; this.container = container; this.fullscreenLayerController = new FullscreenLayerController({ - video, container, }); this.intervalIdleChecker = intervalIdleChecker; - this.tooltipLayoutRoot = tooltipLayoutRoot; this.useVideoFrameCallbacks = !!this.video && typeof this.video.requestVideoFrameCallback === "function"; @@ -241,26 +244,19 @@ export class SubtitlesWidget { }); this.bindEvents(); } - public updateMount({ - container, - tooltipLayoutRoot, - }: { - container: HTMLElement; - tooltipLayoutRoot?: HTMLElement; - }): void { + public updateMount({ container }: { container: HTMLElement }): void { const containerChanged = this.container !== container; - const tooltipRootChanged = this.tooltipLayoutRoot !== tooltipLayoutRoot; this.container = container; this.fullscreenLayerController.updateContainer(container); - this.tooltipLayoutRoot = tooltipLayoutRoot; this.syncWidgetMount(); - if (containerChanged || tooltipRootChanged) { + if (containerChanged) { + const parentElement = this.getTokenTooltipParentElement(); this.tokenTooltip?.updateMount({ - parentElement: this.getTokenTooltipParentElement(), - layoutRoot: this.tooltipLayoutRoot ?? document.documentElement, + parentElement, + layoutRoot: this.tooltipMount?.host, }); } @@ -491,23 +487,51 @@ export class SubtitlesWidget { } } private syncGuideLayerMount(): void { - const widgetParent = - this.fullscreenLayerController.getWidgetParentElement(); const guidesLayer = this.ensureGuidesLayer(); - if (guidesLayer.parentElement !== widgetParent) { - widgetParent.appendChild(guidesLayer); + if (guidesLayer.parentElement !== this.container) { + this.container.appendChild(guidesLayer); } } private syncWidgetMount(): void { - this.fullscreenLayerController.syncWidgetContainer(this.subtitlesContainer); + this.fullscreenLayerController.syncWidgetContainer(null); + if ( + this.subtitlesContainer && + this.subtitlesContainer.parentElement !== this.container + ) { + this.container.appendChild(this.subtitlesContainer); + } + if (this.tooltipMount) { + reparentShadowMount(this.tooltipMount, this.container); + } this.syncGuideLayerMount(); } + private ensureTooltipMount(): ShadowMount { + if (!this.tooltipMount) { + this.tooltipMount = createShadowMount({ + parent: this.container, + rootClasses: ["vot-portal-local"], + hostStyles: { + position: "absolute", + inset: "0", + display: "block", + "pointer-events": "none", + }, + rootStyles: { + position: "relative", + display: "block", + width: "100%", + height: "100%", + "pointer-events": "none", + }, + }); + } else { + reparentShadowMount(this.tooltipMount, this.container); + } + + return this.tooltipMount; + } private getTokenTooltipParentElement(): HTMLElement { - const widgetParent = - this.fullscreenLayerController.getWidgetParentElement(); - return widgetParent === this.container - ? document.documentElement - : widgetParent; + return this.ensureTooltipMount().root; } private createSubtitlesContainer(): HTMLElement { if (this.subtitlesContainer) { @@ -519,7 +543,8 @@ export class SubtitlesWidget { this.syncWidgetMount(); container.addEventListener("pointerdown", this.onPointerDownBound, { signal: this.abortController.signal, - passive: true, + passive: false, + capture: true, }); this.syncVisualStyleVars(); this.insetCacheReady = false; @@ -677,16 +702,17 @@ export class SubtitlesWidget { this.dragDocListenersAttached = true; document.addEventListener("pointermove", this.onPointerMoveBound, { passive: false, + capture: true, }); - document.addEventListener("pointerup", this.onPointerUpBound); - document.addEventListener("pointercancel", this.onPointerUpBound); + document.addEventListener("pointerup", this.onPointerUpBound, true); + document.addEventListener("pointercancel", this.onPointerUpBound, true); } private detachDragDocumentListeners(): void { if (!this.dragDocListenersAttached) return; this.dragDocListenersAttached = false; - document.removeEventListener("pointermove", this.onPointerMoveBound); - document.removeEventListener("pointerup", this.onPointerUpBound); - document.removeEventListener("pointercancel", this.onPointerUpBound); + document.removeEventListener("pointermove", this.onPointerMoveBound, true); + document.removeEventListener("pointerup", this.onPointerUpBound, true); + document.removeEventListener("pointercancel", this.onPointerUpBound, true); } private onResize(): void { this.syncWidgetMount(); @@ -822,6 +848,7 @@ export class SubtitlesWidget { return; if (!event.isPrimary) return; if (event.pointerType === "mouse" && event.button !== 0) return; + event.stopPropagation(); const layout = this.getLayoutSize(); const { rect: containerRect, w, h, scaleX, scaleY } = layout; if (!w || !h) return; @@ -849,11 +876,6 @@ export class SubtitlesWidget { this.dragging.offset.y = anchorY - pointerY; this.hideSnapGuides(); this.attachDragDocumentListeners(); - const captureEl: Element | null = - this.subtitlesBlock ?? (target instanceof Element ? target : null); - try { - (captureEl as HTMLElement | null)?.setPointerCapture(event.pointerId); - } catch {} } private onPointerUp(event: PointerEvent): void { if (this.dragging.pointerId === null) return; @@ -886,6 +908,9 @@ export class SubtitlesWidget { this.dragging.moved = true; this.suppressTokenClicksUntil = performance.now() + 450; this.releaseTooltip(); + try { + this.subtitlesContainer?.setPointerCapture(event.pointerId); + } catch {} } else { this.dragging.moved = true; } @@ -1488,6 +1513,8 @@ export class SubtitlesWidget { } this.tokenTooltip?.release(); this.tokenTooltip = undefined; + destroyShadowMount(this.tooltipMount); + this.tooltipMount = undefined; return this; } private clearPendingSchedulerState(): void { @@ -1588,13 +1615,14 @@ export class SubtitlesWidget { this.subtitlesBlock?.offsetWidth ?? 0, Math.min(globalThis.innerWidth * 0.6, 320), ); + const tooltipMount = this.ensureTooltipMount(); return new Tooltip({ target, anchor: this.subtitlesBlock ?? target, - layoutRoot: this.tooltipLayoutRoot, content, - parentElement: this.getTokenTooltipParentElement(), + parentElement: tooltipMount.root, + layoutRoot: tooltipMount.host, offset: { x: 4, y: 12 }, maxWidth: tooltipMaxWidth, borderRadius: 12, @@ -2042,6 +2070,8 @@ export class SubtitlesWidget { this.subtitlesContainer.remove(); this.subtitlesContainer = null; } + destroyShadowMount(this.tooltipMount); + this.tooltipMount = undefined; this.fullscreenLayerController.release(); if (this.safeAreaProbeEl) { this.safeAreaProbeEl.remove(); diff --git a/src/types/uiManager.ts b/src/types/uiManager.ts index 83329713..6ade3544 100644 --- a/src/types/uiManager.ts +++ b/src/types/uiManager.ts @@ -12,7 +12,6 @@ export type OverlayMount = { root: HTMLElement; portalContainer: HTMLElement; subtitlesMountContainer: HTMLElement; - tooltipLayoutRoot?: HTMLElement; }; export type UIManagerProps = { diff --git a/src/ui.ts b/src/ui.ts index ecd0f184..e2caef90 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -1,28 +1,8 @@ import type { TemplateResult } from "lit-html"; import { render } from "lit-html"; import { localizationProvider } from "./localization/localizationProvider"; -import mainScss from "./styles/main.scss?inline"; import type { LitHtml } from "./types/components/shared"; -function injectMainStyles(css: string): HTMLStyleElement | HTMLElement { - const gmAddStyle = ( - globalThis as typeof globalThis & { - GM_addStyle?: (styleText: string) => HTMLStyleElement | HTMLElement; - } - ).GM_addStyle; - - if (typeof gmAddStyle === "function") { - return gmAddStyle(css); - } - - const style = document.createElement("style"); - style.textContent = css; - (document.head || document.documentElement).appendChild(style); - return style; -} - -injectMainStyles(mainScss); - declare global { interface Window { __votKeyboardNavInitialized?: boolean; diff --git a/src/ui/components/dialog.ts b/src/ui/components/dialog.ts index c14c35eb..50439251 100644 --- a/src/ui/components/dialog.ts +++ b/src/ui/components/dialog.ts @@ -1,6 +1,7 @@ import { EventImpl } from "../../core/eventImpl"; import type { DialogProps } from "../../types/components/dialog"; import UI from "../../ui"; +import { getDeepActiveElement } from "../../utils/dom"; import { CLOSE_ICON } from "../icons"; import { addComponentEventListener, @@ -156,7 +157,7 @@ export default class Dialog { open() { // Temp dialogs are created visible; still run focus/keyboard setup. - this.previouslyFocused ??= document.activeElement; + this.previouslyFocused ??= getDeepActiveElement(document); this.hidden = false; this.attachKeydownTrap(); @@ -340,7 +341,9 @@ export default class Dialog { const first = focusables[0]; const last = focusables.at(-1) ?? first; - const active = document.activeElement; + const active = getDeepActiveElement( + this.container.getRootNode() as Document | ShadowRoot, + ); if (e.shiftKey) { if (active === first || active === this.box) { diff --git a/src/ui/components/tooltip.ts b/src/ui/components/tooltip.ts index 78796d45..370e31d8 100644 --- a/src/ui/components/tooltip.ts +++ b/src/ui/components/tooltip.ts @@ -30,6 +30,8 @@ export default class Tooltip { pageHeight!: number; globalOffsetX!: number; globalOffsetY!: number; + renderOffsetX!: number; + renderOffsetY!: number; maxWidth?: number; backgroundColor?: string; borderRadius?: number; @@ -224,7 +226,7 @@ export default class Tooltip { // Layout bounds may be computed against a player container while the // tooltip itself is mounted into a portal attached elsewhere in the DOM. // We therefore calculate in layout-root coordinates and later convert - // back to viewport coordinates for the rendered tooltip. + // back into the tooltip parent's coordinate space before rendering. if (this.layoutRoot === document.documentElement) { this.globalOffsetX = 0; this.globalOffsetY = 0; @@ -234,6 +236,11 @@ export default class Tooltip { this.globalOffsetY = top; } + const { left: parentLeft, top: parentTop } = + this.parentElement.getBoundingClientRect(); + this.renderOffsetX = parentLeft; + this.renderOffsetY = parentTop; + this.pageWidth = this.layoutRoot.clientWidth || document.documentElement.clientWidth; this.pageHeight = @@ -423,8 +430,8 @@ export default class Tooltip { this.position = resolvedPosition; return { - top: coords.top + this.globalOffsetY, - left: coords.left + this.globalOffsetX, + top: coords.top + this.globalOffsetY - this.renderOffsetY, + left: coords.left + this.globalOffsetX - this.renderOffsetX, }; } diff --git a/src/ui/manager.ts b/src/ui/manager.ts index 3ff85ca3..a9185b54 100644 --- a/src/ui/manager.ts +++ b/src/ui/manager.ts @@ -9,9 +9,7 @@ import { serializeProcessedSubtitles } from "../subtitles/standards"; import type { Status } from "../types/components/votButton"; import type { StorageData } from "../types/storage"; import type { OverlayMount, UIManagerProps } from "../types/uiManager"; -import ui from "../ui"; import debug from "../utils/debug"; -import { resolveScopedFullscreenElement } from "../utils/dom"; import { downloadTranslation } from "../utils/download"; import { GM_fetch } from "../utils/gm"; import type { IntervalIdleChecker } from "../utils/intervalIdleChecker"; @@ -23,6 +21,12 @@ import { downloadBlob, } from "../utils/utils"; import { applyOverlayMountUpdate } from "./mount"; +import { + createShadowMount, + destroyShadowMount, + reparentShadowMount, + type ShadowMount, +} from "./shadowMount"; import { handleTranslationButtonCommand } from "./translationCommands"; import { OverlayView } from "./views/overlay"; import { SettingsView } from "./views/settings"; @@ -36,6 +40,7 @@ export class UIManager { data: Partial; votGlobalPortal?: HTMLElement; + private globalPortalMount?: ShadowMount; /** * Contains all elements over video player e.g. button, menu and etc */ @@ -65,8 +70,8 @@ export class UIManager { return this.mount.portalContainer; } - get tooltipLayoutRoot(): HTMLElement | undefined { - return this.mount.tooltipLayoutRoot; + getSubtitlesMountContainer(): HTMLElement { + return this.votOverlayView?.root ?? this.mount.subtitlesMountContainer; } isInitialized(): this is { @@ -84,8 +89,11 @@ export class UIManager { this.initialized = true; - this.votGlobalPortal = ui.createPortal(); - this.getGlobalPortalHost(this.mount).appendChild(this.votGlobalPortal); + this.globalPortalMount = createShadowMount({ + parent: this.getGlobalPortalHost(this.mount), + rootClasses: ["vot-portal"], + }); + this.votGlobalPortal = this.globalPortalMount.root; this.votOverlayView = new OverlayView({ mount: this.mount, @@ -105,22 +113,25 @@ export class UIManager { }); this.votSettingsView.initUI(); + this.videoHandler?.subtitlesWidget?.updateMount({ + container: this.getSubtitlesMountContainer(), + }); + return this; } updateMount(mount: OverlayMount) { - const globalPortalHost = this.getGlobalPortalHost(mount); - if (this.votGlobalPortal?.parentElement !== globalPortalHost) { - globalPortalHost.appendChild(this.votGlobalPortal); - } + reparentShadowMount( + this.globalPortalMount, + this.getGlobalPortalHost(mount), + ); this.mount = applyOverlayMountUpdate(this.mount, mount, (nextMount) => { this.votOverlayView?.updateMount(nextMount); }); this.videoHandler?.subtitlesWidget?.updateMount({ - container: mount.subtitlesMountContainer, - tooltipLayoutRoot: mount.tooltipLayoutRoot, + container: this.getSubtitlesMountContainer(), }); return this; @@ -131,11 +142,11 @@ export class UIManager { webkitFullscreenElement?: Element | null; }; const fullscreenEl = doc.fullscreenElement ?? doc.webkitFullscreenElement; - const isCurrentVideoFullscreen = Boolean( - resolveScopedFullscreenElement(fullscreenEl, [mount.root], { - allowDocumentViewport: true, - }), - ); + const isCurrentVideoFullscreen = + fullscreenEl instanceof HTMLElement && + (fullscreenEl === mount.root || + fullscreenEl.contains(mount.root) || + mount.root.contains(fullscreenEl)); return isCurrentVideoFullscreen ? mount.root : document.documentElement; } @@ -167,11 +178,13 @@ export class UIManager { } try { - const isPiPActive = - this.videoHandler.video === document.pictureInPictureElement; - await (isPiPActive - ? document.exitPictureInPicture() - : this.videoHandler.video.requestPictureInPicture()); + // this.videoHandler.video.disablePictureInPicture = false; + const inPiP = document.pictureInPictureElement != null; + if (inPiP) { + await document.exitPictureInPicture(); + } else { + await this.videoHandler.video.requestPictureInPicture(); + } } catch (err) { debug.warn("[VOT] Failed to toggle Picture-in-Picture", err); } @@ -675,7 +688,9 @@ export class UIManager { // Each view is now idempotent and releases events before DOM. this.votOverlayView.release(); this.votSettingsView.release(); - this.votGlobalPortal.remove(); + destroyShadowMount(this.globalPortalMount); + this.globalPortalMount = undefined; + this.votGlobalPortal = undefined; this.initialized = false; return this; diff --git a/src/ui/mount.ts b/src/ui/mount.ts index 1c9214b9..e5fcba95 100644 --- a/src/ui/mount.ts +++ b/src/ui/mount.ts @@ -13,8 +13,7 @@ export function isSameOverlayMount( return ( previous.root === next.root && previous.portalContainer === next.portalContainer && - previous.subtitlesMountContainer === next.subtitlesMountContainer && - previous.tooltipLayoutRoot === next.tooltipLayoutRoot + previous.subtitlesMountContainer === next.subtitlesMountContainer ); } @@ -34,17 +33,3 @@ export function applyOverlayMountUpdate( onChanged(next); return next; } - -/** - * Tooltip geometry must be refreshed when either the button/root is reparented - * or the layout root itself changes. - */ -export function didTooltipMountContextChange( - previous: OverlayMount, - next: OverlayMount, -): boolean { - return ( - previous.root !== next.root || - previous.tooltipLayoutRoot !== next.tooltipLayoutRoot - ); -} diff --git a/src/ui/overlayVisibilityController.ts b/src/ui/overlayVisibilityController.ts index 800183f4..5e9f1a46 100644 --- a/src/ui/overlayVisibilityController.ts +++ b/src/ui/overlayVisibilityController.ts @@ -1,4 +1,5 @@ import debug from "../utils/debug"; +import { containsCrossShadow, getDeepActiveElement } from "../utils/dom"; import type { IntervalIdleChecker } from "../utils/intervalIdleChecker"; import type { OverlayView } from "./views/overlay"; @@ -140,7 +141,7 @@ export class OverlayVisibilityController { if ( relatedNode && - (currentNode?.contains(relatedNode) || + ((currentNode && containsCrossShadow(currentNode, relatedNode)) || this.deps.isInteractiveNode(relatedNode)) ) { return; @@ -164,7 +165,7 @@ export class OverlayVisibilityController { typeof document !== "undefined" && typeof document.hasFocus === "function"; if (canCheckFocus && document.hasFocus()) { - active = document.activeElement; + active = getDeepActiveElement(document); } if (active && this.deps.isInteractiveNode(active)) { debug.log("[OverlayVisibility] skip hide (focus inside overlay)"); diff --git a/src/ui/shadowMount.ts b/src/ui/shadowMount.ts new file mode 100644 index 00000000..5104bd29 --- /dev/null +++ b/src/ui/shadowMount.ts @@ -0,0 +1,142 @@ +import mainScss from "../styles/main.scss?inline"; + +type InlineStyleMap = Partial>; + +export type ShadowMount = { + host: HTMLElement; + root: HTMLElement; + shadowRoot: ShadowRoot; +}; + +type CreateShadowMountOptions = { + parent: HTMLElement; + hostTag?: string; + rootTag?: string; + hostClasses?: string[]; + rootClasses?: string[]; + hostStyles?: InlineStyleMap; + rootStyles?: InlineStyleMap; + delegatesFocus?: boolean; +}; + +const shadowScopedCssText = scopeCssForShadowRoots(mainScss); +let sharedShadowStyleSheet: CSSStyleSheet | null | undefined; + +function scopeCssForShadowRoots(cssText: string): string { + return cssText + .replace(/:root\b/g, ":host") + .replace(/html\.vot-keyboard-nav/g, ":host-context(.vot-keyboard-nav)") + .replace(/:fullscreen(?=\s|,)/g, ":host-context(:fullscreen)") + .replace( + /:-webkit-full-screen(?=\s|,)/g, + ":host-context(:-webkit-full-screen)", + ); +} + +function applyInlineStyles( + element: HTMLElement, + styles: InlineStyleMap | undefined, +): void { + if (!styles) { + return; + } + + for (const [name, value] of Object.entries(styles)) { + if (typeof value !== "string") { + continue; + } + element.style.setProperty(name, value); + } +} + +function getSharedShadowStyleSheet(): CSSStyleSheet | null { + if (sharedShadowStyleSheet !== undefined) { + return sharedShadowStyleSheet; + } + + const canUseConstructableSheets = + typeof CSSStyleSheet !== "undefined" && + typeof CSSStyleSheet.prototype.replaceSync === "function"; + + if (!canUseConstructableSheets) { + sharedShadowStyleSheet = null; + return sharedShadowStyleSheet; + } + + const sheet = new CSSStyleSheet(); + sheet.replaceSync(shadowScopedCssText); + sharedShadowStyleSheet = sheet; + return sharedShadowStyleSheet; +} + +function adoptScopedStyles(shadowRoot: ShadowRoot): void { + const sharedSheet = getSharedShadowStyleSheet(); + if (sharedSheet) { + if (!shadowRoot.adoptedStyleSheets.includes(sharedSheet)) { + shadowRoot.adoptedStyleSheets = [ + ...shadowRoot.adoptedStyleSheets, + sharedSheet, + ]; + } + return; + } + + const style = document.createElement("style"); + style.textContent = shadowScopedCssText; + shadowRoot.append(style); +} + +export function createShadowMount({ + parent, + hostTag = "vot-shadow-host", + rootTag = "vot-block", + hostClasses = [], + rootClasses = [], + hostStyles, + rootStyles, + delegatesFocus = false, +}: CreateShadowMountOptions): ShadowMount { + const host = document.createElement(hostTag); + if (hostClasses.length > 0) { + host.classList.add(...hostClasses); + } + applyInlineStyles(host, hostStyles); + + const shadowRoot = host.attachShadow({ + mode: "open", + delegatesFocus, + }); + adoptScopedStyles(shadowRoot); + + const root = document.createElement(rootTag); + if (rootClasses.length > 0) { + root.classList.add(...rootClasses); + } + applyInlineStyles(root, rootStyles); + shadowRoot.append(root); + + parent.append(host); + + return { + host, + root, + shadowRoot, + }; +} + +export function reparentShadowMount( + mount: ShadowMount | undefined, + parent: HTMLElement, +): void { + if (!mount) { + return; + } + + if (mount.host.parentElement !== parent) { + parent.append(mount.host); + } +} + +export function destroyShadowMount(mount: ShadowMount | undefined): void { + mount?.host.remove(); +} diff --git a/src/ui/views/overlay.ts b/src/ui/views/overlay.ts index 99b9ffd7..e0fa6473 100644 --- a/src/ui/views/overlay.ts +++ b/src/ui/views/overlay.ts @@ -25,7 +25,12 @@ import Tooltip from "../components/tooltip"; import VOTButton from "../components/votButton"; import VOTMenu from "../components/votMenu"; import { SETTINGS_ICON, SUBTITLES_ICON } from "./../icons"; -import { didTooltipMountContextChange } from "../mount"; +import { + createShadowMount, + destroyShadowMount, + reparentShadowMount, + type ShadowMount, +} from "../shadowMount"; export class OverlayView { private static readonly BIG_CONTAINER_WIDTH_PX = 550; @@ -52,6 +57,7 @@ export class OverlayView { private readonly data: Partial; private readonly videoHandler?: VideoHandler; private readonly intervalIdleChecker: IntervalIdleChecker; + private overlayMount?: ShadowMount; private readonly events: { [K in keyof OverlayViewEventMap]: EventImpl; @@ -113,26 +119,20 @@ export class OverlayView { } get root(): HTMLElement { - return this.mount.root; + return this.overlayMount?.root ?? this.mount.root; } get portalContainer(): HTMLElement { return this.mount.portalContainer; } - get tooltipLayoutRoot(): HTMLElement | undefined { - return this.mount.tooltipLayoutRoot; - } - /** - * Update mount points (root/tooltipLayoutRoot) when the player container changes. + * Update mount points when the player container changes. * Moves already-mounted UI nodes and rebinds root-bound listeners (dragging). */ updateMount(nextMount: OverlayMount): this { const prevRoot = this.mount.root; const nextRoot = nextMount.root; - const prevTooltipRoot = this.mount.tooltipLayoutRoot; - const nextTooltipRoot = nextMount.tooltipLayoutRoot; this.mount = nextMount; @@ -140,34 +140,23 @@ export class OverlayView { return this; } - // Move mounted nodes to new containers. if (prevRoot !== nextRoot) { - if (this.votButton) { - nextRoot.appendChild(this.votButton.container); - } - if (this.votMenu) { - nextRoot.appendChild(this.votMenu.container); + if (this.overlayMount) { + reparentShadowMount(this.overlayMount, nextRoot); + } else { + if (this.votButton) { + nextRoot.appendChild(this.votButton.container); + } + if (this.votMenu) { + nextRoot.appendChild(this.votMenu.container); + } } } - // Tooltip geometry depends on both the layout root and the overlay root: - // some fullscreen transitions only reparent the button/root while keeping - // the same tooltipLayoutRoot, so force a refresh for either change. - if ( - this.votButtonTooltip && - didTooltipMountContextChange( - { - root: prevRoot, - portalContainer: this.mount.portalContainer, - subtitlesMountContainer: this.mount.subtitlesMountContainer, - tooltipLayoutRoot: prevTooltipRoot, - }, - nextMount, - ) - ) { - // If tooltipLayoutRoot becomes undefined, fall back to documentElement. + if (this.votButtonTooltip && prevRoot !== nextRoot) { this.votButtonTooltip.updateMount({ - layoutRoot: nextTooltipRoot ?? document.documentElement, + parentElement: this.root, + layoutRoot: this.overlayMount?.host, }); } @@ -256,6 +245,23 @@ export class OverlayView { } this.initialized = true; + this.overlayMount = createShadowMount({ + parent: this.mount.root, + rootClasses: ["vot-overlay-root"], + hostStyles: { + position: "absolute", + inset: "0", + display: "block", + "pointer-events": "none", + }, + rootStyles: { + position: "relative", + display: "block", + width: "100%", + height: "100%", + "pointer-events": "none", + }, + }); // #region Shared logic const { position, direction } = this.calcButtonLayout(buttonPosition); @@ -282,8 +288,8 @@ export class OverlayView { autoLayout: false, hidden: direction === "row", bordered: false, - parentElement: this.globalPortal, - layoutRoot: this.tooltipLayoutRoot, + parentElement: this.root, + layoutRoot: this.overlayMount.host, }); // #endregion VOT Button @@ -598,9 +604,11 @@ export class OverlayView { // Keep menu open while interacting with dialogs spawned from it // (language picker, etc.). - const isInsideDialog = - target instanceof HTMLElement && - !!target.closest(".vot-dialog-container"); + const isInsideDialog = path.some( + (node) => + node instanceof HTMLElement && + node.classList.contains("vot-dialog-container"), + ); if ( isInsideMenu || @@ -997,6 +1005,8 @@ export class OverlayView { this.votButton?.remove(); this.votMenu?.remove(); this.votButtonTooltip?.release(); + destroyShadowMount(this.overlayMount); + this.overlayMount = undefined; } private doReleaseUIEvents(): void { diff --git a/src/utils/debug.ts b/src/utils/debug.ts index 145a3bac..6058f688 100644 --- a/src/utils/debug.ts +++ b/src/utils/debug.ts @@ -2,7 +2,7 @@ type DebugMethod = (...text: unknown[]) => void; const noop: DebugMethod = () => {}; -const log: DebugMethod = DEBUG_MODE +const log: DebugMethod = !DEBUG_MODE ? (...text: unknown[]) => { console.log( "%c[VOT DEBUG]", @@ -12,7 +12,7 @@ const log: DebugMethod = DEBUG_MODE } : noop; -const warn: DebugMethod = DEBUG_MODE +const warn: DebugMethod = !DEBUG_MODE ? (...text: unknown[]) => { console.warn( "%c[VOT DEBUG]", @@ -22,7 +22,7 @@ const warn: DebugMethod = DEBUG_MODE } : noop; -const error: DebugMethod = DEBUG_MODE +const error: DebugMethod = !DEBUG_MODE ? (...text: unknown[]) => { console.error( "%c[VOT DEBUG]", diff --git a/src/utils/dom.ts b/src/utils/dom.ts index e7f71a7b..1e0e69c8 100644 --- a/src/utils/dom.ts +++ b/src/utils/dom.ts @@ -8,6 +8,22 @@ function getComposableParent(node: Node | null): Node | null { return node.parentNode ?? null; } +export function getDeepActiveElement( + root: Document | ShadowRoot = document, +): Element | null { + let activeElement: Element | null = root.activeElement; + + while (activeElement instanceof HTMLElement && activeElement.shadowRoot) { + const nestedActiveElement = activeElement.shadowRoot.activeElement; + if (!nestedActiveElement) { + break; + } + activeElement = nestedActiveElement; + } + + return activeElement; +} + /** * Checks whether `target` is a descendant of `container` in the composed tree * (crossing ShadowRoot boundaries via hosts). diff --git a/src/utils/gm.ts b/src/utils/gm.ts index 337eeaab..deae0372 100644 --- a/src/utils/gm.ts +++ b/src/utils/gm.ts @@ -1,5 +1,3 @@ -// Minimal HTTP method type for GM_xmlhttpRequest compatibility. -// (Avoid pulling external typings just for this union.) type HttpMethod = | "GET" | "POST" @@ -13,6 +11,7 @@ type HttpMethod = import { executeWithResponseCache } from "../core/cacheManager"; import type { FetchOpts } from "../types/utils/gm"; import { createTimeoutSignal } from "./abort"; +import { browserInfo } from "./browserInfo"; import debug from "./debug"; import { getErrorMessage, isAbortError, makeAbortError } from "./errors"; import { getHeaders } from "./utils"; @@ -20,11 +19,13 @@ import { getHeaders } from "./utils"; const YANDEX_API_HOST = "api.browser.yandex.ru"; const GOOGLEVIDEO_HOST_SUFFIX = "googlevideo.com"; const HEADER_LINE_RE = /^([\w-]+):\s*(.+)$/; +// Matches statusText reason-phrase: printable ASCII except control chars const URL_SCHEME_RE = /^[a-zA-Z][a-zA-Z\d+.-]*:/; + type RequestUrlLike = string | URL | Request; type GmXhrResponse = { finalUrl?: string; - response?: Blob; + response?: Blob | null; responseHeaders?: string; status?: number; statusText?: string; @@ -61,8 +62,8 @@ function hasSupportedGmXhr(): boolean { export const isProxyOnlyExtension = !(typeof IS_EXTENSION !== "undefined" && IS_EXTENSION) && - !!scriptHandler && - !hasSupportedGmXhr(); + (browserInfo.browser?.name === "Safari" || + !["Tampermonkey", "Violentmonkey"].includes(scriptHandler)); export const isSupportGM4 = typeof GM !== "undefined" || (globalThis as any).GM !== undefined; export const isSupportGMXhr = hasSupportedGmXhr(); @@ -75,9 +76,7 @@ function getRequestHost(url: string): string | undefined { if (!URL_SCHEME_RE.test(normalizedUrl)) { try { return new URL(`https://${normalizedUrl}`).hostname.toLowerCase(); - } catch { - // fall through - } + } catch {} } return undefined; } @@ -104,8 +103,6 @@ function shouldUseGmXhr( ); } - // These endpoints are routinely blocked by page-world CORS. Going through - // native fetch first only adds noisy console errors and an extra failed hop. return ( isHostOrSubdomain(host, YANDEX_API_HOST) || isHostOrSubdomain(host, GOOGLEVIDEO_HOST_SUFFIX) @@ -155,65 +152,87 @@ function getGmXhrErrorMessage(error: unknown): string { error?: unknown; statusText?: unknown; }; - if (typeof maybeError?.error === "string") { + if ( + typeof maybeError?.error === "string" && + maybeError.error.trim().length > 0 + ) { return maybeError.error; } - if (typeof maybeError?.statusText === "string") { + if ( + typeof maybeError?.statusText === "string" && + maybeError.statusText.trim().length > 0 && + maybeError.statusText !== '""' && + maybeError.statusText !== "''" + ) { return maybeError.statusText; } - return getErrorMessage(error) || "Unknown error"; + return getErrorMessage(error) || "Unknown GM XHR error"; } -async function gmXhrFetch( +function buildResponse(resp: GmXhrResponse, urlStr: string): Response { + const status = resp.status; + const statusText = typeof resp.statusText === "string" ? resp.statusText : ""; + const body = resp.response instanceof Blob ? resp.response : null; + const responseHeaders = parseResponseHeaders(resp.responseHeaders); + + const response = new Response(body, { + status, + statusText, + headers: responseHeaders, + }); + + Object.defineProperty(response, "url", { + value: resp.finalUrl ?? urlStr, + }); + + return response; +} + +async function executeCallbackGmXhr( + gmXhr: GmXhrCallbackApi, urlStr: string, timeout: number, fetchOptions: Omit, + method: string, + headers: Record, ): Promise { +<<<<<<< Updated upstream const headers = getHeaders(fetchOptions.headers); const callbackGmXhr = getCallbackGmXhr(); const promiseGmXhr = getPromiseGmXhr(); +======= + return new Promise((resolve, reject) => { + let settled = false; + let onAbort: (() => void) | undefined; +>>>>>>> Stashed changes - if (callbackGmXhr) { - return await new Promise((resolve, reject) => { - let settled = false; - let onAbort: (() => void) | undefined; - const cleanupAbort = () => { - if (onAbort) { - fetchOptions.signal?.removeEventListener("abort", onAbort); - } - }; - const failOnce = (error: Error) => { + const cleanupAbort = () => { + if (onAbort) { + fetchOptions.signal?.removeEventListener("abort", onAbort); + } + }; + + const failOnce = (error: Error) => { + if (settled) return; + settled = true; + cleanupAbort(); + reject(error); + }; + + const request = gmXhr({ + method: method as HttpMethod, + url: urlStr, + responseType: "blob" as any, + data: fetchOptions.body as any, + timeout, + headers, + onload: (resp: GmXhrResponse) => { if (settled) return; settled = true; cleanupAbort(); - reject(error); - }; - - const request = callbackGmXhr({ - method: (fetchOptions.method || "GET") as HttpMethod, - url: urlStr, - responseType: "blob" as any, - data: fetchOptions.body as any, - timeout, - headers, - onload: (resp: GmXhrResponse) => { - if (settled) return; - settled = true; - cleanupAbort(); - const responseHeaders = parseResponseHeaders(resp.responseHeaders); - - const response = new Response(resp.response as Blob, { - status: resp.status, - statusText: - typeof resp.statusText === "string" ? resp.statusText : "", - headers: responseHeaders, - }); - - Object.defineProperty(response, "url", { - value: resp.finalUrl ?? urlStr, - }); +<<<<<<< Updated upstream resolve(response); }, ontimeout: () => failOnce(new Error("Timeout")), @@ -227,26 +246,92 @@ async function gmXhrFetch( request?.abort?.(); } catch { // ignore abort races +======= + try { + const response = buildResponse(resp, urlStr); + debug.log("[GM_fetch] GM_xmlhttpRequest completed", { + url: response.url, + method, + status: response.status, + statusText: response.statusText, + }); + resolve(response); + } catch (buildErr) { + // Constructing Response failed even after sanitization — surface error + debug.warn("[GM_fetch] GM_xmlhttpRequest response build failed", { + url: urlStr, + method, + error: getErrorMessage(buildErr), + rawStatus: resp.status, + rawStatusText: resp.statusText, + }); + reject( + buildErr instanceof Error + ? buildErr + : new Error(getErrorMessage(buildErr)), + ); +>>>>>>> Stashed changes } + }, + ontimeout: () => { + debug.warn("[GM_fetch] GM_xmlhttpRequest timed out", { + url: urlStr, + method, + timeout, + }); + failOnce(new Error("Timeout")); + }, + onerror: (error: unknown) => { + // Safari can deliver an empty-string error — fall back to generic message + const message = getGmXhrErrorMessage(error); + debug.warn("[GM_fetch] GM_xmlhttpRequest failed", { + url: urlStr, + method, + error: message, + }); + failOnce(new Error(message)); + }, + onabort: () => { + debug.warn("[GM_fetch] GM_xmlhttpRequest aborted", { + url: urlStr, + method, + }); failOnce(makeAbortError()); - }; - - if (fetchOptions.signal) { - fetchOptions.signal.addEventListener("abort", onAbort, { once: true }); - if (fetchOptions.signal.aborted) { - onAbort(); - return; - } - } + }, }); - } - if (!promiseGmXhr) { - throw new TypeError("GM_xmlhttpRequest is not available"); - } + onAbort = () => { + try { + request?.abort?.(); + } catch {} + failOnce(makeAbortError()); + }; +<<<<<<< Updated upstream const request = promiseGmXhr({ method: (fetchOptions.method || "GET") as HttpMethod, +======= + if (fetchOptions.signal) { + fetchOptions.signal.addEventListener("abort", onAbort, { once: true }); + if (fetchOptions.signal.aborted) { + onAbort(); + return; + } + } + }); +} + +async function executePromiseGmXhr( + gmXhr: GmXhrPromiseApi, + urlStr: string, + timeout: number, + fetchOptions: Omit, + method: string, + headers: Record, +): Promise { + const request = gmXhr({ + method: method as HttpMethod, +>>>>>>> Stashed changes url: urlStr, responseType: "blob" as any, data: fetchOptions.body as any, @@ -264,9 +349,7 @@ async function gmXhrFetch( abortHandler = () => { try { request.abort?.(); - } catch { - // ignore abort races - } + } catch {} reject(makeAbortError()); }; @@ -279,17 +362,8 @@ async function gmXhrFetch( }); const resp = (await Promise.race([request, abortPromise])) as GmXhrResponse; - const responseHeaders = parseResponseHeaders(resp.responseHeaders); - const response = new Response(resp.response as Blob, { - status: resp.status, - statusText: typeof resp.statusText === "string" ? resp.statusText : "", - headers: responseHeaders, - }); - - Object.defineProperty(response, "url", { - value: resp.finalUrl ?? urlStr, - }); + const response = buildResponse(resp, urlStr); return response; } finally { @@ -299,6 +373,68 @@ async function gmXhrFetch( } } +async function gmXhrFetch( + urlStr: string, + timeout: number, + fetchOptions: Omit, +): Promise { + const headers = getHeaders(fetchOptions.headers); + const method = (fetchOptions.method || "GET").toUpperCase(); + debug.log("[GM_fetch] GM_xmlhttpRequest start", { + url: urlStr, + method, + timeout, + headerCount: Object.keys(headers).length, + }); + + const callbackGmXhr = getCallbackGmXhr(); + if (callbackGmXhr) { + debug.log("[GM_fetch] attempting callback-style GM_xmlhttpRequest"); + try { + return await executeCallbackGmXhr( + callbackGmXhr, + urlStr, + timeout, + fetchOptions, + method, + headers, + ); + } catch (error) { + if (isAbortError(error)) throw error; + debug.warn("[GM_fetch] callback-style GM_xmlhttpRequest failed", { + url: urlStr, + method, + error: getGmXhrErrorMessage(error), + }); + } + } + + const promiseGmXhr = getPromiseGmXhr(); + if (promiseGmXhr) { + debug.log("[GM_fetch] attempting promise-style GM.xmlHttpRequest"); + try { + return await executePromiseGmXhr( + promiseGmXhr, + urlStr, + timeout, + fetchOptions, + method, + headers, + ); + } catch (error) { + if (isAbortError(error)) throw error; + debug.warn("[GM_fetch] promise-style GM.xmlHttpRequest failed", { + url: urlStr, + method, + error: getGmXhrErrorMessage(error), + }); + } + } + + debug.warn("[GM_fetch] none of the GM approaches worked"); + throw new Error("All GM approaches failed"); +} + export async function GM_fetch( url: RequestUrlLike, opts: FetchOpts = {}, @@ -320,7 +456,33 @@ export async function GM_fetch( reason: forceGmXhr ? "forced" : "host-policy", url: urlStr, }); - return await gmXhrFetch(urlStr, timeout, fetchOptions); + try { + return await gmXhrFetch(urlStr, timeout, fetchOptions); + } catch (err) { + if (isAbortError(err)) throw err; + if (forceGmXhr || shouldUseGmXhr(host, urlStr)) throw err; + debug.warn( + "[GM_fetch] all GM approaches failed, falling back to native fetch", + { + url: urlStr, + method, + host: host ?? "unknown", + error: getErrorMessage(err) || "Unknown error", + }, + ); + const { signal, cleanup } = createTimeoutSignal( + timeout, + fetchOptions.signal, + ); + try { + return await fetch(url, { + ...fetchOptions, + signal, + }); + } finally { + cleanup(); + } + } } const { signal, cleanup } = createTimeoutSignal( @@ -336,11 +498,20 @@ export async function GM_fetch( if (signal.aborted || isAbortError(err)) { throw err; } +<<<<<<< Updated upstream // If fetch fails, retry via GM_xmlhttpRequest. debug.log( "GM_fetch preventing CORS by GM_xmlhttpRequest", getErrorMessage(err) || "Unknown error", ); +======= + debug.warn("[GM_fetch] fetch failed, retrying via GM_xmlhttpRequest", { + url: urlStr, + method, + host: host ?? "unknown", + error: getErrorMessage(err) || "Unknown error", + }); +>>>>>>> Stashed changes return await gmXhrFetch(urlStr, timeout, fetchOptions); } finally { cleanup(); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index cd32bbd5..31e3a872 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -179,9 +179,10 @@ export async function downloadBlob( if (options.preferShare) { const shareResult = await shareBlob(blob, filename); - return shareResult === "shared"; + if (shareResult === "shared") { + return true; + } } - return triggerBlobDownload(blob, filename); } diff --git a/src/videoHandler/modules/events.ts b/src/videoHandler/modules/events.ts index 20418859..3ed111f4 100644 --- a/src/videoHandler/modules/events.ts +++ b/src/videoHandler/modules/events.ts @@ -11,7 +11,12 @@ import { import { resetAndHideLifecycle } from "../../core/lifecycleShared"; import type { VideoHandler } from "../../index"; import debug from "../../utils/debug"; +<<<<<<< Updated upstream +======= +import { containsCrossShadow, getDeepActiveElement } from "../../utils/dom"; +>>>>>>> Stashed changes import { GM_fetch } from "../../utils/gm"; +import { isIframe } from "../../utils/iframeConnector"; import { getPlatformEventConfig } from "../../utils/platformEvents"; import { clampPercentInt } from "../../utils/volume"; import { handlePlaybackResumedTranslationRefresh } from "./translation"; @@ -253,6 +258,14 @@ function bindYouTubeVolumeSync(ctx: ExtraEventsContext): void { videoPercent = toPercentInt(fallbackVolume * 100); } self.syncVideoVolumeSlider(); +<<<<<<< Updated upstream +======= + const activeOverlayView = self.uiManager.votOverlayView; + if (!activeOverlayView?.isInitialized()) return; + const videoPercent = toPercentInt( + activeOverlayView.videoVolumeSlider.value, + ); +>>>>>>> Stashed changes syncAudioTranslationVolumeFromVideo(self, videoPercent); }); const ytpVolumePanel = document.querySelector(".ytp-volume-panel"); @@ -378,7 +391,7 @@ function bindGlobalDismissAndHotkeys(ctx: ExtraEventsContext): void { const keyboardEvent = event as KeyboardEvent; if (keyboardEvent.repeat) return; userPressedKeys.add(keyboardEvent.code); - const activeElement = document.activeElement as HTMLElement | null; + const activeElement = getDeepActiveElement(document) as HTMLElement | null; const activeTag = activeElement?.tagName?.toLowerCase?.() ?? ""; const isInputElement = ["input", "textarea"].includes(activeTag) || @@ -421,6 +434,7 @@ function bindGlobalDismissAndHotkeys(ctx: ExtraEventsContext): void { add(globalThis, "blur", clearUserPressedKeys); const eventContainer = self.getEventContainer(); if (eventContainer) { +<<<<<<< Updated upstream addMany(eventContainer, ["pointerenter", "pointerdown"], (event) => self.overlayVisibility.handleHostInteraction(event), ); @@ -433,6 +447,38 @@ function bindGlobalDismissAndHotkeys(ctx: ExtraEventsContext): void { add(eventContainer, "pointerleave", (event) => self.overlayVisibility.scheduleHide(event), ); +======= + const useWindowEvents = + isIframe() && typeof globalThis.window !== "undefined"; + const interactionTarget = useWindowEvents + ? globalThis.window + : eventContainer; + + if (useWindowEvents) { + addMany( + interactionTarget, + ["pointermove", "pointerdown"], + (event) => self.overlayVisibility.handleHostInteraction(event), + { passive: true }, + ); + add(interactionTarget, "blur", () => + self.overlayVisibility.scheduleHide(), + ); + } else { + addMany(interactionTarget, ["pointerenter", "pointerdown"], (event) => + self.overlayVisibility.handleHostInteraction(event), + ); + add( + interactionTarget, + "pointermove", + (event) => self.overlayVisibility.handleHostInteraction(event), + { passive: true }, + ); + add(interactionTarget, "pointerleave", (event) => + self.overlayVisibility.scheduleHide(event), + ); + } +>>>>>>> Stashed changes } self.rebindOverlayVisibilityTargets(); if (platformConfig.allowTouchMoveHandler) { @@ -462,7 +508,7 @@ export function bindPlaybackRefreshOnResume(ctx: ExtraEventsContext): void { add(self.video, "playing", () => { if (!wasPausedSinceLastPlay) return; wasPausedSinceLastPlay = false; - void handlePlaybackResumedTranslationRefresh.call(self).catch((error) => { + handlePlaybackResumedTranslationRefresh.call(self).catch((error) => { debug.log( "[VOT] Failed to refresh translation after playback resumed", error, @@ -581,8 +627,9 @@ export function isOverlayInteractiveNode( const buttonContainer = overlayView?.votButton?.container; const menuContainer = overlayView?.votMenu?.container; return ( - (buttonContainer instanceof Node && buttonContainer.contains(node)) || - (menuContainer instanceof Node && menuContainer.contains(node)) + (buttonContainer instanceof Node && + containsCrossShadow(buttonContainer, node)) || + (menuContainer instanceof Node && containsCrossShadow(menuContainer, node)) ); } export function getAutoHideDelay(this: VideoHandler): number { diff --git a/src/videoHandler/modules/subtitles.ts b/src/videoHandler/modules/subtitles.ts index edba3650..22729d08 100644 --- a/src/videoHandler/modules/subtitles.ts +++ b/src/videoHandler/modules/subtitles.ts @@ -26,9 +26,19 @@ function getPreferredSubtitlesLanguage( handler: VideoHandler, ): string | undefined { const videoData = handler.videoData; +<<<<<<< Updated upstream return handler.getPreferredSubtitlesLanguage( videoData?.detectedLanguage, videoData?.responseLanguage, +======= + return ( + handler.getPreferredSubtitlesLanguage( + videoData?.detectedLanguage, + videoData?.responseLanguage, + ) ?? + videoData?.responseLanguage ?? + handler.translateToLang +>>>>>>> Stashed changes ); }