diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00082a10..85da2758 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: - name: Run linter run: npm run lint - name: Run type checker - run: npx tsc --noEmit + run: npm run type-check # - name: Run tests # run: npm run test - name: Build for Firefox diff --git a/README.md b/README.md index 20adeae6..cfcc2458 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ TTV LOL PRO removes _most_ livestream ads from Twitch. This is free, don't expec **TTV LOL PRO:** - removes _most_ livestream ads from Twitch, -- lets you whitelist channels (Firefox only), +- lets you whitelist channels, - improves TTV LOL's popup by showing stream status, - lets you add custom primary/fallback proxies. diff --git a/package-lock.json b/package-lock.json index 40a42594..82f3d994 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ttv-lol-pro", - "version": "2.1.6", + "version": "2.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ttv-lol-pro", - "version": "2.1.6", + "version": "2.2.0", "license": "GPL-3.0", "dependencies": { "bowser": "^2.11.0", @@ -14,50 +14,113 @@ }, "devDependencies": { "@parcel/config-webextension": "^2.9.3", - "@types/chrome": "^0.0.243", - "@types/ip": "^1.1.0", - "@types/webextension-polyfill": "^0.10.1", + "@types/chrome": "^0.0.246", + "@types/ip": "^1.1.1", + "@types/webextension-polyfill": "^0.10.4", "buffer": "^6.0.3", "os-browserify": "^0.3.0", "parcel": "^2.9.3", - "postcss": "^8.4.27", + "postcss": "^8.4.31", "prettier": "2.8.8", "prettier-plugin-css-order": "^1.3.1", "prettier-plugin-organize-imports": "^3.2.3", "shx": "^0.3.4", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "webextension-polyfill": "^0.10.0" } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -127,18 +190,18 @@ } }, "node_modules/@lezer/common": { - "version": "0.15.12", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", - "integrity": "sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.1.0.tgz", + "integrity": "sha512-XPIN3cYDXsoJI/oDWoR2tD++juVrhgIago9xyKhZ7IhGlzdDM9QgC8D8saKNCz5pindGcznFr2HBSsEQSWnSjw==", "dev": true }, "node_modules/@lezer/lr": { - "version": "0.15.8", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz", - "integrity": "sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.12.tgz", + "integrity": "sha512-5nwY1JzCueUdRtlMBnlf1SUi69iGCq2ABq7WQFQMkn/kxPvoACAEnTp4P17CtXxYr7WCwtYPLL2AEvxKPuF1OQ==", "dev": true, "dependencies": { - "@lezer/common": "^0.15.0" + "@lezer/common": "^1.0.0" } }, "node_modules/@lmdb/lmdb-darwin-arm64": { @@ -220,13 +283,13 @@ ] }, "node_modules/@mischnic/json-sourcemap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz", - "integrity": "sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz", + "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==", "dev": true, "dependencies": { - "@lezer/common": "^0.15.7", - "@lezer/lr": "^0.15.4", + "@lezer/common": "^1.0.0", + "@lezer/lr": "^1.0.0", "json5": "^2.2.1" }, "engines": { @@ -1579,9 +1642,9 @@ } }, "node_modules/@parcel/watcher": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.2.0.tgz", - "integrity": "sha512-71S4TF+IMyAn24PK4KSkdKtqJDR3zRzb0HE3yXpacItqTM7XfF2f5q9NEGLEVl0dAaBAGfNwDCjH120y25F6Tg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz", + "integrity": "sha512-pW7QaFiL11O0BphO+bq3MgqeX/INAk9jgBldVDYjlQPO4VddoZnF22TcF9onMhnLVHuNqBJeRf+Fj7eezi/+rQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -1598,22 +1661,24 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.2.0", - "@parcel/watcher-darwin-arm64": "2.2.0", - "@parcel/watcher-darwin-x64": "2.2.0", - "@parcel/watcher-linux-arm-glibc": "2.2.0", - "@parcel/watcher-linux-arm64-glibc": "2.2.0", - "@parcel/watcher-linux-arm64-musl": "2.2.0", - "@parcel/watcher-linux-x64-glibc": "2.2.0", - "@parcel/watcher-linux-x64-musl": "2.2.0", - "@parcel/watcher-win32-arm64": "2.2.0", - "@parcel/watcher-win32-x64": "2.2.0" + "@parcel/watcher-android-arm64": "2.3.0", + "@parcel/watcher-darwin-arm64": "2.3.0", + "@parcel/watcher-darwin-x64": "2.3.0", + "@parcel/watcher-freebsd-x64": "2.3.0", + "@parcel/watcher-linux-arm-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-glibc": "2.3.0", + "@parcel/watcher-linux-arm64-musl": "2.3.0", + "@parcel/watcher-linux-x64-glibc": "2.3.0", + "@parcel/watcher-linux-x64-musl": "2.3.0", + "@parcel/watcher-win32-arm64": "2.3.0", + "@parcel/watcher-win32-ia32": "2.3.0", + "@parcel/watcher-win32-x64": "2.3.0" } }, "node_modules/@parcel/watcher-android-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.2.0.tgz", - "integrity": "sha512-nU2wh00CTQT9rr1TIKTjdQ9lAGYpmz6XuKw0nAwAN+S2A5YiD55BK1u+E5WMCT8YOIDe/n6gaj4o/Bi9294SSQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.3.0.tgz", + "integrity": "sha512-f4o9eA3dgk0XRT3XhB0UWpWpLnKgrh1IwNJKJ7UJek7eTYccQ8LR7XUWFKqw6aEq5KUNlCcGvSzKqSX/vtWVVA==", "cpu": [ "arm64" ], @@ -1631,9 +1696,9 @@ } }, "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-cJl0UZDcodciy3TDMomoK/Huxpjlkkim3SyMgWzjovHGOZKNce9guLz2dzuFwfObBFCjfznbFMIvAZ5syXotYw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.3.0.tgz", + "integrity": "sha512-mKY+oijI4ahBMc/GygVGvEdOq0L4DxhYgwQqYAz/7yPzuGi79oXrZG52WdpGA1wLBPrYb0T8uBaGFo7I6rvSKw==", "cpu": [ "arm64" ], @@ -1651,9 +1716,9 @@ } }, "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.2.0.tgz", - "integrity": "sha512-QI77zxaGrCV1StKcoRYfsUfmUmvPMPfQrubkBBy5XujV2fwaLgZivQOTQMBgp5K2+E19u1ufpspKXAPqSzpbyg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.3.0.tgz", + "integrity": "sha512-20oBj8LcEOnLE3mgpy6zuOq8AplPu9NcSSSfyVKgfOhNAc4eF4ob3ldj0xWjGGbOF7Dcy1Tvm6ytvgdjlfUeow==", "cpu": [ "x64" ], @@ -1670,10 +1735,30 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.3.0.tgz", + "integrity": "sha512-7LftKlaHunueAEiojhCn+Ef2CTXWsLgTl4hq0pkhkTBFI3ssj2bJXmH2L67mKpiAD5dz66JYk4zS66qzdnIOgw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.2.0.tgz", - "integrity": "sha512-I2GPBcAXazPzabCmfsa3HRRW+MGlqxYd8g8RIueJU+a4o5nyNZDz0CR1cu0INT0QSQXEZV7w6UE8Hz9CF8u3Pg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.3.0.tgz", + "integrity": "sha512-1apPw5cD2xBv1XIHPUlq0cO6iAaEUQ3BcY0ysSyD9Kuyw4MoWm1DV+W9mneWI+1g6OeP6dhikiFE6BlU+AToTQ==", "cpu": [ "arm" ], @@ -1691,9 +1776,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.2.0.tgz", - "integrity": "sha512-St5mlfp+2lS9AmgixUqfwJa/DwVmTCJxC1HcOubUTz6YFOKIlkHCeUa1Bxi4E/tR/HSez8+heXHL8HQkJ4Bd8g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.3.0.tgz", + "integrity": "sha512-mQ0gBSQEiq1k/MMkgcSB0Ic47UORZBmWoAWlMrTW6nbAGoLZP+h7AtUM7H3oDu34TBFFvjy4JCGP43JlylkTQA==", "cpu": [ "arm64" ], @@ -1711,9 +1796,9 @@ } }, "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.2.0.tgz", - "integrity": "sha512-jS+qfhhoOBVWwMLP65MaG8xdInMK30pPW8wqTCg2AAuVJh5xepMbzkhHJ4zURqHiyY3EiIRuYu4ONJKCxt8iqA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.3.0.tgz", + "integrity": "sha512-LXZAExpepJew0Gp8ZkJ+xDZaTQjLHv48h0p0Vw2VMFQ8A+RKrAvpFuPVCVwKJCr5SE+zvaG+Etg56qXvTDIedw==", "cpu": [ "arm64" ], @@ -1731,9 +1816,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.2.0.tgz", - "integrity": "sha512-xJvJ7R2wJdi47WZBFS691RDOWvP1j/IAs3EXaWVhDI8FFITbWrWaln7KoNcR0Y3T+ZwimFY/cfb0PNht1q895g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.3.0.tgz", + "integrity": "sha512-P7Wo91lKSeSgMTtG7CnBS6WrA5otr1K7shhSjKHNePVmfBHDoAOHYRXgUmhiNfbcGk0uMCHVcdbfxtuiZCHVow==", "cpu": [ "x64" ], @@ -1751,9 +1836,9 @@ } }, "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.2.0.tgz", - "integrity": "sha512-D+NMpgr23a+RI5mu8ZPKWy7AqjBOkURFDgP5iIXXEf/K3hm0jJ3ogzi0Ed2237B/CdYREimCgXyeiAlE/FtwyA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.3.0.tgz", + "integrity": "sha512-+kiRE1JIq8QdxzwoYY+wzBs9YbJ34guBweTK8nlzLKimn5EQ2b2FSC+tAOpq302BuIMjyuUGvBiUhEcLIGMQ5g==", "cpu": [ "x64" ], @@ -1771,9 +1856,9 @@ } }, "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.2.0.tgz", - "integrity": "sha512-z225cPn3aygJsyVUOWwfyW+fY0Tvk7N3XCOl66qUPFxpbuXeZuiuuJemmtm8vxyqa3Ur7peU/qJxrpC64aeI7Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.3.0.tgz", + "integrity": "sha512-35gXCnaz1AqIXpG42evcoP2+sNL62gZTMZne3IackM+6QlfMcJLy3DrjuL6Iks7Czpd3j4xRBzez3ADCj1l7Aw==", "cpu": [ "arm64" ], @@ -1790,10 +1875,30 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.3.0.tgz", + "integrity": "sha512-FJS/IBQHhRpZ6PiCjFt1UAcPr0YmCLHRbTc00IBTrelEjlmmgIVLeOx4MSXzx2HFEy5Jo5YdhGpxCuqCyDJ5ow==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.2.0.tgz", - "integrity": "sha512-JqGW0RJ61BkKx+yYzIURt9s53P7xMVbv0uxYPzAXLBINGaFmkIKSuUPyBVfy8TMbvp93lvF4SPBNDzVRJfvgOw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.3.0.tgz", + "integrity": "sha512-dLx+0XRdMnVI62kU3wbXvbIRhLck4aE28bIGKbRGS7BJNt54IIj9+c/Dkqb+7DJEbHUZAX1bwaoM8PqVlHJmCA==", "cpu": [ "x64" ], @@ -1835,11 +1940,15 @@ } }, "node_modules/@swc/core": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.74.tgz", - "integrity": "sha512-P+MIExOTdWlfq8Heb1/NhBAke6UTckd4cRDuJoFcFMGBRvgoCMNWhnfP3FRRXPLI7GGg27dRZS+xHiqYyQmSrA==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.91.tgz", + "integrity": "sha512-r950d0fdlZ8qbSDyvApn3HyCojiZE8xpgJzQvypeMi32dalYwugdJKWyLB55JIGMRGJ8+lmVvY4MPGkSR3kXgA==", "dev": true, "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.1", + "@swc/types": "^0.1.5" + }, "engines": { "node": ">=10" }, @@ -1848,16 +1957,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.74", - "@swc/core-darwin-x64": "1.3.74", - "@swc/core-linux-arm-gnueabihf": "1.3.74", - "@swc/core-linux-arm64-gnu": "1.3.74", - "@swc/core-linux-arm64-musl": "1.3.74", - "@swc/core-linux-x64-gnu": "1.3.74", - "@swc/core-linux-x64-musl": "1.3.74", - "@swc/core-win32-arm64-msvc": "1.3.74", - "@swc/core-win32-ia32-msvc": "1.3.74", - "@swc/core-win32-x64-msvc": "1.3.74" + "@swc/core-darwin-arm64": "1.3.91", + "@swc/core-darwin-x64": "1.3.91", + "@swc/core-linux-arm-gnueabihf": "1.3.91", + "@swc/core-linux-arm64-gnu": "1.3.91", + "@swc/core-linux-arm64-musl": "1.3.91", + "@swc/core-linux-x64-gnu": "1.3.91", + "@swc/core-linux-x64-musl": "1.3.91", + "@swc/core-win32-arm64-msvc": "1.3.91", + "@swc/core-win32-ia32-msvc": "1.3.91", + "@swc/core-win32-x64-msvc": "1.3.91" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -1869,9 +1978,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.74.tgz", - "integrity": "sha512-2rMV4QxM583jXcREfo0MhV3Oj5pgRSfSh/kVrB1twL2rQxOrbzkAPT/8flmygdVoL4f2F7o1EY5lKlYxEBiIKQ==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.91.tgz", + "integrity": "sha512-7kHGiQ1he5khcEeJuHDmLZPM3rRL/ith5OTmV6bOPsoHi46kLeixORW+ts1opC3tC9vu6xbk16xgX0QAJchc1w==", "cpu": [ "arm64" ], @@ -1885,9 +1994,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.74.tgz", - "integrity": "sha512-KKEGE1wXneYXe15fWDRM8/oekd/Q4yAuccA0vWY/7i6nOSPqWYcSDR0nRtR030ltDxWt0rk/eCTmNkrOWrKs3A==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.91.tgz", + "integrity": "sha512-8SpU18FbFpZDVzsHsAwdI1thF/picQGxq9UFxa8W+T9SDnbsqwFJv/6RqKJeJoDV6qFdl2OLjuO0OL7xrp0qnQ==", "cpu": [ "x64" ], @@ -1901,9 +2010,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.74.tgz", - "integrity": "sha512-HehH5DR6r/5fIVu7tu8ZqgrHkhSCQNewf1ztFQJgcmaQWn+H4AJERBjwkjosqh4TvUJucZv8vyRTvrFeBXaCSA==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.91.tgz", + "integrity": "sha512-fOq4Cy8UbwX1yf0WB0d8hWZaIKCnPtPGguRqdXGLfwvhjZ9SIErT6PnmGTGRbQCNCIkOZWHKyTU0r8t2dN3haQ==", "cpu": [ "arm" ], @@ -1917,9 +2026,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.74.tgz", - "integrity": "sha512-+xkbCRz/wczgdknoV4NwYxbRI2dD7x/qkIFcVM2buzLCq8oWLweuV8+aL4pRqu0qDh7ZSb1jcaVTUIsySCJznA==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.91.tgz", + "integrity": "sha512-fki4ioRP/Esy4vdp8T34RCV+V9dqkRmOt763pf74pdiyFV2dPLXa5lnw/XvR1RTfPGknrYgjEQLCfZlReTryRw==", "cpu": [ "arm64" ], @@ -1933,9 +2042,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.74.tgz", - "integrity": "sha512-maKFZSCD3tQznzPV7T3V+TtiWZFEFM8YrnSS5fQNNb+K9J65sL+170uTb3M7H4cFkG+9Sm5k5yCrCIutlvV48g==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.91.tgz", + "integrity": "sha512-XrG+DUUqNtfVLcJ20imby7fpBwQNG5VsEQBzQndSonPyUOa2YkTbBb60YDondfQGDABopuHH8gHN8o2H2/VCnQ==", "cpu": [ "arm64" ], @@ -1949,9 +2058,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.74.tgz", - "integrity": "sha512-LEXpcShF6DLTWJSiBhMSYZkLQ27UvaQ24fCFhoIV/R3dhYaUpHmIyLPPBNC82T03lB3ONUFVwrRw6fxDJ/f00A==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.91.tgz", + "integrity": "sha512-d11bYhX+YPBr/Frcjc6eVn3C0LuS/9U1Li9EmQ+6s9EpYtYRl2ygSlC8eueLbaiazBnCVYFnc8bU4o0kc5B9sw==", "cpu": [ "x64" ], @@ -1965,9 +2074,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.74.tgz", - "integrity": "sha512-sxsFctbFMZEFmDE7CmYljG0dMumH8XBTwwtGr8s6z0fYAzXBGNq2AFPcmEh2np9rPWkt7pE1m0ByESD+dMkbxQ==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.91.tgz", + "integrity": "sha512-2SRp5Dke2P4jCQePkDx9trkkTstnRpZJVw5r3jvYdk0zeO6iC4+ZPvvoWXJLigqQv/fZnIiSUfJ6ssOoaEqTzQ==", "cpu": [ "x64" ], @@ -1981,9 +2090,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.74.tgz", - "integrity": "sha512-F7hY9/BjFCozA4YPFYFH5FGCyWwa44vIXHqG66F5cDwXDGFn8ZtBsYIsiPfUYcx0AeAo1ojnVWKPxokZhYNYqA==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.91.tgz", + "integrity": "sha512-l9qKXikOxj42UIjbeZpz9xtBmr736jOMqInNP8mVF2/U+ws5sI8zJjcOFFtfis4ru7vWCXhB1wtltdlJYO2vGA==", "cpu": [ "arm64" ], @@ -1997,9 +2106,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.74.tgz", - "integrity": "sha512-qBAsiD1AlIdqED6wy3UNRHyAys9pWMUidX0LJ6mj24r/vfrzzTBAUrLJe5m7bzE+F1Rgi001avYJeEW1DLEJ+Q==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.91.tgz", + "integrity": "sha512-+s+52O0QVPmzOgjEe/rcb0AK6q/J7EHKwAyJCu/FaYO9df5ovE0HJjSKP6HAF0dGPO5hkENrXuNGujofUH9vtQ==", "cpu": [ "ia32" ], @@ -2013,9 +2122,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.74", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.74.tgz", - "integrity": "sha512-S3YAvvLprTnPRwQuy9Dkwubb5SRLpVK3JJsqYDbGfgj8PGQyKHZcVJ5X3nfFsoWLy3j9B/3Os2nawprRSzeC5A==", + "version": "1.3.91", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.91.tgz", + "integrity": "sha512-7u9HDQhjUC3Gv43EFW84dZtduWCSa4MgltK+Sp9zEGti6WXqDPu/ESjvDsQEVYTBEMEvZs/xVAXPgLVHorV5nQ==", "cpu": [ "x64" ], @@ -2028,15 +2137,27 @@ "node": ">=10" } }, + "node_modules/@swc/counter": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.2.tgz", + "integrity": "sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==", + "dev": true + }, "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "dev": true, "dependencies": { "tslib": "^2.4.0" } }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", + "dev": true + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -2047,9 +2168,9 @@ } }, "node_modules/@types/chrome": { - "version": "0.0.243", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.243.tgz", - "integrity": "sha512-4PHv0kxxxpZFHWPBiJJ9TWH8kbx0567j1b2djnhpJjpiSGNI7UKkz7dSEECBtQ0B3N5nQTMwSB/5IopkWGAbEA==", + "version": "0.0.246", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.246.tgz", + "integrity": "sha512-MxGxEomGxsJiL9xe/7ZwVgwdn8XVKWbPvxpVQl3nWOjrS0Ce63JsfzxUc4aU3GvRcUPYsfufHmJ17BFyKxeA4g==", "dev": true, "dependencies": { "@types/filesystem": "*", @@ -2057,45 +2178,45 @@ } }, "node_modules/@types/filesystem": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.32.tgz", - "integrity": "sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==", + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.33.tgz", + "integrity": "sha512-2KedRPzwu2K528vFkoXnnWdsG0MtUwPjuA7pRy4vKxlxHEe8qUDZibYHXJKZZr2Cl/ELdCWYqyb/MKwsUuzBWw==", "dev": true, "dependencies": { "@types/filewriter": "*" } }, "node_modules/@types/filewriter": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.29.tgz", - "integrity": "sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ==", + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.30.tgz", + "integrity": "sha512-lB98tui0uxc7erbj0serZfJlHKLNJHwBltPnbmO1WRpL5T325GOHRiQfr2E29V2q+S1brDO63Fpdt6vb3bES9Q==", "dev": true }, "node_modules/@types/har-format": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.11.tgz", - "integrity": "sha512-T232/TneofqK30AD1LRrrf8KnjLvzrjWDp7eWST5KoiSzrBfRsLrWDPk4STQPW4NZG6v2MltnduBVmakbZOBIQ==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.13.tgz", + "integrity": "sha512-PwBsCBD3lDODn4xpje3Y1di0aDJp4Ww7aSfMRVw6ysnxD4I7Wmq2mBkSKaDtN403hqH5sp6c9xQUvFYY3+lkBg==", "dev": true }, "node_modules/@types/ip": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.0.tgz", - "integrity": "sha512-dwNe8gOoF70VdL6WJBwVHtQmAX4RMd62M+mAB9HQFjG1/qiCLM/meRy95Pd14FYBbEDwCq7jgJs89cHpLBu4HQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/ip/-/ip-1.1.1.tgz", + "integrity": "sha512-/v+XZuKNBQHJi3dKeFt9LySLzWNkgmaYRtnFfg27Ag0MO9tQLzHUuAA8zOhPtbDvDGkcnZGr4pVZQPGNft/WYA==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/node": { - "version": "20.4.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.6.tgz", - "integrity": "sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA==", + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", "dev": true }, "node_modules/@types/webextension-polyfill": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.1.tgz", - "integrity": "sha512-Sdg+E2F5JUbhkE1qX15QUxpyhfMFKRGJqND9nb1C0gNN4NR7kCV31/1GvNbg6Xe+m/JElJ9/lG5kepMzjGPuQw==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.4.tgz", + "integrity": "sha512-pvEIqAZEbJRzaqTaWq3xlUoMWa3+euZHHz+VZHCzHWW+jOf8qLOq9wXy38U+WiPG3108SJC/wNc1X6vPC5TcjQ==", "dev": true }, "node_modules/abortcontroller-polyfill": { @@ -2194,9 +2315,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", "dev": true, "funding": [ { @@ -2213,10 +2334,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -2259,9 +2380,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001519", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", - "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", + "version": "1.0.30001542", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001542.tgz", + "integrity": "sha512-UrtAXVcj1mvPBFQ4sKd38daP8dEcXXr5sQe6QNNinaPd0iA/cxg9/l3VrSdL73jgw5sKyuQ6jNgiKO12W3SsVA==", "dev": true, "funding": [ { @@ -2355,14 +2476,14 @@ } }, "node_modules/cosmiconfig": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", - "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "dependencies": { - "import-fresh": "^3.2.1", + "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", + "parse-json": "^5.2.0", "path-type": "^4.0.0" }, "engines": { @@ -2370,12 +2491,20 @@ }, "funding": { "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/css-declaration-sorter": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.0.3.tgz", - "integrity": "sha512-/PHObPdiAXf0H3LOZCyXgBLt5fiS5XGCml/Ylpkmr7ADgq94GffvdGxJEmsSLDo0XGzItJY79dusRka0e4UVLw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.1.1.tgz", + "integrity": "sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==", "dev": true, "engines": { "node": "^14 || ^16 || >=18" @@ -2623,9 +2752,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.482", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.482.tgz", - "integrity": "sha512-h+UqpfmEr1Qkk0zp7ej/jid7CXoq4m4QzW6wNTb0ELJ/BZCpA4wgUylBIMGCe621tnr4l5VmoHjdoSx2lbnNJA==", + "version": "1.4.539", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.539.tgz", + "integrity": "sha512-wRmWJ8F7rgmINuI32S6r2SLrw/h/bJQsDSvBiq9GBfvc2Lh73qTOwn73r3Cf67mjVgFGJYcYtmERzySa5jIWlg==", "dev": true }, "node_modules/entities": { @@ -2721,9 +2850,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2895,9 +3024,9 @@ "dev": true }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -2979,9 +3108,9 @@ } }, "node_modules/lightningcss": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.5.tgz", - "integrity": "sha512-/pEUPeih2EwIx9n4T82aOG6CInN83tl/mWlw6B5gWLf36UplQi1L+5p3FUHsdt4fXVfOkkh9KIaM3owoq7ss8A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.22.0.tgz", + "integrity": "sha512-+z0qvwRVzs4XGRXelnWRNwqsXUx8k3bSkbP8vD42kYKSk3z9OM2P3e/gagT7ei/gwh8DTS80LZOFZV6lm8Z8Fg==", "dev": true, "dependencies": { "detect-libc": "^1.0.3" @@ -2994,20 +3123,21 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.21.5", - "lightningcss-darwin-x64": "1.21.5", - "lightningcss-linux-arm-gnueabihf": "1.21.5", - "lightningcss-linux-arm64-gnu": "1.21.5", - "lightningcss-linux-arm64-musl": "1.21.5", - "lightningcss-linux-x64-gnu": "1.21.5", - "lightningcss-linux-x64-musl": "1.21.5", - "lightningcss-win32-x64-msvc": "1.21.5" + "lightningcss-darwin-arm64": "1.22.0", + "lightningcss-darwin-x64": "1.22.0", + "lightningcss-freebsd-x64": "1.22.0", + "lightningcss-linux-arm-gnueabihf": "1.22.0", + "lightningcss-linux-arm64-gnu": "1.22.0", + "lightningcss-linux-arm64-musl": "1.22.0", + "lightningcss-linux-x64-gnu": "1.22.0", + "lightningcss-linux-x64-musl": "1.22.0", + "lightningcss-win32-x64-msvc": "1.22.0" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.5.tgz", - "integrity": "sha512-z05hyLX85WY0UfhkFUOrWEFqD69lpVAmgl3aDzMKlIZJGygbhbegqb4PV8qfUrKKNBauut/qVNPKZglhTaDDxA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.22.0.tgz", + "integrity": "sha512-aH2be3nNny+It5YEVm8tBSSdRlBVWQV8m2oJ7dESiYRzyY/E/bQUe2xlw5caaMuhlM9aoTMtOH25yzMhir0qPg==", "cpu": [ "arm64" ], @@ -3025,9 +3155,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.5.tgz", - "integrity": "sha512-MSJhmej/U9MrdPxDk7+FWhO8+UqVoZUHG4VvKT5RQ4RJtqtANTiWiI97LvoVNMtdMnHaKs1Pkji6wHUFxjJsHQ==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.22.0.tgz", + "integrity": "sha512-9KHRFA0Y6mNxRHeoQMp0YaI0R0O2kOgUlYPRjuasU4d+pI8NRhVn9bt0yX9VPs5ibWX1RbDViSPtGJvYYrfVAQ==", "cpu": [ "x64" ], @@ -3044,10 +3174,30 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.22.0.tgz", + "integrity": "sha512-xaYL3xperGwD85rQioDb52ozF3NAJb+9wrge3jD9lxGffplu0Mn35rXMptB8Uc2N9Mw1i3Bvl7+z1evlqVl7ww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.5.tgz", - "integrity": "sha512-xN6+5/JsMrbZHL1lPl+MiNJ3Xza12ueBKPepiyDCFQzlhFRTj7D0LG+cfNTzPBTO8KcYQynLpl1iBB8LGp3Xtw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.22.0.tgz", + "integrity": "sha512-epQGvXIjOuxrZpMpMnRjK54ZqzhiHhCPLtHvw2fb6NeK2kK9YtF0wqmeTBiQ1AkbWfnnXGTstYaFNiadNK+StQ==", "cpu": [ "arm" ], @@ -3065,9 +3215,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.5.tgz", - "integrity": "sha512-KfzFNhC4XTbmG3ma/xcTs/IhCwieW89XALIusKmnV0N618ZDXEB0XjWOYQRCXeK9mfqPdbTBpurEHV/XZtkniQ==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.22.0.tgz", + "integrity": "sha512-AArGtKSY4DGTA8xP8SDyNyKtpsUl1Rzq6FW4JomeyUQ4nBrR71uPChksTpj3gmWuGhZeRKLeCUI1DBid/zhChg==", "cpu": [ "arm64" ], @@ -3085,9 +3235,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.5.tgz", - "integrity": "sha512-bc0GytQO5Mn9QM6szaZ+31fQHNdidgpM1sSCwzPItz8hg3wOvKl8039rU0veMJV3ZgC9z0ypNRceLrSHeRHmXw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.22.0.tgz", + "integrity": "sha512-RRraNgP8hnBPhInTTUdlFm+z16C/ghbxBG51Sw00hd7HUyKmEUKRozyc5od+/N6pOrX/bIh5vIbtMXIxsos0lg==", "cpu": [ "arm64" ], @@ -3105,9 +3255,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.5.tgz", - "integrity": "sha512-JwMbgypPQgc2kW2av3OwzZ8cbrEuIiDiXPJdXRE6aVxu67yHauJawQLqJKTGUhiAhy6iLDG8Wg0a3/ziL+m+Kw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.22.0.tgz", + "integrity": "sha512-grdrhYGRi2KrR+bsXJVI0myRADqyA7ekprGxiuK5QRNkv7kj3Yq1fERDNyzZvjisHwKUi29sYMClscbtl+/Zpw==", "cpu": [ "x64" ], @@ -3125,9 +3275,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.5.tgz", - "integrity": "sha512-Ib8b6IQ/OR/VrPU6YBgy4T3QnuHY7DUa95O+nz+cwrTkMSN6fuHcTcIaz4t8TJ6HI5pl3uxUOZjmtls2pyQWow==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.22.0.tgz", + "integrity": "sha512-t5f90X+iQUtIyR56oXIHMBUyQFX/zwmPt72E6Dane3P8KNGlkijTg2I75XVQS860gNoEFzV7Mm5ArRRA7u5CAQ==", "cpu": [ "x64" ], @@ -3145,9 +3295,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.5.tgz", - "integrity": "sha512-A8cSi8lUpBeVmoF+DqqW7cd0FemDbCuKr490IXdjyeI+KL8adpSKUs8tcqO0OXPh1EoDqK7JNkD/dELmd4Iz5g==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.22.0.tgz", + "integrity": "sha512-64HTDtOOZE9PUCZJiZZQpyqXBbdby1lnztBccnqh+NtbKxjnGzP92R2ngcgeuqMPecMNqNWxgoWgTGpC+yN5Sw==", "cpu": [ "x64" ], @@ -3265,9 +3415,9 @@ } }, "node_modules/msgpackr": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.6.tgz", - "integrity": "sha512-50rmb6+ZWvEm0vJn8R8CwI1Eavss3h5rgtKrcdUal3EkZcpqw82+xsmc7RoHb8fYB5V4EOU2NDaOitDAdO0t+w==", + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.9.tgz", + "integrity": "sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A==", "dev": true, "optionalDependencies": { "msgpackr-extract": "^3.0.2" @@ -3492,9 +3642,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -3532,9 +3682,9 @@ } }, "node_modules/postcss-scss": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.6.tgz", - "integrity": "sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==", + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", "dev": true, "funding": [ { @@ -3544,13 +3694,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "engines": { "node": ">=12.0" }, "peerDependencies": { - "postcss": "^8.4.19" + "postcss": "^8.4.29" } }, "node_modules/postcss-value-parser": { @@ -3695,12 +3849,12 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", "dev": true, "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -3912,9 +4066,9 @@ } }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/type-fest": { @@ -3930,9 +4084,9 @@ } }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -3943,9 +4097,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 9f8380b5..db0806bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ttv-lol-pro", - "version": "2.1.6", + "version": "2.2.0", "description": "TTV LOL PRO removes most livestream ads from Twitch.", "@parcel/bundler-default": { "minBundles": 10000000, @@ -24,6 +24,7 @@ "dev:chromium": "parcel src/manifest.json --host localhost --target webext-dev --no-hmr", "lint": "prettier --check .", "lint:fix": "prettier --write .", + "type-check": "tsc --noEmit", "prebuild:firefox": "npm run clean && shx cp src/manifest.firefox.json src/manifest.json", "prebuild:chromium": "npm run clean && shx cp src/manifest.chromium.json src/manifest.json", "build:firefox": "parcel build src/manifest.json --target webext-prod --no-source-maps", @@ -46,18 +47,18 @@ }, "devDependencies": { "@parcel/config-webextension": "^2.9.3", - "@types/chrome": "^0.0.243", - "@types/ip": "^1.1.0", - "@types/webextension-polyfill": "^0.10.1", + "@types/chrome": "^0.0.246", + "@types/ip": "^1.1.1", + "@types/webextension-polyfill": "^0.10.4", "buffer": "^6.0.3", "os-browserify": "^0.3.0", "parcel": "^2.9.3", - "postcss": "^8.4.27", + "postcss": "^8.4.31", "prettier": "2.8.8", "prettier-plugin-css-order": "^1.3.1", "prettier-plugin-organize-imports": "^3.2.3", "shx": "^0.3.4", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "webextension-polyfill": "^0.10.0" }, "private": true diff --git a/src/background/background.ts b/src/background/background.ts index abcde524..8db61947 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -5,6 +5,7 @@ import onAuthRequired from "./handlers/onAuthRequired"; import onBeforeSendHeaders from "./handlers/onBeforeSendHeaders"; import onBeforeVideoWeaverRequest from "./handlers/onBeforeVideoWeaverRequest"; import onProxyRequest from "./handlers/onProxyRequest"; +import onProxySettingsChange from "./handlers/onProxySettingsChanged"; import onResponseStarted from "./handlers/onResponseStarted"; import onStartupStoreCleanup from "./handlers/onStartupStoreCleanup"; import onTabCreated from "./handlers/onTabCreated"; @@ -29,6 +30,9 @@ browser.webRequest.onResponseStarted.addListener(onResponseStarted, { }); if (isChromium) { + // Listen to whether proxy is set or not. + browser.proxy.settings.onChange.addListener(onProxySettingsChange); + // Check if there are any opened Twitch tabs on startup. checkForOpenedTwitchTabs(); diff --git a/src/background/handlers/checkForOpenedTwitchTabs.ts b/src/background/handlers/checkForOpenedTwitchTabs.ts index 18491c93..485f9eae 100644 --- a/src/background/handlers/checkForOpenedTwitchTabs.ts +++ b/src/background/handlers/checkForOpenedTwitchTabs.ts @@ -1,4 +1,5 @@ import browser from "webextension-polyfill"; +import areAllTabsWhitelisted from "../../common/ts/areAllTabsWhitelisted"; import isChromium from "../../common/ts/isChromium"; import { clearProxySettings, @@ -13,17 +14,16 @@ export default function checkForOpenedTwitchTabs() { browser.tabs .query({ url: ["https://www.twitch.tv/*", "https://m.twitch.tv/*"] }) .then(tabs => { - const tabsIds = tabs.filter(tab => tab.id != null).map(tab => tab.id!); - if (tabsIds.length === 0) { - if (isChromium) clearProxySettings(); - return; - } - console.log( - `🔍 Found ${tabsIds.length} opened Twitch tabs: ${tabsIds.join(", ")}` - ); + console.log(`🔍 Found ${tabs.length} opened Twitch tabs.`); + store.state.openedTwitchTabs = tabs; + if (isChromium) { - updateProxySettings(); + const allTabsAreWhitelisted = areAllTabsWhitelisted(tabs); + if (tabs.length > 0 && !allTabsAreWhitelisted) { + updateProxySettings(); + } else { + clearProxySettings(); + } } - store.state.openedTwitchTabs = tabsIds; }); } diff --git a/src/background/handlers/onBeforeVideoWeaverRequest.ts b/src/background/handlers/onBeforeVideoWeaverRequest.ts index 9768f893..30adcbf9 100644 --- a/src/background/handlers/onBeforeVideoWeaverRequest.ts +++ b/src/background/handlers/onBeforeVideoWeaverRequest.ts @@ -1,5 +1,6 @@ import { WebRequest } from "webextension-polyfill"; import filterResponseDataWrapper from "../../common/ts/filterResponseDataWrapper"; +import findChannelFromTwitchTvUrl from "../../common/ts/findChannelFromTwitchTvUrl"; import findChannelFromVideoWeaverUrl from "../../common/ts/findChannelFromVideoWeaverUrl"; import getHostFromUrl from "../../common/ts/getHostFromUrl"; import { videoWeaverHostRegex } from "../../common/ts/regexes"; @@ -23,50 +24,46 @@ export default function onBeforeVideoWeaverRequest( const textLower = text.toLowerCase(); const isAd = textLower.includes(adSignifier); const isMidroll = textLower.includes(midrollSignifier); + if (!isAd && !isMidroll) return text; - if (isAd || isMidroll) { - const adType: AdType = isMidroll ? AdType.MIDROLL : AdType.PREROLL; - const channel = findChannelFromVideoWeaverUrl(details.url); - const isPurpleScreen = textLower.includes( - "https://help.twitch.tv/s/article/ad-experience-on-twitch" - ); - let proxy: string | null = null; - if (details.proxyInfo && details.proxyInfo.type !== "direct") { - proxy = `${details.proxyInfo.host}:${details.proxyInfo.port}`; - } - const proxyTwitchWebpage = store.state.proxyTwitchWebpage; - const proxyUsherRequests = store.state.proxyUsherRequests; - const timestamp = details.timeStamp; - const videoWeaverHost = host; - const videoWeaverUrl = details.url; + const isDuplicate = store.state.adLog.some( + entry => + entry.videoWeaverUrl === details.url && + details.timeStamp - entry.timestamp < 1000 * 30 // 30 seconds + ); + if (isDuplicate) return text; - const isDuplicate = store.state.adLog.some( - entry => - entry.videoWeaverUrl === videoWeaverUrl && - timestamp - entry.timestamp < 1000 * 30 // 30 seconds - ); - if (isDuplicate) return text; + const channelName = + findChannelFromVideoWeaverUrl(details.url) ?? + findChannelFromTwitchTvUrl(details.documentUrl); + const isPurpleScreen = textLower.includes( + "https://help.twitch.tv/s/article/ad-experience-on-twitch" + ); + const proxy = + details.proxyInfo && details.proxyInfo.type !== "direct" + ? `${details.proxyInfo.host}:${details.proxyInfo.port}` + : null; - const adLog = store.state.adLog.filter( - entry => timestamp - entry.timestamp < 1000 * 60 * 60 * 24 * 7 // 7 days - ); - store.state.adLog = [ - ...adLog, - { - adType, - channel, - isPurpleScreen, - proxy, - proxyTwitchWebpage, - proxyUsherRequests, - timestamp, - videoWeaverHost, - videoWeaverUrl, - }, - ]; - console.log(`📝 Ad log updated (${adLog.length + 1} entries).`); - console.log(text); - } + const adLog = store.state.adLog.filter( + entry => details.timeStamp - entry.timestamp < 1000 * 60 * 60 * 24 * 7 // 7 days + ); + store.state.adLog = [ + ...adLog, + { + adType: isMidroll ? AdType.MIDROLL : AdType.PREROLL, + channel: channelName, + isPurpleScreen, + proxy, + proxyTwitchWebpage: store.state.proxyTwitchWebpage, + proxyUsherRequests: store.state.proxyUsherRequests, + anonymousMode: store.state.anonymousMode, + timestamp: details.timeStamp, + videoWeaverHost: host, + videoWeaverUrl: details.url, + }, + ]; + console.log(`📝 Ad log updated (${store.state.adLog.length} entries).`); + console.log(text); return text; }); diff --git a/src/background/handlers/onProxyRequest.ts b/src/background/handlers/onProxyRequest.ts index a73bf9f2..61fd95d2 100644 --- a/src/background/handlers/onProxyRequest.ts +++ b/src/background/handlers/onProxyRequest.ts @@ -1,4 +1,5 @@ import { Proxy } from "webextension-polyfill"; +import findChannelFromTwitchTvUrl from "../../common/ts/findChannelFromTwitchTvUrl"; import findChannelFromUsherUrl from "../../common/ts/findChannelFromUsherUrl"; import findChannelFromVideoWeaverUrl from "../../common/ts/findChannelFromVideoWeaverUrl"; import getHostFromUrl from "../../common/ts/getHostFromUrl"; @@ -21,6 +22,12 @@ export default async function onProxyRequest( const host = getHostFromUrl(details.url); if (!host) return { type: "direct" }; + const documentHost = details.documentUrl + ? getHostFromUrl(details.documentUrl) + : null; + const isFromTwitchTvHost = + documentHost && twitchTvHostRegex.test(documentHost); + // Wait for the store to be ready. if (store.readyState !== "complete") { await new Promise(resolve => { @@ -73,6 +80,13 @@ export default async function onProxyRequest( // Usher requests. if (store.state.proxyUsherRequests && usherHostRegex.test(host)) { + // Don't proxy Usher requests from non-supported hosts. + if (!isFromTwitchTvHost) { + console.log( + `✋ '${details.url}' from host '${documentHost}' is not supported.` + ); + return { type: "direct" }; + } // Don't proxy whitelisted channels. const channelName = findChannelFromUsherUrl(details.url); if (isChannelWhitelisted(channelName)) { @@ -89,8 +103,17 @@ export default async function onProxyRequest( // Video Weaver requests. if (videoWeaverHostRegex.test(host) && isFlagged) { + // Don't proxy Video Weaver requests from non-supported hosts. + if (!isFromTwitchTvHost) { + console.log( + `✋ '${details.url}' from host '${documentHost}' is not supported.` + ); + return { type: "direct" }; + } // Don't proxy whitelisted channels. - const channelName = findChannelFromVideoWeaverUrl(details.url); + const channelName = + findChannelFromVideoWeaverUrl(details.url) ?? + findChannelFromTwitchTvUrl(details.documentUrl); if (isChannelWhitelisted(channelName)) { console.log(`✋ Channel '${channelName}' is whitelisted.`); return { type: "direct" }; diff --git a/src/background/handlers/onProxySettingsChanged.ts b/src/background/handlers/onProxySettingsChanged.ts new file mode 100644 index 00000000..49735710 --- /dev/null +++ b/src/background/handlers/onProxySettingsChanged.ts @@ -0,0 +1,10 @@ +import { Types } from "webextension-polyfill"; +import store from "../../store"; + +export default function onProxySettingsChange( + details: Types.SettingOnChangeDetailsType +) { + console.log(`⚙️ Proxy settings changed: ${details.levelOfControl}`); + store.state.chromiumProxyActive = + details.levelOfControl == "controlled_by_this_extension"; +} diff --git a/src/background/handlers/onResponseStarted.ts b/src/background/handlers/onResponseStarted.ts index df121a76..f70a2c51 100644 --- a/src/background/handlers/onResponseStarted.ts +++ b/src/background/handlers/onResponseStarted.ts @@ -1,4 +1,5 @@ import { WebRequest } from "webextension-polyfill"; +import findChannelFromTwitchTvUrl from "../../common/ts/findChannelFromTwitchTvUrl"; import findChannelFromVideoWeaverUrl from "../../common/ts/findChannelFromVideoWeaverUrl"; import getHostFromUrl from "../../common/ts/getHostFromUrl"; import getProxyInfoFromUrl from "../../common/ts/getProxyInfoFromUrl"; @@ -48,7 +49,9 @@ export default function onResponseStarted( // Video-weaver requests. if (videoWeaverHostRegex.test(host)) { - const channelName = findChannelFromVideoWeaverUrl(details.url); + const channelName = + findChannelFromVideoWeaverUrl(details.url) ?? + findChannelFromTwitchTvUrl(details.documentUrl); const streamStatus = getStreamStatus(channelName); const stats = streamStatus?.stats ?? { proxied: 0, notProxied: 0 }; if (!proxy) { diff --git a/src/background/handlers/onStartupStoreCleanup.ts b/src/background/handlers/onStartupStoreCleanup.ts index 15c88c1e..af1d2c2b 100644 --- a/src/background/handlers/onStartupStoreCleanup.ts +++ b/src/background/handlers/onStartupStoreCleanup.ts @@ -12,6 +12,7 @@ export default function onStartupStoreCleanup(): void { if (store.readyState !== "complete") return store.addEventListener("load", onStartupStoreCleanup); + store.state.chromiumProxyActive = false; store.state.dnsResponses = []; store.state.openedTwitchTabs = []; store.state.streamStatuses = {}; diff --git a/src/background/handlers/onTabCreated.ts b/src/background/handlers/onTabCreated.ts index 9cb7e94b..31c5c7a1 100644 --- a/src/background/handlers/onTabCreated.ts +++ b/src/background/handlers/onTabCreated.ts @@ -1,18 +1,33 @@ import { Tabs } from "webextension-polyfill"; +import findChannelFromTwitchTvUrl from "../../common/ts/findChannelFromTwitchTvUrl"; import getHostFromUrl from "../../common/ts/getHostFromUrl"; +import isChannelWhitelisted from "../../common/ts/isChannelWhitelisted"; import isChromium from "../../common/ts/isChromium"; import { updateProxySettings } from "../../common/ts/proxySettings"; import { twitchTvHostRegex } from "../../common/ts/regexes"; import store from "../../store"; export default function onTabCreated(tab: Tabs.Tab): void { - if (!tab.url || tab.id == null) return; - const host = getHostFromUrl(tab.url); - if (host != null && twitchTvHostRegex.test(host)) { + const url = tab.url || tab.pendingUrl; + if (!url) return; + const host = getHostFromUrl(url); + if (!host) return; + + // TODO: `twitchTvHostRegex` doesn't match `appeals.twitch.tv` and + // `dashboard.twitch.tv` which means that passport requests from those + // subdomains will not be proxied. This could mess up the cookie country. + if (twitchTvHostRegex.test(host)) { console.log(`➕ Opened Twitch tab: ${tab.id}`); - if (isChromium && store.state.openedTwitchTabs.length === 0) { - updateProxySettings(); + store.state.openedTwitchTabs.push(tab); + + if (isChromium) { + const channelName = findChannelFromTwitchTvUrl(url); + const isWhitelisted = channelName + ? isChannelWhitelisted(channelName) + : false; + if (!isWhitelisted && !store.state.chromiumProxyActive) { + updateProxySettings(); + } } - store.state.openedTwitchTabs.push(tab.id); } } diff --git a/src/background/handlers/onTabRemoved.ts b/src/background/handlers/onTabRemoved.ts index 26c81d66..735adf9a 100644 --- a/src/background/handlers/onTabRemoved.ts +++ b/src/background/handlers/onTabRemoved.ts @@ -1,13 +1,23 @@ +import areAllTabsWhitelisted from "../../common/ts/areAllTabsWhitelisted"; import isChromium from "../../common/ts/isChromium"; import { clearProxySettings } from "../../common/ts/proxySettings"; import store from "../../store"; export default function onTabRemoved(tabId: number): void { - const index = store.state.openedTwitchTabs.indexOf(tabId); - if (index !== -1) { - console.log(`➖ Closed Twitch tab: ${tabId}`); - store.state.openedTwitchTabs.splice(index, 1); - if (isChromium && store.state.openedTwitchTabs.length === 0) { + const index = store.state.openedTwitchTabs.findIndex(tab => tab.id === tabId); + if (index === -1) return; + + console.log(`➖ Closed Twitch tab: ${tabId}`); + store.state.openedTwitchTabs.splice(index, 1); + + if (isChromium) { + const allTabsAreWhitelisted = areAllTabsWhitelisted( + store.state.openedTwitchTabs + ); + if ( + (store.state.openedTwitchTabs.length === 0 || allTabsAreWhitelisted) && + store.state.chromiumProxyActive + ) { clearProxySettings(); } } diff --git a/src/background/handlers/onTabUpdated.ts b/src/background/handlers/onTabUpdated.ts index c08aec9b..8d8e3e66 100644 --- a/src/background/handlers/onTabUpdated.ts +++ b/src/background/handlers/onTabUpdated.ts @@ -1,4 +1,5 @@ import { Tabs } from "webextension-polyfill"; +import areAllTabsWhitelisted from "../../common/ts/areAllTabsWhitelisted"; import getHostFromUrl from "../../common/ts/getHostFromUrl"; import isChromium from "../../common/ts/isChromium"; import { @@ -7,35 +8,62 @@ import { } from "../../common/ts/proxySettings"; import { twitchTvHostRegex } from "../../common/ts/regexes"; import store from "../../store"; +import onTabCreated from "./onTabCreated"; +import onTabRemoved from "./onTabRemoved"; export default function onTabUpdated( tabId: number, changeInfo: Tabs.OnUpdatedChangeInfoType, tab: Tabs.Tab ): void { - // Also check for `changeInfo.status === "complete"` because the `url` property - // is not always accurate when navigating to a new page. - if (!(changeInfo.url || changeInfo.status === "complete")) return; + const isPageNavigation = changeInfo.url != null; + // We have to check for `changeInfo.status === "loading"` because + // `changeInfo.url` is incorrect when navigating from Twitch to another + // website. + const isPageLoad = changeInfo.status === "loading"; + if (!isPageNavigation && !isPageLoad) return; - const url = changeInfo.url || tab.url; + const url = changeInfo.url || tab.url || tab.pendingUrl; if (!url) return; const host = getHostFromUrl(url); - const isTwitchTab = host != null && twitchTvHostRegex.test(host); - const wasTwitchTab = store.state.openedTwitchTabs.includes(tabId); + if (!host) return; + const isTwitchTab = twitchTvHostRegex.test(host); + const wasTwitchTab = store.state.openedTwitchTabs.some( + tab => tab.id === tabId + ); + if (!isTwitchTab && !wasTwitchTab) return; + + // Tab created if (isTwitchTab && !wasTwitchTab) { - console.log(`➕ Opened Twitch tab: ${tabId}`); - if (isChromium && store.state.openedTwitchTabs.length === 0) { - updateProxySettings(); - } - store.state.openedTwitchTabs.push(tabId); + onTabCreated(tab); } + + // Tab removed if (!isTwitchTab && wasTwitchTab) { - const index = store.state.openedTwitchTabs.indexOf(tabId); - if (index !== -1) { - console.log(`➖ Closed Twitch tab: ${tabId}`); - store.state.openedTwitchTabs.splice(index, 1); - if (isChromium && store.state.openedTwitchTabs.length === 0) { + onTabRemoved(tabId); + } + + // Tab updated + if (isTwitchTab && wasTwitchTab) { + const index = store.state.openedTwitchTabs.findIndex( + tab => tab.id === tabId + ); + if (index === -1) return; + + console.log(`🟰 Updated Twitch tab: ${tabId}`); + store.state.openedTwitchTabs[index] = tab; + + if (isChromium) { + const allTabsAreWhitelisted = areAllTabsWhitelisted( + store.state.openedTwitchTabs + ); + // We don't check for `store.state.openedTwitchTabs.length === 0` because + // there is always at least one tab open (the one that triggered this + // event). + if (!allTabsAreWhitelisted && !store.state.chromiumProxyActive) { + updateProxySettings(); + } else if (allTabsAreWhitelisted && store.state.chromiumProxyActive) { clearProxySettings(); } } diff --git a/src/common/ts/areAllTabsWhitelisted.ts b/src/common/ts/areAllTabsWhitelisted.ts new file mode 100644 index 00000000..f56bc02b --- /dev/null +++ b/src/common/ts/areAllTabsWhitelisted.ts @@ -0,0 +1,15 @@ +import { Tabs } from "webextension-polyfill"; +import findChannelFromTwitchTvUrl from "./findChannelFromTwitchTvUrl"; +import isChannelWhitelisted from "./isChannelWhitelisted"; + +export default function areAllTabsWhitelisted(tabs: Tabs.Tab[]): boolean { + return tabs.every(tab => { + const url = tab.url || tab.pendingUrl; + if (!url) return false; + const channelName = findChannelFromTwitchTvUrl(url); + const isWhitelisted = channelName + ? isChannelWhitelisted(channelName) + : false; + return isWhitelisted; + }); +} diff --git a/src/common/ts/findChannelFromTwitchTvUrl.ts b/src/common/ts/findChannelFromTwitchTvUrl.ts new file mode 100644 index 00000000..dba40715 --- /dev/null +++ b/src/common/ts/findChannelFromTwitchTvUrl.ts @@ -0,0 +1,17 @@ +import { twitchChannelNameRegex } from "./regexes"; + +/** + * Returns the channel name from a Twitch.tv URL. + * Returns `null` if the URL is not a valid Twitch.tv URL. + * @param twitchTvUrl + * @returns + */ +export default function findChannelFromTwitchTvUrl( + twitchTvUrl: string | undefined +): string | null { + if (!twitchTvUrl) return null; + const match = twitchChannelNameRegex.exec(twitchTvUrl); + if (!match) return null; + const [, channelName] = match; + return channelName; +} diff --git a/src/common/ts/regexes.ts b/src/common/ts/regexes.ts index 5bf2cf3a..99c6131e 100644 --- a/src/common/ts/regexes.ts +++ b/src/common/ts/regexes.ts @@ -1,7 +1,7 @@ export const passportHostRegex = /^passport\.twitch\.tv$/i; export const twitchApiChannelNameRegex = /\/hls\/(.+)\.m3u8/i; export const twitchChannelNameRegex = - /^https?:\/\/(?:www|m)\.twitch\.tv\/(?:videos\/)?(\w+)/i; + /^https?:\/\/(?:www|m)\.twitch\.tv\/(?:videos\/|popout\/)?(\w+)/i; export const twitchGqlHostRegex = /^gql\.twitch\.tv$/i; export const twitchTvHostRegex = /^(?:www|m)\.twitch\.tv$/i; export const usherHostRegex = /^usher\.ttvnw\.net$/i; diff --git a/src/content/content.ts b/src/content/content.ts index 005bfb55..d19bb7e7 100644 --- a/src/content/content.ts +++ b/src/content/content.ts @@ -1,6 +1,7 @@ import pageScriptURL from "url:../page/page.ts"; import workerScriptURL from "url:../page/worker.ts"; -import { twitchChannelNameRegex } from "../common/ts/regexes"; +import findChannelFromTwitchTvUrl from "../common/ts/findChannelFromTwitchTvUrl"; +import isChromium from "../common/ts/isChromium"; import { getStreamStatus, setStreamStatus } from "../common/ts/streamStatus"; import store from "../store"; @@ -8,8 +9,8 @@ console.info("[TTV LOL PRO] 🚀 Content script running."); injectPageScript(); -if (store.readyState === "complete") clearStats(); -else store.addEventListener("load", clearStats); +if (store.readyState === "complete") onStoreReady(); +else store.addEventListener("load", onStoreReady); window.addEventListener("message", onMessage); @@ -18,7 +19,8 @@ function injectPageScript() { const script = document.createElement("script"); script.src = pageScriptURL; // src/page/page.ts script.dataset.params = JSON.stringify({ - workerScriptURL: workerScriptURL, // src/page/worker.ts + isChromium, + workerScriptURL, // src/page/worker.ts }); script.onload = () => script.remove(); // --------------------------------------- @@ -30,19 +32,31 @@ function injectPageScript() { (document.head || document.documentElement).append(script); // Note: Despite what the TS types say, `document.head` can be `null`. } +function onStoreReady() { + // Send store state to page script. + const message = { + type: "StoreReady", + state: JSON.parse(JSON.stringify(store.state)), + }; + window.postMessage({ + type: "PageScriptMessage", + message, + }); + // Clear stats for stream on page load/reload. + clearStats(); +} + /** * Clear stats for stream on page load/reload. * @returns */ function clearStats() { // TODO: Clear stats on navigation. - const match = twitchChannelNameRegex.exec(location.href); - if (!match) return; - const [, streamId] = match; - if (!streamId) return; + const channelName = findChannelFromTwitchTvUrl(location.href); + if (!channelName) return; - if (store.state.streamStatuses.hasOwnProperty(streamId)) { - store.state.streamStatuses[streamId].stats = { + if (store.state.streamStatuses.hasOwnProperty(channelName)) { + store.state.streamStatuses[channelName].stats = { proxied: 0, notProxied: 0, }; diff --git a/src/manifest.chromium.json b/src/manifest.chromium.json index 365e8aa5..7b0d9d7d 100644 --- a/src/manifest.chromium.json +++ b/src/manifest.chromium.json @@ -2,7 +2,7 @@ "manifest_version": 3, "name": "TTV LOL PRO", "description": "TTV LOL PRO removes most livestream ads from Twitch.", - "version": "2.1.6", + "version": "2.2.0", "background": { "service_worker": "background/background.ts", "type": "module" diff --git a/src/manifest.firefox.json b/src/manifest.firefox.json index 556b21a5..5ecd3e30 100644 --- a/src/manifest.firefox.json +++ b/src/manifest.firefox.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "TTV LOL PRO", "description": "TTV LOL PRO removes most livestream ads from Twitch.", - "version": "2.1.6", + "version": "2.2.0", "background": { "scripts": ["background/background.ts"], "persistent": false diff --git a/src/options/options.ts b/src/options/options.ts index 257b427e..070281ad 100644 --- a/src/options/options.ts +++ b/src/options/options.ts @@ -2,7 +2,10 @@ import $ from "../common/ts/$"; import { readFile, saveFile } from "../common/ts/file"; import getProxyInfoFromUrl from "../common/ts/getProxyInfoFromUrl"; import isChromium from "../common/ts/isChromium"; -import { updateProxySettings } from "../common/ts/proxySettings"; +import { + clearProxySettings, + updateProxySettings, +} from "../common/ts/proxySettings"; import sendAdLog from "../common/ts/sendAdLog"; import store from "../store"; import getDefaultState from "../store/getDefaultState"; @@ -28,13 +31,17 @@ type ListOptions = { //#endregion //#region HTML Elements -// Proxy Usher requests +// Proxy settings const proxyUsherRequestsCheckboxElement = $( "#proxy-usher-requests-checkbox" ) as HTMLInputElement; const proxyTwitchWebpageCheckboxElement = $( "#proxy-twitch-webpage-checkbox" ) as HTMLInputElement; +const anonymousModeLiElement = $("#anonymous-mode-li") as HTMLLIElement; +const anonymousModeCheckboxElement = $( + "#anonymous-mode-checkbox" +) as HTMLInputElement; // Whitelisted channels const whitelistedChannelsSectionElement = $( "#whitelisted-channels-section" @@ -67,6 +74,9 @@ const adLogClearButtonElement = $("#ad-log-clear-button") as HTMLButtonElement; const exportButtonElement = $("#export-button") as HTMLButtonElement; const importButtonElement = $("#import-button") as HTMLButtonElement; const resetButtonElement = $("#reset-button") as HTMLButtonElement; +const unsetPacScriptButtonElement = $( + "#unset-pac-script-button" +) as HTMLButtonElement; //#endregion const DEFAULT_STATE = Object.freeze(getDefaultState()); @@ -86,32 +96,37 @@ if (store.readyState === "complete") main(); else store.addEventListener("load", main); function main() { - // Proxy Usher requests + // Proxy settings proxyUsherRequestsCheckboxElement.checked = store.state.proxyUsherRequests; proxyUsherRequestsCheckboxElement.addEventListener("change", () => { const checked = proxyUsherRequestsCheckboxElement.checked; store.state.proxyUsherRequests = checked; - if (isChromium && store.state.openedTwitchTabs.length > 0) { + if (isChromium && store.state.chromiumProxyActive) { updateProxySettings(); } }); proxyTwitchWebpageCheckboxElement.checked = store.state.proxyTwitchWebpage; proxyTwitchWebpageCheckboxElement.addEventListener("change", () => { store.state.proxyTwitchWebpage = proxyTwitchWebpageCheckboxElement.checked; - if (isChromium && store.state.openedTwitchTabs.length > 0) { + if (isChromium && store.state.chromiumProxyActive) { updateProxySettings(); } }); - // Whitelisted channels + // TODO: Figure out why this feature doesn't work in Chromium. if (isChromium) { - whitelistedChannelsSectionElement.style.display = "none"; + anonymousModeLiElement.style.display = "none"; } else { - listInit(whitelistedChannelsListElement, "whitelistedChannels", { - getAlreadyExistsAlertMessage: channelName => - `'${channelName}' is already whitelisted`, - getPromptPlaceholder: () => "Enter a channel name…", + anonymousModeCheckboxElement.checked = store.state.anonymousMode; + anonymousModeCheckboxElement.addEventListener("change", () => { + store.state.anonymousMode = anonymousModeCheckboxElement.checked; }); } + // Whitelisted channels + listInit(whitelistedChannelsListElement, "whitelistedChannels", { + getAlreadyExistsAlertMessage: channelName => + `'${channelName}' is already whitelisted`, + getPromptPlaceholder: () => "Enter a channel name…", + }); // Proxies if (isChromium) { optimizedProxiesDivElement.style.display = "none"; @@ -145,7 +160,7 @@ function main() { isAddAllowed: isNormalProxyUrlAllowed, isEditAllowed: isNormalProxyUrlAllowed, onEdit() { - if (isChromium && store.state.openedTwitchTabs.length > 0) { + if (isChromium && store.state.chromiumProxyActive) { updateProxySettings(); } }, @@ -161,6 +176,9 @@ function main() { store.state.adLogEnabled = adLogEnabledCheckboxElement.checked; }); } + if (!isChromium) { + unsetPacScriptButtonElement.style.display = "none"; + } } function isOptimizedProxyUrlAllowed(url: string): AllowedResult { @@ -439,6 +457,7 @@ exportButtonElement.addEventListener("click", () => { "ttv-lol-pro_backup.json", JSON.stringify({ adLogEnabled: store.state.adLogEnabled, + anonymousMode: store.state.anonymousMode, normalProxies: store.state.normalProxies, optimizedProxies: store.state.optimizedProxies, optimizedProxiesEnabled: store.state.optimizedProxiesEnabled, @@ -493,3 +512,10 @@ resetButtonElement.addEventListener("click", () => { store.clear(); window.location.reload(); // Reload page to update UI. }); + +unsetPacScriptButtonElement.addEventListener("click", () => { + if (isChromium) { + clearProxySettings(); + alert("PAC script unset successfully."); + } +}); diff --git a/src/options/page.html b/src/options/page.html index d9675d69..02e6183a 100644 --- a/src/options/page.html +++ b/src/options/page.html @@ -83,6 +83,21 @@