Merge branch 'main' of https://www.coastalcommits.com/CoastalCommitsArchival/github.com-Vendicated-Vencord
This commit is contained in:
commit
c045a02598
62 changed files with 1386 additions and 283 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"ignorePatterns": ["dist", "browser"],
|
"ignorePatterns": ["dist", "browser", "packages/vencord-types"],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint",
|
"@typescript-eslint",
|
||||||
"simple-header",
|
"simple-header",
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
/// <reference path="../src/modules.d.ts" />
|
/// <reference path="../src/modules.d.ts" />
|
||||||
/// <reference path="../src/globals.d.ts" />
|
/// <reference path="../src/globals.d.ts" />
|
||||||
|
|
||||||
import monacoHtmlLocal from "~fileContent/monacoWin.html";
|
import monacoHtmlLocal from "file://monacoWin.html?minify";
|
||||||
import monacoHtmlCdn from "~fileContent/../src/main/monacoWin.html";
|
import monacoHtmlCdn from "file://../src/main/monacoWin.html?minify";
|
||||||
import * as DataStore from "../src/api/DataStore";
|
import * as DataStore from "../src/api/DataStore";
|
||||||
import { debounce } from "../src/utils";
|
import { debounce } from "../src/utils";
|
||||||
import { EXTENSION_BASE_URL } from "../src/utils/web-metadata";
|
import { EXTENSION_BASE_URL } from "../src/utils/web-metadata";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.8.5",
|
"version": "1.8.6",
|
||||||
"description": "The cutest Discord client mod",
|
"description": "The cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
@ -18,8 +18,9 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/build.mjs",
|
"build": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/build.mjs",
|
||||||
|
"buildStandalone": "pnpm build --standalone",
|
||||||
"buildWeb": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/buildWeb.mjs",
|
"buildWeb": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/buildWeb.mjs",
|
||||||
"watch": "node --require=./scripts/suppressExperimentalWarnings.js scripts/build/build.mjs --watch",
|
"watch": "pnpm build --watch",
|
||||||
"generatePluginJson": "tsx scripts/generatePluginList.ts",
|
"generatePluginJson": "tsx scripts/generatePluginList.ts",
|
||||||
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types",
|
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types",
|
||||||
"inject": "node scripts/runInstaller.mjs",
|
"inject": "node scripts/runInstaller.mjs",
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern src/userplugins",
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern src/userplugins",
|
||||||
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
|
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
|
||||||
"lint:fix": "pnpm lint --fix",
|
"lint:fix": "pnpm lint --fix",
|
||||||
"test": "pnpm build && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson",
|
"test": "pnpm buildStandalone && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson",
|
||||||
"testWeb": "pnpm lint && pnpm buildWeb && pnpm testTsc",
|
"testWeb": "pnpm lint && pnpm buildWeb && pnpm testTsc",
|
||||||
"testTsc": "tsc --noEmit"
|
"testTsc": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||||
"eslint-plugin-unused-imports": "^2.0.0",
|
"eslint-plugin-unused-imports": "^2.0.0",
|
||||||
"highlight.js": "10.6.0",
|
"highlight.js": "10.6.0",
|
||||||
|
"html-minifier-terser": "^7.2.0",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"puppeteer-core": "^19.11.1",
|
"puppeteer-core": "^19.11.1",
|
||||||
"standalone-electron-types": "^1.0.0",
|
"standalone-electron-types": "^1.0.0",
|
||||||
|
|
156
pnpm-lock.yaml
156
pnpm-lock.yaml
|
@ -98,6 +98,9 @@ importers:
|
||||||
highlight.js:
|
highlight.js:
|
||||||
specifier: 10.6.0
|
specifier: 10.6.0
|
||||||
version: 10.6.0
|
version: 10.6.0
|
||||||
|
html-minifier-terser:
|
||||||
|
specifier: ^7.2.0
|
||||||
|
version: 7.2.0
|
||||||
moment:
|
moment:
|
||||||
specifier: ^2.29.4
|
specifier: ^2.29.4
|
||||||
version: 2.29.4
|
version: 2.29.4
|
||||||
|
@ -393,6 +396,27 @@ packages:
|
||||||
'@humanwhocodes/object-schema@1.2.1':
|
'@humanwhocodes/object-schema@1.2.1':
|
||||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||||
|
|
||||||
|
'@jridgewell/gen-mapping@0.3.5':
|
||||||
|
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2':
|
||||||
|
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/set-array@1.2.1':
|
||||||
|
resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/source-map@0.3.6':
|
||||||
|
resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.4.15':
|
||||||
|
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
|
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
@ -688,6 +712,9 @@ packages:
|
||||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
camel-case@4.1.2:
|
||||||
|
resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
|
||||||
|
|
||||||
camelcase-keys@6.2.2:
|
camelcase-keys@6.2.2:
|
||||||
resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
|
resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -716,6 +743,10 @@ packages:
|
||||||
resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
|
resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
clean-css@5.3.3:
|
||||||
|
resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==}
|
||||||
|
engines: {node: '>= 10.0'}
|
||||||
|
|
||||||
cliui@8.0.1:
|
cliui@8.0.1:
|
||||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -740,6 +771,13 @@ packages:
|
||||||
colord@2.9.3:
|
colord@2.9.3:
|
||||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||||
|
|
||||||
|
commander@10.0.1:
|
||||||
|
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
commander@2.20.3:
|
||||||
|
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
|
||||||
|
|
||||||
component-emitter@1.3.0:
|
component-emitter@1.3.0:
|
||||||
resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
|
resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
|
||||||
|
|
||||||
|
@ -871,12 +909,19 @@ packages:
|
||||||
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
dot-case@3.0.4:
|
||||||
|
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
|
||||||
|
|
||||||
emoji-regex@8.0.0:
|
emoji-regex@8.0.0:
|
||||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
|
|
||||||
end-of-stream@1.4.4:
|
end-of-stream@1.4.4:
|
||||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||||
|
|
||||||
|
entities@4.5.0:
|
||||||
|
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||||
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
error-ex@1.3.2:
|
error-ex@1.3.2:
|
||||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||||
|
|
||||||
|
@ -1402,6 +1447,11 @@ packages:
|
||||||
resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
|
resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
html-minifier-terser@7.2.0:
|
||||||
|
resolution: {integrity: sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==}
|
||||||
|
engines: {node: ^14.13.1 || >=16.0.0}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
html-tags@3.3.1:
|
html-tags@3.3.1:
|
||||||
resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
|
resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -1673,6 +1723,9 @@ packages:
|
||||||
lodash.truncate@4.4.2:
|
lodash.truncate@4.4.2:
|
||||||
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
|
resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==}
|
||||||
|
|
||||||
|
lower-case@2.0.2:
|
||||||
|
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
|
||||||
|
|
||||||
lru-cache@6.0.0:
|
lru-cache@6.0.0:
|
||||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
@ -1770,6 +1823,9 @@ packages:
|
||||||
natural-compare@1.4.0:
|
natural-compare@1.4.0:
|
||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
|
|
||||||
|
no-case@3.0.4:
|
||||||
|
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
||||||
|
|
||||||
node-fetch@2.6.7:
|
node-fetch@2.6.7:
|
||||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||||
engines: {node: 4.x || >=6.0.0}
|
engines: {node: 4.x || >=6.0.0}
|
||||||
|
@ -1855,6 +1911,9 @@ packages:
|
||||||
pako@1.0.11:
|
pako@1.0.11:
|
||||||
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
|
||||||
|
|
||||||
|
param-case@3.0.4:
|
||||||
|
resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
|
||||||
|
|
||||||
parent-module@1.0.1:
|
parent-module@1.0.1:
|
||||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
@ -1863,6 +1922,9 @@ packages:
|
||||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
pascal-case@3.1.2:
|
||||||
|
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
|
||||||
|
|
||||||
pascalcase@0.1.1:
|
pascalcase@0.1.1:
|
||||||
resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
|
resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -1985,6 +2047,10 @@ packages:
|
||||||
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
relateurl@0.2.7:
|
||||||
|
resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==}
|
||||||
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
require-directory@2.1.1:
|
require-directory@2.1.1:
|
||||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -2228,6 +2294,11 @@ packages:
|
||||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
terser@5.31.0:
|
||||||
|
resolution: {integrity: sha512-Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
text-table@0.2.0:
|
text-table@0.2.0:
|
||||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||||
|
|
||||||
|
@ -2263,6 +2334,9 @@ packages:
|
||||||
tslib@1.14.1:
|
tslib@1.14.1:
|
||||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||||
|
|
||||||
|
tslib@2.6.2:
|
||||||
|
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||||
|
|
||||||
tsutils@3.21.0:
|
tsutils@3.21.0:
|
||||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -2599,6 +2673,28 @@ snapshots:
|
||||||
|
|
||||||
'@humanwhocodes/object-schema@1.2.1': {}
|
'@humanwhocodes/object-schema@1.2.1': {}
|
||||||
|
|
||||||
|
'@jridgewell/gen-mapping@0.3.5':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/set-array': 1.2.1
|
||||||
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
'@jridgewell/trace-mapping': 0.3.25
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2': {}
|
||||||
|
|
||||||
|
'@jridgewell/set-array@1.2.1': {}
|
||||||
|
|
||||||
|
'@jridgewell/source-map@0.3.6':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/gen-mapping': 0.3.5
|
||||||
|
'@jridgewell/trace-mapping': 0.3.25
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.4.15': {}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.25':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
||||||
'@nodelib/fs.scandir@2.1.5':
|
'@nodelib/fs.scandir@2.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
|
@ -2958,6 +3054,11 @@ snapshots:
|
||||||
|
|
||||||
callsites@3.1.0: {}
|
callsites@3.1.0: {}
|
||||||
|
|
||||||
|
camel-case@4.1.2:
|
||||||
|
dependencies:
|
||||||
|
pascal-case: 3.1.2
|
||||||
|
tslib: 2.6.2
|
||||||
|
|
||||||
camelcase-keys@6.2.2:
|
camelcase-keys@6.2.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase: 5.3.1
|
camelcase: 5.3.1
|
||||||
|
@ -2991,6 +3092,10 @@ snapshots:
|
||||||
isobject: 3.0.1
|
isobject: 3.0.1
|
||||||
static-extend: 0.1.2
|
static-extend: 0.1.2
|
||||||
|
|
||||||
|
clean-css@5.3.3:
|
||||||
|
dependencies:
|
||||||
|
source-map: 0.6.1
|
||||||
|
|
||||||
cliui@8.0.1:
|
cliui@8.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
|
@ -3016,6 +3121,10 @@ snapshots:
|
||||||
|
|
||||||
colord@2.9.3: {}
|
colord@2.9.3: {}
|
||||||
|
|
||||||
|
commander@10.0.1: {}
|
||||||
|
|
||||||
|
commander@2.20.3: {}
|
||||||
|
|
||||||
component-emitter@1.3.0: {}
|
component-emitter@1.3.0: {}
|
||||||
|
|
||||||
concat-map@0.0.1: {}
|
concat-map@0.0.1: {}
|
||||||
|
@ -3139,12 +3248,19 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
|
dot-case@3.0.4:
|
||||||
|
dependencies:
|
||||||
|
no-case: 3.0.4
|
||||||
|
tslib: 2.6.2
|
||||||
|
|
||||||
emoji-regex@8.0.0: {}
|
emoji-regex@8.0.0: {}
|
||||||
|
|
||||||
end-of-stream@1.4.4:
|
end-of-stream@1.4.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
once: 1.4.0
|
once: 1.4.0
|
||||||
|
|
||||||
|
entities@4.5.0: {}
|
||||||
|
|
||||||
error-ex@1.3.2:
|
error-ex@1.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arrayish: 0.2.1
|
is-arrayish: 0.2.1
|
||||||
|
@ -3733,6 +3849,16 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
lru-cache: 6.0.0
|
lru-cache: 6.0.0
|
||||||
|
|
||||||
|
html-minifier-terser@7.2.0:
|
||||||
|
dependencies:
|
||||||
|
camel-case: 4.1.2
|
||||||
|
clean-css: 5.3.3
|
||||||
|
commander: 10.0.1
|
||||||
|
entities: 4.5.0
|
||||||
|
param-case: 3.0.4
|
||||||
|
relateurl: 0.2.7
|
||||||
|
terser: 5.31.0
|
||||||
|
|
||||||
html-tags@3.3.1: {}
|
html-tags@3.3.1: {}
|
||||||
|
|
||||||
https-proxy-agent@5.0.1:
|
https-proxy-agent@5.0.1:
|
||||||
|
@ -3974,6 +4100,10 @@ snapshots:
|
||||||
|
|
||||||
lodash.truncate@4.4.2: {}
|
lodash.truncate@4.4.2: {}
|
||||||
|
|
||||||
|
lower-case@2.0.2:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.6.2
|
||||||
|
|
||||||
lru-cache@6.0.0:
|
lru-cache@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
|
@ -4071,6 +4201,11 @@ snapshots:
|
||||||
|
|
||||||
natural-compare@1.4.0: {}
|
natural-compare@1.4.0: {}
|
||||||
|
|
||||||
|
no-case@3.0.4:
|
||||||
|
dependencies:
|
||||||
|
lower-case: 2.0.2
|
||||||
|
tslib: 2.6.2
|
||||||
|
|
||||||
node-fetch@2.6.7:
|
node-fetch@2.6.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
|
@ -4168,6 +4303,11 @@ snapshots:
|
||||||
|
|
||||||
pako@1.0.11: {}
|
pako@1.0.11: {}
|
||||||
|
|
||||||
|
param-case@3.0.4:
|
||||||
|
dependencies:
|
||||||
|
dot-case: 3.0.4
|
||||||
|
tslib: 2.6.2
|
||||||
|
|
||||||
parent-module@1.0.1:
|
parent-module@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
callsites: 3.1.0
|
callsites: 3.1.0
|
||||||
|
@ -4179,6 +4319,11 @@ snapshots:
|
||||||
json-parse-even-better-errors: 2.3.1
|
json-parse-even-better-errors: 2.3.1
|
||||||
lines-and-columns: 1.2.4
|
lines-and-columns: 1.2.4
|
||||||
|
|
||||||
|
pascal-case@3.1.2:
|
||||||
|
dependencies:
|
||||||
|
no-case: 3.0.4
|
||||||
|
tslib: 2.6.2
|
||||||
|
|
||||||
pascalcase@0.1.1: {}
|
pascalcase@0.1.1: {}
|
||||||
|
|
||||||
path-exists@4.0.0: {}
|
path-exists@4.0.0: {}
|
||||||
|
@ -4296,6 +4441,8 @@ snapshots:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
set-function-name: 2.0.2
|
set-function-name: 2.0.2
|
||||||
|
|
||||||
|
relateurl@0.2.7: {}
|
||||||
|
|
||||||
require-directory@2.1.1: {}
|
require-directory@2.1.1: {}
|
||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
@ -4605,6 +4752,13 @@ snapshots:
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
|
||||||
|
terser@5.31.0:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/source-map': 0.3.6
|
||||||
|
acorn: 8.10.0
|
||||||
|
commander: 2.20.3
|
||||||
|
source-map-support: 0.5.21
|
||||||
|
|
||||||
text-table@0.2.0: {}
|
text-table@0.2.0: {}
|
||||||
|
|
||||||
through@2.3.8: {}
|
through@2.3.8: {}
|
||||||
|
@ -4646,6 +4800,8 @@ snapshots:
|
||||||
|
|
||||||
tslib@1.14.1: {}
|
tslib@1.14.1: {}
|
||||||
|
|
||||||
|
tslib@2.6.2: {}
|
||||||
|
|
||||||
tsutils@3.21.0(typescript@5.4.5):
|
tsutils@3.21.0(typescript@5.4.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
|
|
|
@ -20,8 +20,10 @@ import "../suppressExperimentalWarnings.js";
|
||||||
import "../checkNodeVersion.js";
|
import "../checkNodeVersion.js";
|
||||||
|
|
||||||
import { exec, execSync } from "child_process";
|
import { exec, execSync } from "child_process";
|
||||||
|
import esbuild from "esbuild";
|
||||||
import { constants as FsConstants, readFileSync } from "fs";
|
import { constants as FsConstants, readFileSync } from "fs";
|
||||||
import { access, readdir, readFile } from "fs/promises";
|
import { access, readdir, readFile } from "fs/promises";
|
||||||
|
import { minify as minifyHtml } from "html-minifier-terser";
|
||||||
import { join, relative } from "path";
|
import { join, relative } from "path";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
|
|
||||||
|
@ -161,21 +163,60 @@ export const gitRemotePlugin = {
|
||||||
/**
|
/**
|
||||||
* @type {import("esbuild").Plugin}
|
* @type {import("esbuild").Plugin}
|
||||||
*/
|
*/
|
||||||
export const fileIncludePlugin = {
|
export const fileUrlPlugin = {
|
||||||
name: "file-include-plugin",
|
name: "file-uri-plugin",
|
||||||
setup: build => {
|
setup: build => {
|
||||||
const filter = /^~fileContent\/.+$/;
|
const filter = /^file:\/\/.+$/;
|
||||||
build.onResolve({ filter }, args => ({
|
build.onResolve({ filter }, args => ({
|
||||||
namespace: "include-file",
|
namespace: "file-uri",
|
||||||
path: args.path,
|
path: args.path,
|
||||||
pluginData: {
|
pluginData: {
|
||||||
path: join(args.resolveDir, args.path.slice("include-file/".length))
|
uri: args.path,
|
||||||
|
path: join(args.resolveDir, args.path.slice("file://".length).split("?")[0])
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
build.onLoad({ filter, namespace: "include-file" }, async ({ pluginData: { path } }) => {
|
build.onLoad({ filter, namespace: "file-uri" }, async ({ pluginData: { path, uri } }) => {
|
||||||
const [name, format] = path.split(";");
|
const { searchParams } = new URL(uri);
|
||||||
|
const base64 = searchParams.has("base64");
|
||||||
|
const minify = isStandalone === "true" && searchParams.has("minify");
|
||||||
|
const noTrim = searchParams.get("trim") === "false";
|
||||||
|
|
||||||
|
const encoding = base64 ? "base64" : "utf-8";
|
||||||
|
|
||||||
|
let content;
|
||||||
|
if (!minify) {
|
||||||
|
content = await readFile(path, encoding);
|
||||||
|
if (!noTrim) content = content.trimEnd();
|
||||||
|
} else {
|
||||||
|
if (path.endsWith(".html")) {
|
||||||
|
content = await minifyHtml(await readFile(path, "utf-8"), {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeComments: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyJS: true,
|
||||||
|
removeEmptyAttributes: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
removeScriptTypeAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
useShortDoctype: true
|
||||||
|
});
|
||||||
|
} else if (/[mc]?[jt]sx?$/.test(path)) {
|
||||||
|
const res = await esbuild.build({
|
||||||
|
entryPoints: [path],
|
||||||
|
write: false,
|
||||||
|
minify: true
|
||||||
|
});
|
||||||
|
content = res.outputFiles[0].text;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Don't know how to minify file type: ${path}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base64)
|
||||||
|
content = Buffer.from(content).toString("base64");
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contents: `export default ${JSON.stringify(await readFile(name, format ?? "utf-8"))}`
|
contents: `export default ${JSON.stringify(content)}`
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -217,7 +258,7 @@ export const commonOpts = {
|
||||||
sourcemap: watch ? "inline" : "",
|
sourcemap: watch ? "inline" : "",
|
||||||
legalComments: "linked",
|
legalComments: "linked",
|
||||||
banner,
|
banner,
|
||||||
plugins: [fileIncludePlugin, gitHashPlugin, gitRemotePlugin, stylePlugin],
|
plugins: [fileUrlPlugin, gitHashPlugin, gitRemotePlugin, stylePlugin],
|
||||||
external: ["~plugins", "~git-hash", "~git-remote", "/assets/*"],
|
external: ["~plugins", "~git-hash", "~git-remote", "/assets/*"],
|
||||||
inject: ["./scripts/build/inject/react.mjs"],
|
inject: ["./scripts/build/inject/react.mjs"],
|
||||||
jsxFactory: "VencordCreateElement",
|
jsxFactory: "VencordCreateElement",
|
||||||
|
|
|
@ -243,19 +243,27 @@ page.on("console", async e => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDebug) {
|
async function getText() {
|
||||||
console.error(e.text());
|
|
||||||
} else if (level === "error") {
|
|
||||||
const text = await Promise.all(
|
|
||||||
e.args().map(async a => {
|
|
||||||
try {
|
try {
|
||||||
|
return await Promise.all(
|
||||||
|
e.args().map(async a => {
|
||||||
return await maybeGetError(a) || await a.jsonValue();
|
return await maybeGetError(a) || await a.jsonValue();
|
||||||
} catch (e) {
|
|
||||||
return a.toString();
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
).then(a => a.join(" ").trim());
|
).then(a => a.join(" ").trim());
|
||||||
|
} catch {
|
||||||
|
return e.text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDebug) {
|
||||||
|
const text = await getText();
|
||||||
|
|
||||||
|
console.error(text);
|
||||||
|
if (text.includes("A fatal error occurred:")) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else if (level === "error") {
|
||||||
|
const text = await getText();
|
||||||
|
|
||||||
if (text.length && !text.startsWith("Failed to load resource: the server responded with a status of") && !text.includes("Webpack")) {
|
if (text.length && !text.startsWith("Failed to load resource: the server responded with a status of") && !text.includes("Webpack")) {
|
||||||
console.error("[Unexpected Error]", text);
|
console.error("[Unexpected Error]", text);
|
||||||
|
@ -322,22 +330,31 @@ async function runtime(token: string) {
|
||||||
|
|
||||||
const validChunks = new Set<string>();
|
const validChunks = new Set<string>();
|
||||||
const invalidChunks = new Set<string>();
|
const invalidChunks = new Set<string>();
|
||||||
|
const deferredRequires = new Set<string>();
|
||||||
|
|
||||||
let chunksSearchingResolve: (value: void | PromiseLike<void>) => void;
|
let chunksSearchingResolve: (value: void | PromiseLike<void>) => void;
|
||||||
const chunksSearchingDone = new Promise<void>(r => chunksSearchingResolve = r);
|
const chunksSearchingDone = new Promise<void>(r => chunksSearchingResolve = r);
|
||||||
|
|
||||||
// True if resolved, false otherwise
|
// True if resolved, false otherwise
|
||||||
const chunksSearchPromises = [] as Array<() => boolean>;
|
const chunksSearchPromises = [] as Array<() => boolean>;
|
||||||
const lazyChunkRegex = canonicalizeMatch(/Promise\.all\((\[\i\.\i\(".+?"\).+?\])\).then\(\i\.bind\(\i,"(.+?)"\)\)/g);
|
|
||||||
const chunkIdsRegex = canonicalizeMatch(/\("(.+?)"\)/g);
|
const LazyChunkRegex = canonicalizeMatch(/(?:Promise\.all\(\[(\i\.\i\("[^)]+?"\)[^\]]+?)\]\)|(\i\.\i\("[^)]+?"\)))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/g);
|
||||||
|
|
||||||
async function searchAndLoadLazyChunks(factoryCode: string) {
|
async function searchAndLoadLazyChunks(factoryCode: string) {
|
||||||
const lazyChunks = factoryCode.matchAll(lazyChunkRegex);
|
const lazyChunks = factoryCode.matchAll(LazyChunkRegex);
|
||||||
const validChunkGroups = new Set<[chunkIds: string[], entryPoint: string]>();
|
const validChunkGroups = new Set<[chunkIds: string[], entryPoint: string]>();
|
||||||
|
|
||||||
await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIds, entryPoint]) => {
|
// Workaround for a chunk that depends on the ChannelMessage component but may be be force loaded before
|
||||||
const chunkIds = Array.from(rawChunkIds.matchAll(chunkIdsRegex)).map(m => m[1]);
|
// the chunk containing the component
|
||||||
if (chunkIds.length === 0) return;
|
const shouldForceDefer = factoryCode.includes(".Messages.GUILD_FEED_UNFEATURE_BUTTON_TEXT");
|
||||||
|
|
||||||
|
await Promise.all(Array.from(lazyChunks).map(async ([, rawChunkIdsArray, rawChunkIdsSingle, entryPoint]) => {
|
||||||
|
const rawChunkIds = rawChunkIdsArray ?? rawChunkIdsSingle;
|
||||||
|
const chunkIds = rawChunkIds ? Array.from(rawChunkIds.matchAll(Vencord.Webpack.ChunkIdsRegex)).map(m => m[1]) : [];
|
||||||
|
|
||||||
|
if (chunkIds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let invalidChunkGroup = false;
|
let invalidChunkGroup = false;
|
||||||
|
|
||||||
|
@ -373,6 +390,11 @@ async function runtime(token: string) {
|
||||||
// Requires the entry points for all valid chunk groups
|
// Requires the entry points for all valid chunk groups
|
||||||
for (const [, entryPoint] of validChunkGroups) {
|
for (const [, entryPoint] of validChunkGroups) {
|
||||||
try {
|
try {
|
||||||
|
if (shouldForceDefer) {
|
||||||
|
deferredRequires.add(entryPoint);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (wreq.m[entryPoint]) wreq(entryPoint as any);
|
if (wreq.m[entryPoint]) wreq(entryPoint as any);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
@ -435,6 +457,11 @@ async function runtime(token: string) {
|
||||||
|
|
||||||
await chunksSearchingDone;
|
await chunksSearchingDone;
|
||||||
|
|
||||||
|
// Require deferred entry points
|
||||||
|
for (const deferredRequire of deferredRequires) {
|
||||||
|
wreq!(deferredRequire as any);
|
||||||
|
}
|
||||||
|
|
||||||
// All chunks Discord has mapped to asset files, even if they are not used anymore
|
// All chunks Discord has mapped to asset files, even if they are not used anymore
|
||||||
const allChunks = [] as string[];
|
const allChunks = [] as string[];
|
||||||
|
|
||||||
|
@ -514,7 +541,6 @@ async function runtime(token: string) {
|
||||||
setTimeout(() => console.log("[PUPPETEER_TEST_DONE_SIGNAL]"), 1000);
|
setTimeout(() => console.log("[PUPPETEER_TEST_DONE_SIGNAL]"), 1000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("[PUP_DEBUG]", "A fatal error occurred:", e);
|
console.log("[PUP_DEBUG]", "A fatal error occurred:", e);
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,11 @@ import "./settings";
|
||||||
import { debounce } from "@shared/debounce";
|
import { debounce } from "@shared/debounce";
|
||||||
import { IpcEvents } from "@shared/IpcEvents";
|
import { IpcEvents } from "@shared/IpcEvents";
|
||||||
import { BrowserWindow, ipcMain, shell, systemPreferences } from "electron";
|
import { BrowserWindow, ipcMain, shell, systemPreferences } from "electron";
|
||||||
|
import monacoHtml from "file://monacoWin.html?minify&base64";
|
||||||
import { FSWatcher, mkdirSync, watch, writeFileSync } from "fs";
|
import { FSWatcher, mkdirSync, watch, writeFileSync } from "fs";
|
||||||
import { open, readdir, readFile } from "fs/promises";
|
import { open, readdir, readFile } from "fs/promises";
|
||||||
import { join, normalize } from "path";
|
import { join, normalize } from "path";
|
||||||
|
|
||||||
import monacoHtml from "~fileContent/monacoWin.html;base64";
|
|
||||||
|
|
||||||
import { getThemeInfo, stripBOM, UserThemeHeader } from "./themes";
|
import { getThemeInfo, stripBOM, UserThemeHeader } from "./themes";
|
||||||
import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, THEMES_DIR } from "./utils/constants";
|
import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, THEMES_DIR } from "./utils/constants";
|
||||||
import { makeLinksOpenExternally } from "./utils/externalLinks";
|
import { makeLinksOpenExternally } from "./utils/externalLinks";
|
||||||
|
|
|
@ -73,6 +73,9 @@ if (!IS_VANILLA) {
|
||||||
const original = options.webPreferences.preload;
|
const original = options.webPreferences.preload;
|
||||||
options.webPreferences.preload = join(__dirname, IS_DISCORD_DESKTOP ? "preload.js" : "vencordDesktopPreload.js");
|
options.webPreferences.preload = join(__dirname, IS_DISCORD_DESKTOP ? "preload.js" : "vencordDesktopPreload.js");
|
||||||
options.webPreferences.sandbox = false;
|
options.webPreferences.sandbox = false;
|
||||||
|
// work around discord unloading when in background
|
||||||
|
options.webPreferences.backgroundThrottling = false;
|
||||||
|
|
||||||
if (settings.frameless) {
|
if (settings.frameless) {
|
||||||
options.frame = false;
|
options.frame = false;
|
||||||
} else if (process.platform === "win32" && settings.winNativeTitleBar) {
|
} else if (process.platform === "win32" && settings.winNativeTitleBar) {
|
||||||
|
@ -136,6 +139,15 @@ if (!IS_VANILLA) {
|
||||||
}
|
}
|
||||||
return originalAppend.apply(this, args);
|
return originalAppend.apply(this, args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// disable renderer backgrounding to prevent the app from unloading when in the background
|
||||||
|
// https://github.com/electron/electron/issues/2822
|
||||||
|
// https://github.com/GoogleChrome/chrome-launcher/blob/5a27dd574d47a75fec0fb50f7b774ebf8a9791ba/docs/chrome-flags-for-tools.md#task-throttling
|
||||||
|
// Work around discord unloading when in background
|
||||||
|
// Discord also recently started adding these flags but only on windows for some reason dunno why, it happens on Linux too
|
||||||
|
app.commandLine.appendSwitch("disable-renderer-backgrounding");
|
||||||
|
app.commandLine.appendSwitch("disable-background-timer-throttling");
|
||||||
|
app.commandLine.appendSwitch("disable-backgrounding-occluded-windows");
|
||||||
} else {
|
} else {
|
||||||
console.log("[Vencord] Running in vanilla mode. Not loading Vencord");
|
console.log("[Vencord] Running in vanilla mode. Not loading Vencord");
|
||||||
}
|
}
|
||||||
|
|
2
src/modules.d.ts
vendored
2
src/modules.d.ts
vendored
|
@ -38,7 +38,7 @@ declare module "~git-remote" {
|
||||||
export default remote;
|
export default remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "~fileContent/*" {
|
declare module "file://*" {
|
||||||
const content: string;
|
const content: string;
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default definePlugin({
|
||||||
find: '"NoticeStore"',
|
find: '"NoticeStore"',
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /\i=null;(?=.{0,80}getPremiumSubscription\(\))/g,
|
match: /(?<=!1;)\i=null;(?=.{0,80}getPremiumSubscription\(\))/g,
|
||||||
replace: "if(Vencord.Api.Notices.currentNotice)return false;$&"
|
replace: "if(Vencord.Api.Notices.currentNotice)return false;$&"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,6 +56,26 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
// Discord Stable
|
||||||
|
// FIXME: remove once change merged to stable
|
||||||
|
{
|
||||||
|
find: "Messages.ACTIVITY_SETTINGS",
|
||||||
|
replacement: {
|
||||||
|
get match() {
|
||||||
|
switch (Settings.plugins.Settings.settingsLocation) {
|
||||||
|
case "top": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.USER_SETTINGS/;
|
||||||
|
case "aboveNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.BILLING_SETTINGS/;
|
||||||
|
case "belowNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS/;
|
||||||
|
case "belowActivity": return /(?<=\{section:(\i\.\i)\.DIVIDER},)\{section:"changelog"/;
|
||||||
|
case "bottom": return /\{section:(\i\.\i)\.CUSTOM,\s*element:.+?}/;
|
||||||
|
case "aboveActivity":
|
||||||
|
default:
|
||||||
|
return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.ACTIVITY_SETTINGS/;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
replace: "...$self.makeSettingsCategories($1),$&"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
find: "Messages.ACTIVITY_SETTINGS",
|
find: "Messages.ACTIVITY_SETTINGS",
|
||||||
replacement: {
|
replacement: {
|
||||||
|
|
|
@ -31,10 +31,10 @@ export default definePlugin({
|
||||||
// Some modules match the find but the replacement is returned untouched
|
// Some modules match the find but the replacement is returned untouched
|
||||||
noWarn: true,
|
noWarn: true,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /canAnimate:.+?(?=([,}].*?\)))/g,
|
match: /canAnimate:.+?([,}].*?\))/g,
|
||||||
replace: (m, rest) => {
|
replace: (m, rest) => {
|
||||||
const destructuringMatch = rest.match(/}=.+/);
|
const destructuringMatch = rest.match(/}=.+/);
|
||||||
if (destructuringMatch == null) return "canAnimate:!0";
|
if (destructuringMatch == null) return `canAnimate:!0${rest}`;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,13 +73,13 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "instantBatchUpload:function",
|
find: "instantBatchUpload:function",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /uploadFiles:(.{1,2}),/,
|
match: /uploadFiles:(\i),/,
|
||||||
replace:
|
replace:
|
||||||
"uploadFiles:(...args)=>(args[0].uploads.forEach(f=>f.filename=$self.anonymise(f)),$1(...args)),",
|
"uploadFiles:(...args)=>(args[0].uploads.forEach(f=>f.filename=$self.anonymise(f)),$1(...args)),",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "message.attachments",
|
find: 'addFilesTo:"message.attachments"',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(\i.uploadFiles\((\i),)/,
|
match: /(\i.uploadFiles\((\i),)/,
|
||||||
replace: "$2.forEach(f=>f.filename=$self.anonymise(f)),$1"
|
replace: "$2.forEach(f=>f.filename=$self.anonymise(f)),$1"
|
||||||
|
|
|
@ -112,8 +112,8 @@ export default definePlugin({
|
||||||
replacement: [
|
replacement: [
|
||||||
// Create the isBetterFolders variable in the GuildsBar component
|
// Create the isBetterFolders variable in the GuildsBar component
|
||||||
{
|
{
|
||||||
match: /(?<=let{disableAppDownload:\i=\i\.isPlatformEmbedded,isOverlay:.+?)(?=}=\i,)/,
|
match: /let{disableAppDownload:\i=\i\.isPlatformEmbedded,isOverlay:.+?(?=}=\i,)/,
|
||||||
replace: ",isBetterFolders"
|
replace: "$&,isBetterFolders"
|
||||||
},
|
},
|
||||||
// If we are rendering the Better Folders sidebar, we filter out guilds that are not in folders and unexpanded folders
|
// If we are rendering the Better Folders sidebar, we filter out guilds that are not in folders and unexpanded folders
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# BetterRoleContext
|
# BetterRoleContext
|
||||||
|
|
||||||
Adds options to copy role color and edit role when right clicking roles in the user profile
|
Adds options to copy role color, edit role and view role icon when right clicking roles in the user profile
|
||||||
|
|
||||||
![](https://github.com/Vendicated/Vencord/assets/45497981/d1765e9e-7db2-4a3c-b110-139c59235326)
|
![](https://github.com/Vendicated/Vencord/assets/45497981/354220a4-09f3-4c5f-a28e-4b19ca775190)
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import { ImageIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getCurrentGuild } from "@utils/discord";
|
import { getCurrentGuild, openImageModal } from "@utils/discord";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy } from "@webpack";
|
import { findByPropsLazy } from "@webpack";
|
||||||
import { Clipboard, GuildStore, Menu, PermissionStore, TextAndImagesSettingsStores } from "@webpack/common";
|
import { Clipboard, GuildStore, Menu, PermissionStore, TextAndImagesSettingsStores } from "@webpack/common";
|
||||||
|
|
||||||
|
@ -34,10 +36,34 @@ function AppearanceIcon() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
roleIconFileFormat: {
|
||||||
|
type: OptionType.SELECT,
|
||||||
|
description: "File format to use when viewing role icons",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "png",
|
||||||
|
value: "png",
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "webp",
|
||||||
|
value: "webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "jpg",
|
||||||
|
value: "jpg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "BetterRoleContext",
|
name: "BetterRoleContext",
|
||||||
description: "Adds options to copy role color / edit role when right clicking roles in the user profile",
|
description: "Adds options to copy role color / edit role / view role icon when right clicking roles in the user profile",
|
||||||
authors: [Devs.Ven],
|
authors: [Devs.Ven, Devs.goodbee],
|
||||||
|
|
||||||
|
settings,
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
// DeveloperMode needs to be enabled for the context menu to be shown
|
// DeveloperMode needs to be enabled for the context menu to be shown
|
||||||
|
@ -63,6 +89,20 @@ export default definePlugin({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (role.icon) {
|
||||||
|
children.push(
|
||||||
|
<Menu.MenuItem
|
||||||
|
id="vc-view-role-icon"
|
||||||
|
label="View Role Icon"
|
||||||
|
action={() => {
|
||||||
|
openImageModal(`${location.protocol}//${window.GLOBAL_ENV.CDN_HOST}/role-icons/${role.id}/${role.icon}.${settings.store.roleIconFileFormat}`);
|
||||||
|
}}
|
||||||
|
icon={ImageIcon}
|
||||||
|
/>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (PermissionStore.getGuildPermissionProps(guild).canManageRoles) {
|
if (PermissionStore.getGuildPermissionProps(guild).canManageRoles) {
|
||||||
children.push(
|
children.push(
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
|
|
|
@ -111,8 +111,8 @@ export default definePlugin({
|
||||||
{ // Load menu TOC eagerly
|
{ // Load menu TOC eagerly
|
||||||
find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format",
|
find: "Messages.USER_SETTINGS_WITH_BUILD_OVERRIDE.format",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?openContextMenuLazy.{0,100}?(await Promise\.all[^};]*?\)\)).*?,)(?=\1\(this)/,
|
match: /(\i)\(this,"handleOpenSettingsContextMenu",.{0,100}?openContextMenuLazy.{0,100}?(await Promise\.all[^};]*?\)\)).*?,(?=\1\(this)/,
|
||||||
replace: "(async ()=>$2)(),"
|
replace: "$&(async ()=>$2)(),"
|
||||||
},
|
},
|
||||||
predicate: () => settings.store.eagerLoad
|
predicate: () => settings.store.eagerLoad
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,9 +34,9 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".AVATAR_STATUS_MOBILE_16;",
|
find: ".AVATAR_STATUS_MOBILE_16;",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=fromIsMobile:\i=!0,.+?)status:(\i)/,
|
match: /(fromIsMobile:\i=!0,.+?)status:(\i)/,
|
||||||
// Rename field to force it to always use "online"
|
// Rename field to force it to always use "online"
|
||||||
replace: 'status_$:$1="online"'
|
replace: '$1status_$:$2="online"'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -17,24 +17,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
||||||
|
import { SYM_LAZY_CACHED, SYM_LAZY_GET } from "@utils/lazy";
|
||||||
import { relaunch } from "@utils/native";
|
import { relaunch } from "@utils/native";
|
||||||
import { canonicalizeMatch, canonicalizeReplace, canonicalizeReplacement } from "@utils/patches";
|
import { canonicalizeMatch, canonicalizeReplace, canonicalizeReplacement } from "@utils/patches";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin, { PluginNative, StartAt } from "@utils/types";
|
||||||
import * as Webpack from "@webpack";
|
import * as Webpack from "@webpack";
|
||||||
import { extract, filters, findAll, search } from "@webpack";
|
import { extract, filters, findAll, findModuleId, search } from "@webpack";
|
||||||
import { React, ReactDOM } from "@webpack/common";
|
import * as Common from "@webpack/common";
|
||||||
import type { ComponentType } from "react";
|
import type { ComponentType } from "react";
|
||||||
|
|
||||||
const WEB_ONLY = (f: string) => () => {
|
const DESKTOP_ONLY = (f: string) => () => {
|
||||||
throw new Error(`'${f}' is Discord Desktop only.`);
|
throw new Error(`'${f}' is Discord Desktop only.`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default definePlugin({
|
const define: typeof Object.defineProperty =
|
||||||
name: "ConsoleShortcuts",
|
(obj, prop, desc) => {
|
||||||
description: "Adds shorter Aliases for many things on the window. Run `shortcutList` for a list.",
|
if (Object.hasOwn(desc, "value"))
|
||||||
authors: [Devs.Ven],
|
desc.writable = true;
|
||||||
|
|
||||||
getShortcuts() {
|
return Object.defineProperty(obj, prop, {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true,
|
||||||
|
...desc
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function makeShortcuts() {
|
||||||
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn) {
|
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn) {
|
||||||
const cache = new Map<string, unknown>();
|
const cache = new Map<string, unknown>();
|
||||||
|
|
||||||
|
@ -64,16 +73,17 @@ export default definePlugin({
|
||||||
let fakeRenderWin: WeakRef<Window> | undefined;
|
let fakeRenderWin: WeakRef<Window> | undefined;
|
||||||
const find = newFindWrapper(f => f);
|
const find = newFindWrapper(f => f);
|
||||||
const findByProps = newFindWrapper(filters.byProps);
|
const findByProps = newFindWrapper(filters.byProps);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...Vencord.Webpack.Common,
|
...Object.fromEntries(Object.keys(Common).map(key => [key, { getter: () => Common[key] }])),
|
||||||
wp: Vencord.Webpack,
|
wp: Webpack,
|
||||||
wpc: Webpack.wreq.c,
|
wpc: { getter: () => Webpack.cache },
|
||||||
wreq: Webpack.wreq,
|
wreq: { getter: () => Webpack.wreq },
|
||||||
wpsearch: search,
|
wpsearch: search,
|
||||||
wpex: extract,
|
wpex: extract,
|
||||||
wpexs: (code: string) => extract(Webpack.findModuleId(code)!),
|
wpexs: (code: string) => extract(findModuleId(code)!),
|
||||||
find,
|
find,
|
||||||
findAll,
|
findAll: findAll,
|
||||||
findByProps,
|
findByProps,
|
||||||
findAllByProps: (...props: string[]) => findAll(filters.byProps(...props)),
|
findAllByProps: (...props: string[]) => findAll(filters.byProps(...props)),
|
||||||
findByCode: newFindWrapper(filters.byCode),
|
findByCode: newFindWrapper(filters.byCode),
|
||||||
|
@ -82,18 +92,21 @@ export default definePlugin({
|
||||||
findAllComponentsByCode: (...code: string[]) => findAll(filters.componentByCode(...code)),
|
findAllComponentsByCode: (...code: string[]) => findAll(filters.componentByCode(...code)),
|
||||||
findExportedComponent: (...props: string[]) => findByProps(...props)[props[0]],
|
findExportedComponent: (...props: string[]) => findByProps(...props)[props[0]],
|
||||||
findStore: newFindWrapper(filters.byStoreName),
|
findStore: newFindWrapper(filters.byStoreName),
|
||||||
PluginsApi: Vencord.Plugins,
|
PluginsApi: { getter: () => Vencord.Plugins },
|
||||||
plugins: Vencord.Plugins.plugins,
|
plugins: { getter: () => Vencord.Plugins.plugins },
|
||||||
Settings: Vencord.Settings,
|
Settings: { getter: () => Vencord.Settings },
|
||||||
Api: Vencord.Api,
|
Api: { getter: () => Vencord.Api },
|
||||||
|
Util: { getter: () => Vencord.Util },
|
||||||
reload: () => location.reload(),
|
reload: () => location.reload(),
|
||||||
restart: IS_WEB ? WEB_ONLY("restart") : relaunch,
|
restart: IS_WEB ? DESKTOP_ONLY("restart") : relaunch,
|
||||||
canonicalizeMatch,
|
canonicalizeMatch,
|
||||||
canonicalizeReplace,
|
canonicalizeReplace,
|
||||||
canonicalizeReplacement,
|
canonicalizeReplacement,
|
||||||
fakeRender: (component: ComponentType, props: any) => {
|
fakeRender: (component: ComponentType, props: any) => {
|
||||||
const prevWin = fakeRenderWin?.deref();
|
const prevWin = fakeRenderWin?.deref();
|
||||||
const win = prevWin?.closed === false ? prevWin : window.open("about:blank", "Fake Render", "popup,width=500,height=500")!;
|
const win = prevWin?.closed === false
|
||||||
|
? prevWin
|
||||||
|
: window.open("about:blank", "Fake Render", "popup,width=500,height=500")!;
|
||||||
fakeRenderWin = new WeakRef(win);
|
fakeRenderWin = new WeakRef(win);
|
||||||
win.focus();
|
win.focus();
|
||||||
|
|
||||||
|
@ -115,21 +128,88 @@ export default definePlugin({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render(React.createElement(component, props), doc.body.appendChild(document.createElement("div")));
|
Common.ReactDOM.render(Common.React.createElement(component, props), doc.body.appendChild(document.createElement("div")));
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
preEnable: (plugin: string) => (Vencord.Settings.plugins[plugin] ??= { enabled: true }).enabled = true,
|
||||||
|
|
||||||
|
channel: { getter: () => getCurrentChannel(), preload: false },
|
||||||
|
channelId: { getter: () => Common.SelectedChannelStore.getChannelId(), preload: false },
|
||||||
|
guild: { getter: () => getCurrentGuild(), preload: false },
|
||||||
|
guildId: { getter: () => Common.SelectedGuildStore.getGuildId(), preload: false },
|
||||||
|
me: { getter: () => Common.UserStore.getCurrentUser(), preload: false },
|
||||||
|
meId: { getter: () => Common.UserStore.getCurrentUser().id, preload: false },
|
||||||
|
messages: { getter: () => Common.MessageStore.getMessages(Common.SelectedChannelStore.getChannelId()), preload: false }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadAndCacheShortcut(key: string, val: any, forceLoad: boolean) {
|
||||||
|
const currentVal = val.getter();
|
||||||
|
if (!currentVal || val.preload === false) return currentVal;
|
||||||
|
|
||||||
|
const value = currentVal[SYM_LAZY_GET]
|
||||||
|
? forceLoad ? currentVal[SYM_LAZY_GET]() : currentVal[SYM_LAZY_CACHED]
|
||||||
|
: currentVal;
|
||||||
|
|
||||||
|
if (value) define(window.shortcutList, key, { value });
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "ConsoleShortcuts",
|
||||||
|
description: "Adds shorter Aliases for many things on the window. Run `shortcutList` for a list.",
|
||||||
|
authors: [Devs.Ven],
|
||||||
|
|
||||||
|
startAt: StartAt.Init,
|
||||||
start() {
|
start() {
|
||||||
const shortcuts = this.getShortcuts();
|
const shortcuts = makeShortcuts();
|
||||||
window.shortcutList = shortcuts;
|
window.shortcutList = {};
|
||||||
for (const [key, val] of Object.entries(shortcuts))
|
|
||||||
|
for (const [key, val] of Object.entries(shortcuts)) {
|
||||||
|
if ("getter" in val) {
|
||||||
|
define(window.shortcutList, key, {
|
||||||
|
get: () => loadAndCacheShortcut(key, val, true)
|
||||||
|
});
|
||||||
|
|
||||||
|
define(window, key, {
|
||||||
|
get: () => window.shortcutList[key]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.shortcutList[key] = val;
|
||||||
window[key] = val;
|
window[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unproxy loaded modules
|
||||||
|
Webpack.onceReady.then(() => {
|
||||||
|
setTimeout(() => this.eagerLoad(false), 1000);
|
||||||
|
|
||||||
|
if (!IS_WEB) {
|
||||||
|
const Native = VencordNative.pluginHelpers.ConsoleShortcuts as PluginNative<typeof import("./native")>;
|
||||||
|
Native.initDevtoolsOpenEagerLoad();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async eagerLoad(forceLoad: boolean) {
|
||||||
|
await Webpack.onceReady;
|
||||||
|
|
||||||
|
const shortcuts = makeShortcuts();
|
||||||
|
|
||||||
|
for (const [key, val] of Object.entries(shortcuts)) {
|
||||||
|
if (!Object.hasOwn(val, "getter") || (val as any).preload === false) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
loadAndCacheShortcut(key, val, forceLoad);
|
||||||
|
} catch { } // swallow not found errors in DEV
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
delete window.shortcutList;
|
delete window.shortcutList;
|
||||||
for (const key in this.getShortcuts())
|
for (const key in makeShortcuts()) {
|
||||||
delete window[key];
|
delete window[key];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
16
src/plugins/consoleShortcuts/native.ts
Normal file
16
src/plugins/consoleShortcuts/native.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { IpcMainInvokeEvent } from "electron";
|
||||||
|
|
||||||
|
export function initDevtoolsOpenEagerLoad(e: IpcMainInvokeEvent) {
|
||||||
|
const handleDevtoolsOpened = () => e.sender.executeJavaScript("Vencord.Plugins.plugins.ConsoleShortcuts.eagerLoad(true)");
|
||||||
|
|
||||||
|
if (e.sender.isDevToolsOpened())
|
||||||
|
handleDevtoolsOpened();
|
||||||
|
else
|
||||||
|
e.sender.once("devtools-opened", () => handleDevtoolsOpened());
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ export default definePlugin({
|
||||||
type: OptionType.SELECT,
|
type: OptionType.SELECT,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
label: "Ctrl+Enter (Enter or Shift+Enter for new line)",
|
label: "Ctrl+Enter (Enter or Shift+Enter for new line) (cmd+enter on macOS)",
|
||||||
value: "ctrl+enter"
|
value: "ctrl+enter"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ export default definePlugin({
|
||||||
result = event.shiftKey;
|
result = event.shiftKey;
|
||||||
break;
|
break;
|
||||||
case "ctrl+enter":
|
case "ctrl+enter":
|
||||||
result = event.ctrlKey;
|
result = navigator.platform.includes("Mac") ? event.metaKey : event.ctrlKey;
|
||||||
break;
|
break;
|
||||||
case "enter":
|
case "enter":
|
||||||
result = !event.shiftKey && !event.ctrlKey;
|
result = !event.shiftKey && !event.ctrlKey;
|
||||||
|
|
|
@ -182,8 +182,8 @@ export default definePlugin({
|
||||||
|
|
||||||
// add dearrow button
|
// add dearrow button
|
||||||
{
|
{
|
||||||
match: /children:\[(?=null!=\i\?\i\.renderSuppressButton)/,
|
match: /children:\[(?=null!=\i\?(\i)\.renderSuppressButton)/,
|
||||||
replace: "children:[$self.renderButton(this),",
|
replace: "children:[$self.renderButton($1),",
|
||||||
predicate: () => !settings.store.hideButton
|
predicate: () => !settings.store.hideButton
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
35
src/plugins/dontRoundMyTimestamps/index.ts
Normal file
35
src/plugins/dontRoundMyTimestamps/index.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a modification for Discord's desktop app
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
import { moment } from "@webpack/common";
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "DontRoundMyTimestamps",
|
||||||
|
authors: [Devs.Lexi],
|
||||||
|
description: "Always rounds relative timestamps down, so 7.6y becomes 7y instead of 8y",
|
||||||
|
|
||||||
|
start() {
|
||||||
|
moment.relativeTimeRounding(Math.floor);
|
||||||
|
},
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
moment.relativeTimeRounding(Math.round);
|
||||||
|
}
|
||||||
|
});
|
|
@ -344,8 +344,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
// Patch the stickers array to add fake nitro stickers
|
// Patch the stickers array to add fake nitro stickers
|
||||||
predicate: () => settings.store.transformStickers,
|
predicate: () => settings.store.transformStickers,
|
||||||
match: /(?<=renderStickersAccessories\((\i)\){let (\i)=\(0,\i\.\i\)\(\i\).+?;)/,
|
match: /renderStickersAccessories\((\i)\){let (\i)=\(0,\i\.\i\)\(\i\).+?;/,
|
||||||
replace: (_, message, stickers) => `${stickers}=$self.patchFakeNitroStickers(${stickers},${message});`
|
replace: (m, message, stickers) => `${m}${stickers}=$self.patchFakeNitroStickers(${stickers},${message});`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Filter attachments to remove fake nitro stickers or emojis
|
// Filter attachments to remove fake nitro stickers or emojis
|
||||||
|
@ -813,7 +813,7 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
canUseEmote(e: Emoji, channelId: string) {
|
canUseEmote(e: Emoji, channelId: string) {
|
||||||
if (e.type === "UNICODE") return true;
|
if (e.type === 0) return true;
|
||||||
if (e.available === false) return false;
|
if (e.available === false) return false;
|
||||||
|
|
||||||
const isUnusableRoleSubEmoji = RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmojiOriginal ?? RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmoji;
|
const isUnusableRoleSubEmoji = RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmojiOriginal ?? RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmoji;
|
||||||
|
|
3
src/plugins/fakeProfileThemes/index.css
Normal file
3
src/plugins/fakeProfileThemes/index.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.vc-fpt-preview * {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
|
@ -17,13 +17,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// This plugin is a port from Alyxia's Vendetta plugin
|
// This plugin is a port from Alyxia's Vendetta plugin
|
||||||
|
import "./index.css";
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { copyWithToast } from "@utils/misc";
|
import { classes, copyWithToast } from "@utils/misc";
|
||||||
|
import { useAwaiter } from "@utils/react";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { Button, Forms } from "@webpack/common";
|
import { extractAndLoadChunksLazy, findComponentByCodeLazy } from "@webpack";
|
||||||
|
import { Button, Flex, Forms, React, Text, UserProfileStore, UserStore, useState } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
import virtualMerge from "virtual-merge";
|
import virtualMerge from "virtual-merge";
|
||||||
|
|
||||||
|
@ -81,6 +85,34 @@ const settings = definePluginSettings({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface ColorPickerProps {
|
||||||
|
color: number | null;
|
||||||
|
label: React.ReactElement;
|
||||||
|
showEyeDropper?: boolean;
|
||||||
|
suggestedColors?: string[];
|
||||||
|
onChange(value: number | null): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I can't be bothered to figure out the semantics of this component. The
|
||||||
|
// functions surely get some event argument sent to them and they likely aren't
|
||||||
|
// all required. If anyone who wants to use this component stumbles across this
|
||||||
|
// code, you'll have to do the research yourself.
|
||||||
|
interface ProfileModalProps {
|
||||||
|
user: User;
|
||||||
|
pendingThemeColors: [number, number];
|
||||||
|
onAvatarChange: () => void;
|
||||||
|
onBannerChange: () => void;
|
||||||
|
canUsePremiumCustomization: boolean;
|
||||||
|
hideExampleButton: boolean;
|
||||||
|
hideFakeActivity: boolean;
|
||||||
|
isTryItOutFlow: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)");
|
||||||
|
const ProfileModal = findComponentByCodeLazy<ProfileModalProps>('"ProfileCustomizationPreview"');
|
||||||
|
|
||||||
|
const requireColorPicker = extractAndLoadChunksLazy(["USER_SETTINGS_PROFILE_COLOR_DEFAULT_BUTTON.format"], /createPromise:\(\)=>\i\.\i\("(.+?)"\).then\(\i\.bind\(\i,"(.+?)"\)\)/);
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "FakeProfileThemes",
|
name: "FakeProfileThemes",
|
||||||
description: "Allows profile theming by hiding the colors in your bio thanks to invisible 3y3 encoding",
|
description: "Allows profile theming by hiding the colors in your bio thanks to invisible 3y3 encoding",
|
||||||
|
@ -101,21 +133,98 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
settingsAboutComponent: () => (
|
settingsAboutComponent: () => {
|
||||||
|
const existingColors = decode(
|
||||||
|
UserProfileStore.getUserProfile(UserStore.getCurrentUser().id).bio
|
||||||
|
) ?? [0, 0];
|
||||||
|
const [color1, setColor1] = useState(existingColors[0]);
|
||||||
|
const [color2, setColor2] = useState(existingColors[1]);
|
||||||
|
|
||||||
|
const [, , loadingColorPickerChunk] = useAwaiter(requireColorPicker);
|
||||||
|
|
||||||
|
return (
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<Forms.FormTitle tag="h3">Usage</Forms.FormTitle>
|
<Forms.FormTitle tag="h3">Usage</Forms.FormTitle>
|
||||||
<Forms.FormText>
|
<Forms.FormText>
|
||||||
After enabling this plugin, you will see custom colors in the profiles of other people using compatible plugins. <br />
|
After enabling this plugin, you will see custom colors in
|
||||||
|
the profiles of other people using compatible plugins.{" "}
|
||||||
|
<br />
|
||||||
To set your own colors:
|
To set your own colors:
|
||||||
<ul>
|
<ul>
|
||||||
<li>• go to your profile settings</li>
|
<li>
|
||||||
<li>• choose your own colors in the Nitro preview</li>
|
• use the color pickers below to choose your colors
|
||||||
|
</li>
|
||||||
<li>• click the "Copy 3y3" button</li>
|
<li>• click the "Copy 3y3" button</li>
|
||||||
<li>• paste the invisible text anywhere in your bio</li>
|
<li>• paste the invisible text anywhere in your bio</li>
|
||||||
</ul><br />
|
</ul><br />
|
||||||
<b>Please note:</b> if you are using a theme which hides nitro ads, you should disable it temporarily to set colors.
|
<Forms.FormDivider
|
||||||
|
className={classes(Margins.top8, Margins.bottom8)}
|
||||||
|
/>
|
||||||
|
<Forms.FormTitle tag="h3">Color pickers</Forms.FormTitle>
|
||||||
|
{!loadingColorPickerChunk && (
|
||||||
|
<Flex
|
||||||
|
direction={Flex.Direction.HORIZONTAL}
|
||||||
|
style={{ gap: "1rem" }}
|
||||||
|
>
|
||||||
|
<ColorPicker
|
||||||
|
color={color1}
|
||||||
|
label={
|
||||||
|
<Text
|
||||||
|
variant={"text-xs/normal"}
|
||||||
|
style={{ marginTop: "4px" }}
|
||||||
|
>
|
||||||
|
Primary
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
|
onChange={(color: number) => {
|
||||||
|
setColor1(color);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ColorPicker
|
||||||
|
color={color2}
|
||||||
|
label={
|
||||||
|
<Text
|
||||||
|
variant={"text-xs/normal"}
|
||||||
|
style={{ marginTop: "4px" }}
|
||||||
|
>
|
||||||
|
Accent
|
||||||
|
</Text>
|
||||||
|
}
|
||||||
|
onChange={(color: number) => {
|
||||||
|
setColor2(color);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
const colorString = encode(color1, color2);
|
||||||
|
copyWithToast(colorString);
|
||||||
|
}}
|
||||||
|
color={Button.Colors.PRIMARY}
|
||||||
|
size={Button.Sizes.XLARGE}
|
||||||
|
>
|
||||||
|
Copy 3y3
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
<Forms.FormDivider
|
||||||
|
className={classes(Margins.top8, Margins.bottom8)}
|
||||||
|
/>
|
||||||
|
<Forms.FormTitle tag="h3">Preview</Forms.FormTitle>
|
||||||
|
<div className="vc-fpt-preview">
|
||||||
|
<ProfileModal
|
||||||
|
user={UserStore.getCurrentUser()}
|
||||||
|
pendingThemeColors={[color1, color2]}
|
||||||
|
onAvatarChange={() => { }}
|
||||||
|
onBannerChange={() => { }}
|
||||||
|
canUsePremiumCustomization={true}
|
||||||
|
hideExampleButton={true}
|
||||||
|
hideFakeActivity={true}
|
||||||
|
isTryItOutFlow={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
</Forms.FormSection>),
|
</Forms.FormSection>);
|
||||||
|
},
|
||||||
settings,
|
settings,
|
||||||
colorDecodeHook(user: UserProfile) {
|
colorDecodeHook(user: UserProfile) {
|
||||||
if (user) {
|
if (user) {
|
||||||
|
|
|
@ -52,6 +52,8 @@ export default definePlugin({
|
||||||
|
|
||||||
getFriendSince(userId: string) {
|
getFriendSince(userId: string) {
|
||||||
try {
|
try {
|
||||||
|
if (!RelationshipStore.isFriend(userId)) return null;
|
||||||
|
|
||||||
return RelationshipStore.getSince(userId);
|
return RelationshipStore.getSince(userId);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
new Logger("FriendsSince").error(err);
|
new Logger("FriendsSince").error(err);
|
||||||
|
@ -60,6 +62,8 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
friendsSince: ErrorBoundary.wrap(({ userId, textClassName }: { userId: string; textClassName?: string; }) => {
|
friendsSince: ErrorBoundary.wrap(({ userId, textClassName }: { userId: string; textClassName?: string; }) => {
|
||||||
|
if (!RelationshipStore.isFriend(userId)) return null;
|
||||||
|
|
||||||
const friendsSince = RelationshipStore.getSince(userId);
|
const friendsSince = RelationshipStore.getSince(userId);
|
||||||
if (!friendsSince) return null;
|
if (!friendsSince) return null;
|
||||||
|
|
||||||
|
|
|
@ -228,15 +228,15 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".activityTitleText,variant",
|
find: ".activityTitleText,variant",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=\i\.activityTitleText.+?children:(\i)\.name.*?}\),)/,
|
match: /\.activityTitleText.+?children:(\i)\.name.*?}\),/,
|
||||||
replace: (_, props) => `$self.renderToggleActivityButton(${props}),`
|
replace: (m, props) => `${m}$self.renderToggleActivityButton(${props}),`
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".activityCardDetails,children",
|
find: ".activityCardDetails,children",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=\i\.activityCardDetails.+?children:(\i\.application)\.name.*?}\),)/,
|
match: /\.activityCardDetails.+?children:(\i\.application)\.name.*?}\),/,
|
||||||
replace: (_, props) => `$self.renderToggleActivityButton(${props}),`
|
replace: (m, props) => `${m}$self.renderToggleActivityButton(${props}),`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -67,15 +67,18 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const syncVideos = () => {
|
const syncVideos = () => {
|
||||||
currentVideoElementRef.current!.currentTime = originalVideoElementRef.current!.currentTime;
|
if (currentVideoElementRef.current && originalVideoElementRef.current)
|
||||||
|
currentVideoElementRef.current.currentTime = originalVideoElementRef.current.currentTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMousePosition = (e: MouseEvent) => {
|
const updateMousePosition = (e: MouseEvent) => {
|
||||||
|
if (!element.current) return;
|
||||||
|
|
||||||
if (instance.state.mouseOver && instance.state.mouseDown) {
|
if (instance.state.mouseOver && instance.state.mouseDown) {
|
||||||
const offset = size.current / 2;
|
const offset = size.current / 2;
|
||||||
const pos = { x: e.pageX, y: e.pageY };
|
const pos = { x: e.pageX, y: e.pageY };
|
||||||
const x = -((pos.x - element.current!.getBoundingClientRect().left) * zoom.current - offset);
|
const x = -((pos.x - element.current.getBoundingClientRect().left) * zoom.current - offset);
|
||||||
const y = -((pos.y - element.current!.getBoundingClientRect().top) * zoom.current - offset);
|
const y = -((pos.y - element.current.getBoundingClientRect().top) * zoom.current - offset);
|
||||||
setLensPosition({ x: e.x - offset, y: e.y - offset });
|
setLensPosition({ x: e.x - offset, y: e.y - offset });
|
||||||
setImagePosition({ x, y });
|
setImagePosition({ x, y });
|
||||||
setOpacity(1);
|
setOpacity(1);
|
||||||
|
@ -184,6 +187,7 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
||||||
src={originalVideoElementRef.current?.src ?? instance.props.src}
|
src={originalVideoElementRef.current?.src ?? instance.props.src}
|
||||||
autoPlay
|
autoPlay
|
||||||
loop
|
loop
|
||||||
|
muted
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<img
|
<img
|
||||||
|
|
|
@ -18,88 +18,82 @@
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
import presetQuotesText from "file://quotes.txt";
|
||||||
|
|
||||||
// These are Xor encrypted to prevent you from spoiling yourself when you read the source code.
|
const presetQuotes = presetQuotesText.split("\n").map(quote => /^\s*[^#\s]/.test(quote) && quote.trim()).filter(Boolean) as string[];
|
||||||
// don't worry about it :P
|
const noQuotesQuote = "Did you really disable all loading quotes? What a buffoon you are...";
|
||||||
const quotes = [
|
|
||||||
"Eyrokac",
|
|
||||||
"Rdcg$l`'k|~n",
|
|
||||||
'H`tf$d&iajo+d`{"',
|
|
||||||
"Sucqplh`(Eclhualva()&",
|
|
||||||
"Lncgmka'8KNMDC,shpanf'`x./,",
|
|
||||||
"Ioqweijnfn*IeuvfvAotkfxo./,",
|
|
||||||
'Hd{#cp\x7Ft$)nbd!{lq%mig~*\x7Fh`v#mk&sm{gx nd#idjb(a\x7Ffao"bja&amdkge!Rloìkhf)hyedfjjb*\'^hzdrdmm$lu\'|ao+mnqw$fijxh~bbmg#Tjmîefd+fnp#lpkffz5',
|
|
||||||
"h",
|
|
||||||
"sijklm&cam*rot\"hjjq'|ak\x7F xmv#wc'ep*mawmvvlrb(|ynr>\"Aqq&cgg-\x7F ugoh%rom)e\x7Fhdpp%$",
|
|
||||||
'Tnfb}"u\'~`nno!kp$vvhfzeyee"a}%Tfam*Xh`fls%Jboldos-"lj`&hn)~ce!`jcbct|)gdbhnf$wikm$zgaxkmc%afely+og"144?\'ign+iu%p$qisiefr gpfa$',
|
|
||||||
"Ndtfv%ahfgk+ghtf$|ir(|z' Oguaw&`ggdj mgw$|ir(me|n",
|
|
||||||
"(!ͣ³$͙ʐ'ͩ¹#",
|
|
||||||
"(ネ◗ロ◑,マ-2ャユ✬",
|
|
||||||
"Ynw#hjil(ze+psgwp|&sgmkr!",
|
|
||||||
"Tikmolh`(fl+a!dvjk\x7F'y|e\x7Fe/,-",
|
|
||||||
"3/3750?5><9>885:7",
|
|
||||||
"mdmt",
|
|
||||||
"Wdn`khc+(oxbeof",
|
|
||||||
'Ig"zkp*\'g{*xolglj`&~g|*gowg/$mgt(Eclm`.#ticf{l*xed"wl`&Kangj igbhqn\'d`dn `v#lqrw{3%$bhv-h|)kangj_imwhlhb',
|
|
||||||
"Tscmw%Tnoa~x",
|
|
||||||
"I‘f#npus(ec`e!vl$lhsm{`ncu\"ekw&f(defeov-$Rnf|)sdu‘pf$wcam{ceg!vl$du'D`d~x-\"jw%oi(okht-\"DJP)Kags,!mq$du'A‐|n sg`akrkq)~jkdl#pj&diefbnf\"jp)&@F\\*{ltq#Hlhrp'",
|
|
||||||
"Ynw$v`&cg`dl fml`%rhlhs*",
|
|
||||||
"Dnl$p%qhz{s' hv$w%hh|aceg!;#gpvt(fl+cndea`&dg|fon&v#wjjqm(",
|
|
||||||
"\ud83d)pft`gs(ec`e!13$qojmz#",
|
|
||||||
"a!njcmr'ide~nu\"lb%rheoedldpz$lu'gbkr",
|
|
||||||
"dn\"zkp&kgo4",
|
|
||||||
"hnpqkw",
|
|
||||||
"sn\"fau",
|
|
||||||
"Sn\"tmqnh}}*musvkaw&flf&+ldv$w%lr{}*aulr#vlao|)cetn\"jp$",
|
|
||||||
"Dxkmc%ot(hhxomwwai'{hln",
|
|
||||||
"hd{#}js&(pe~'sg#gprb(3#\"",
|
|
||||||
"hd{b${",
|
|
||||||
"<;vqkijbq33271:56<3799?24944:",
|
|
||||||
"Thof$lu'ofdn,!qsefc'az*bnrcma+&Om{o+iu\"`khct$)bnrd\"bcdoi&",
|
|
||||||
"snofplkb{)c'r\"lod'|f*aurv#cpno`abchijklmno",
|
|
||||||
"Wdn`khc'|f*eghl{%"
|
|
||||||
];
|
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
replaceEvents: {
|
replaceEvents: {
|
||||||
description: "Replace Event Quotes too",
|
description: "Should this plugin also apply during events with special event themed quotes? (e.g. Halloween)",
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
default: true
|
default: true
|
||||||
}
|
},
|
||||||
|
enablePluginPresetQuotes: {
|
||||||
|
description: "Enable the quotes preset by this plugin",
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
enableDiscordPresetQuotes: {
|
||||||
|
description: "Enable Discord's preset quotes (including event quotes, during events)",
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
additionalQuotes: {
|
||||||
|
description: "Additional custom quotes to possibly appear, separated by the below delimiter",
|
||||||
|
type: OptionType.STRING,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
additionalQuotesDelimiter: {
|
||||||
|
description: "Delimiter for additional quotes",
|
||||||
|
type: OptionType.STRING,
|
||||||
|
default: "|",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "LoadingQuotes",
|
name: "LoadingQuotes",
|
||||||
description: "Replace Discords loading quotes",
|
description: "Replace Discords loading quotes",
|
||||||
authors: [Devs.Ven, Devs.KraXen72],
|
authors: [Devs.Ven, Devs.KraXen72, Devs.UlyssesZhan],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: ".LOADING_DID_YOU_KNOW}",
|
find: ".LOADING_DID_YOU_KNOW",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /"_loadingText",function\(\)\{/,
|
match: /"_loadingText".+?(?=(\i)\[.{0,10}\.random)/,
|
||||||
replace: "$&return $self.quote;",
|
replace: "$&$self.mutateQuotes($1),"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /"_eventLoadingText",function\(\)\{/,
|
match: /"_eventLoadingText".+?(?=(\i)\[.{0,10}\.random)/,
|
||||||
replace: "$&return $self.quote;",
|
replace: "$&$self.mutateQuotes($1),",
|
||||||
predicate: () => settings.store.replaceEvents
|
predicate: () => settings.store.replaceEvents
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
xor(quote: string) {
|
mutateQuotes(quotes: string[]) {
|
||||||
const key = "read if cute";
|
try {
|
||||||
const codes = Array.from(quote, (s, i) => s.charCodeAt(0) ^ (i % key.length));
|
const { enableDiscordPresetQuotes, additionalQuotes, additionalQuotesDelimiter, enablePluginPresetQuotes } = settings.store;
|
||||||
return String.fromCharCode(...codes);
|
|
||||||
},
|
|
||||||
|
|
||||||
get quote() {
|
if (!enableDiscordPresetQuotes)
|
||||||
return this.xor(quotes[Math.floor(Math.random() * quotes.length)]);
|
quotes.length = 0;
|
||||||
|
|
||||||
|
|
||||||
|
if (enablePluginPresetQuotes)
|
||||||
|
quotes.push(...presetQuotes);
|
||||||
|
|
||||||
|
quotes.push(...additionalQuotes.split(additionalQuotesDelimiter).filter(Boolean));
|
||||||
|
|
||||||
|
if (!quotes.length)
|
||||||
|
quotes.push(noQuotesQuote);
|
||||||
|
} catch (e) {
|
||||||
|
new Logger("LoadingQuotes").error("Failed to mutate quotes", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
37
src/plugins/loadingQuotes/quotes.txt
Normal file
37
src/plugins/loadingQuotes/quotes.txt
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Blank lines and lines starting with "#" are ignored
|
||||||
|
|
||||||
|
Explode
|
||||||
|
Read if cute
|
||||||
|
Have a nice day!
|
||||||
|
Starting Lightcord...
|
||||||
|
Loading 0BDFDB.plugin.js...
|
||||||
|
Installing BetterDiscord...
|
||||||
|
h
|
||||||
|
shhhhh did you know that you're my favourite user? But don't tell the others!!
|
||||||
|
Today's video is sponsored by Raid Shadow Legends, one of the biggest mobile role-playing games of 2019 and it's totally free!
|
||||||
|
Never gonna give you up, Never gonna let you down
|
||||||
|
( ͡° ͜ʖ ͡°)
|
||||||
|
(ノ◕ヮ◕)ノ*:・゚✧
|
||||||
|
You look so pretty today!
|
||||||
|
Thinking of a funny quote...
|
||||||
|
3.141592653589793
|
||||||
|
meow
|
||||||
|
Welcome, friend
|
||||||
|
If you, or someone you love, has Ligma, please see the Ligma health line at https://bit.ly/ligma_hotline
|
||||||
|
Trans Rights
|
||||||
|
I’d just like to interject for a moment. What you’re refering to as Linux, is in fact, GNU/Linux, or as I’ve recently taken to calling it, GNU plus Linux.
|
||||||
|
You're doing good today!
|
||||||
|
Don't worry, it's nothing 9 cups of coffee couldn't solve!
|
||||||
|
<EFBFBD>(repeat like 30 times)
|
||||||
|
a light amount of tomfoolery is okay
|
||||||
|
do you love?
|
||||||
|
horror
|
||||||
|
so eepy
|
||||||
|
So without further ado, let's just jump right into it!
|
||||||
|
Dying is absolutely safe
|
||||||
|
hey you! you're cute :))
|
||||||
|
heya ~
|
||||||
|
<:trolley:997086295010594867>
|
||||||
|
Time is gone, space is insane. Here it comes, here again.
|
||||||
|
sometimes it's okay to just guhhhhhhhhhhhhhh
|
||||||
|
Welcome to nginx!
|
5
src/plugins/maskedLinkPaste/README.md
Normal file
5
src/plugins/maskedLinkPaste/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# MaskedLinkPaste
|
||||||
|
|
||||||
|
Pasting a link while you have text selected will paste your link as a masked link at that location
|
||||||
|
|
||||||
|
![](https://github.com/Vendicated/Vencord/assets/78964224/1d3be2c6-7957-44c9-92ec-551069d46c02)
|
36
src/plugins/maskedLinkPaste/index.ts
Normal file
36
src/plugins/maskedLinkPaste/index.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants.js";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
import { findByPropsLazy } from "@webpack";
|
||||||
|
|
||||||
|
const linkRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
||||||
|
|
||||||
|
const { SlateTransforms } = findByPropsLazy("SlateTransforms");
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "MaskedLinkPaste",
|
||||||
|
authors: [Devs.TheSun],
|
||||||
|
description: "Pasting a link while having text selected will paste a hyperlink",
|
||||||
|
patches: [{
|
||||||
|
find: ".selection,preventEmojiSurrogates:",
|
||||||
|
replacement: {
|
||||||
|
match: /(?<=SlateTransforms.delete.{0,50})(\i)\.insertText\((\i)\)/,
|
||||||
|
replace: "$self.handlePaste($1, $2, () => $&)"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
|
||||||
|
handlePaste(editor, content: string, originalBehavior: () => void) {
|
||||||
|
if (content && linkRegex.test(content) && editor.operations?.[0]?.type === "remove_text") {
|
||||||
|
SlateTransforms.insertText(
|
||||||
|
editor,
|
||||||
|
`[${editor.operations[0].text}](${content})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else originalBehavior();
|
||||||
|
}
|
||||||
|
});
|
|
@ -70,8 +70,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".invitesDisabledTooltip",
|
find: ".invitesDisabledTooltip",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=\.VIEW_AS_ROLES_MENTIONS_WARNING.{0,100})]/,
|
match: /\.VIEW_AS_ROLES_MENTIONS_WARNING.{0,100}(?=])/,
|
||||||
replace: ",$self.renderTooltip(arguments[0].guild)]"
|
replace: "$&,$self.renderTooltip(arguments[0].guild)"
|
||||||
},
|
},
|
||||||
predicate: () => settings.store.toolTip
|
predicate: () => settings.store.toolTip
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,9 @@ export default definePlugin({
|
||||||
// Message wasn't received through gateway
|
// Message wasn't received through gateway
|
||||||
if (!isNonNullish(nonce)) return null;
|
if (!isNonNullish(nonce)) return null;
|
||||||
|
|
||||||
|
// Bots basically never send a nonce, and if someone does do it then it's usually not a snowflake
|
||||||
|
if (message.bot) return null;
|
||||||
|
|
||||||
let isDiscordKotlin = false;
|
let isDiscordKotlin = false;
|
||||||
let delta = SnowflakeUtils.extractTimestamp(id) - SnowflakeUtils.extractTimestamp(nonce); // milliseconds
|
let delta = SnowflakeUtils.extractTimestamp(id) - SnowflakeUtils.extractTimestamp(nonce); // milliseconds
|
||||||
if (!showMillis) {
|
if (!showMillis) {
|
||||||
|
|
|
@ -376,6 +376,9 @@ export default definePlugin({
|
||||||
if (!messageLinkRegex.test(props.message.content))
|
if (!messageLinkRegex.test(props.message.content))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
// need to reset the regex because it's global
|
||||||
|
messageLinkRegex.lastIndex = 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<MessageEmbedAccessory
|
<MessageEmbedAccessory
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
color: var(--status-danger, #f04747) !important;
|
color: var(--status-danger, #f04747) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Markdown title highlighting */
|
||||||
|
.messagelogger-deleted [class*="contents"] :is(h1, h2, h3) {
|
||||||
|
color: var(--status-danger, #f04747) !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Bot "thinking" text highlighting */
|
/* Bot "thinking" text highlighting */
|
||||||
.messagelogger-deleted [class*="colorStandard"] {
|
.messagelogger-deleted [class*="colorStandard"] {
|
||||||
color: var(--status-danger, #f04747) !important;
|
color: var(--status-danger, #f04747) !important;
|
||||||
|
|
|
@ -295,12 +295,9 @@ export default definePlugin({
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
// Pass through editHistory & deleted & original attachments to the "edited message" transformer
|
// Pass through editHistory & deleted & original attachments to the "edited message" transformer
|
||||||
match: /interactionData:(\i)\.interactionData/,
|
match: /(?<=null!=\i\.edited_timestamp\)return )\i\(\i,\{reactions:(\i)\.reactions.{0,50}\}\)/,
|
||||||
replace:
|
replace:
|
||||||
"interactionData:$1.interactionData," +
|
"Object.assign($&,{ deleted:$1.deleted, editHistory:$1.editHistory, attachments:$1.attachments })"
|
||||||
"deleted:$1.deleted," +
|
|
||||||
"editHistory:$1.editHistory," +
|
|
||||||
"attachments:$1.attachments"
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
// {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
.emoji,
|
.emoji,
|
||||||
[data-type="sticker"],
|
[data-type="sticker"],
|
||||||
iframe,
|
iframe,
|
||||||
.messagelogger-deleted-attachment,
|
.messagelogger-deleted-attachment:not([class*="hiddenAttachment_"]),
|
||||||
[class|="inlineMediaEmbed"]
|
[class|="inlineMediaEmbed"]
|
||||||
) {
|
) {
|
||||||
filter: grayscale(1) !important;
|
filter: grayscale(1) !important;
|
||||||
|
|
|
@ -111,8 +111,8 @@ export default definePlugin({
|
||||||
replace: "$self.getScrollOffset(arguments[0],$1,this.props.padding,this.state.preRenderedChildren,$&)"
|
replace: "$self.getScrollOffset(arguments[0],$1,this.props.padding,this.state.preRenderedChildren,$&)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /(?<=scrollToChannel\(\i\){.{1,300})this\.props\.privateChannelIds/,
|
match: /(scrollToChannel\(\i\){.{1,300})(this\.props\.privateChannelIds)/,
|
||||||
replace: "[...$&,...$self.getAllUncollapsedChannels()]"
|
replace: "$1[...$2,...$self.getAllUncollapsedChannels()]"
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { ChannelStore, FluxDispatcher as Dispatcher, MessageStore, PermissionsBi
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
const Kangaroo = findByPropsLazy("jumpToMessage");
|
const Kangaroo = findByPropsLazy("jumpToMessage");
|
||||||
|
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
||||||
|
|
||||||
const isMac = navigator.platform.includes("Mac"); // bruh
|
const isMac = navigator.platform.includes("Mac"); // bruh
|
||||||
let replyIdx = -1;
|
let replyIdx = -1;
|
||||||
|
@ -139,6 +140,10 @@ function getNextMessage(isUp: boolean, isReply: boolean) {
|
||||||
messages = messages.filter(m => m.author.id === meId);
|
messages = messages.filter(m => m.author.id === meId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Vencord.Plugins.isPluginEnabled("NoBlockedMessages")) {
|
||||||
|
messages = messages.filter(m => !RelationshipStore.isBlocked(m.author.id));
|
||||||
|
}
|
||||||
|
|
||||||
const mutate = (i: number) => isUp
|
const mutate = (i: number) => isUp
|
||||||
? Math.min(messages.length - 1, i + 1)
|
? Math.min(messages.length - 1, i + 1)
|
||||||
: Math.max(-1, i - 1);
|
: Math.max(-1, i - 1);
|
||||||
|
|
|
@ -37,7 +37,7 @@ const settings = definePluginSettings({
|
||||||
});
|
});
|
||||||
|
|
||||||
function search(src: string, engine: string) {
|
function search(src: string, engine: string) {
|
||||||
open(engine + encodeURIComponent(src), "_blank");
|
open(engine + encodeURIComponent(src.trim()), "_blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeSearchItem(src: string) {
|
function makeSearchItem(src: string) {
|
||||||
|
|
|
@ -134,8 +134,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: '"MessageActionCreators"',
|
find: '"MessageActionCreators"',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=focusMessage\(\i\){.+?)(?=focus:{messageId:(\i)})/,
|
match: /focusMessage\(\i\){.+?(?=focus:{messageId:(\i)})/,
|
||||||
replace: "after:$1,"
|
replace: "$&after:$1,"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Force Server Home instead of Server Guide
|
// Force Server Home instead of Server Guide
|
||||||
|
|
9
src/plugins/seeSummaries/README.md
Normal file
9
src/plugins/seeSummaries/README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Summaries
|
||||||
|
|
||||||
|
Enables Discord's experimental Summaries feature on every server, displaying AI generated summaries of conversations.
|
||||||
|
|
||||||
|
Read more about summaries in the [official Discord help article](https://support.discord.com/hc/en-us/articles/12926016807575-In-Channel-Conversation-Summaries)!
|
||||||
|
|
||||||
|
Note that this plugin can't fetch old summaries, it can only display ones created while your Discord is running with the plugin enabled.
|
||||||
|
|
||||||
|
![](https://github.com/Vendicated/Vencord/assets/45497981/bd931b0c-2e85-4c10-9f7c-8ba01eb55745)
|
115
src/plugins/seeSummaries/index.tsx
Normal file
115
src/plugins/seeSummaries/index.tsx
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { DataStore } from "@api/index";
|
||||||
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
import { findByPropsLazy } from "@webpack";
|
||||||
|
import { ChannelStore, GuildStore } from "@webpack/common";
|
||||||
|
|
||||||
|
const SummaryStore = findByPropsLazy("allSummaries", "findSummary");
|
||||||
|
const { createSummaryFromServer } = findByPropsLazy("createSummaryFromServer");
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
summaryExpiryThresholdDays: {
|
||||||
|
type: OptionType.SLIDER,
|
||||||
|
description: "The time in days before a summary is removed. Note that only up to 50 summaries are kept per channel",
|
||||||
|
markers: [1, 3, 5, 7, 10, 15, 20, 25, 30],
|
||||||
|
stickToMarkers: false,
|
||||||
|
default: 3,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Summary {
|
||||||
|
count: number;
|
||||||
|
end_id: string;
|
||||||
|
id: string;
|
||||||
|
message_ids: string[];
|
||||||
|
people: string[];
|
||||||
|
source: number;
|
||||||
|
start_id: string;
|
||||||
|
summ_short: string;
|
||||||
|
topic: string;
|
||||||
|
type: number;
|
||||||
|
unsafe: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChannelSummaries {
|
||||||
|
type: string;
|
||||||
|
channel_id: string;
|
||||||
|
guild_id: string;
|
||||||
|
summaries: Summary[];
|
||||||
|
|
||||||
|
// custom property
|
||||||
|
time?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "Summaries",
|
||||||
|
description: "Enables Discord's experimental Summaries feature on every server, displaying AI generated summaries of conversations",
|
||||||
|
authors: [Devs.mantikafasi],
|
||||||
|
settings,
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "ChannelTypesSets.SUMMARIZEABLE.has",
|
||||||
|
replacement: {
|
||||||
|
match: /\i\.hasFeature\(\i\.GuildFeatures\.SUMMARIES_ENABLED\w+?\)/g,
|
||||||
|
replace: "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
find: "RECEIVE_CHANNEL_SUMMARY(",
|
||||||
|
replacement: {
|
||||||
|
match: /shouldFetch\((\i),\i\){/,
|
||||||
|
replace: "$& if(!$self.shouldFetch($1)) return false;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
flux: {
|
||||||
|
CONVERSATION_SUMMARY_UPDATE(data) {
|
||||||
|
const incomingSummaries: ChannelSummaries[] = data.summaries.map((summary: any) => ({ ...createSummaryFromServer(summary), time: Date.now() }));
|
||||||
|
|
||||||
|
// idk if this is good for performance but it doesnt seem to be a problem in my experience
|
||||||
|
DataStore.update("summaries-data", summaries => {
|
||||||
|
summaries ??= {};
|
||||||
|
summaries[data.channel_id] ? summaries[data.channel_id].unshift(...incomingSummaries) : (summaries[data.channel_id] = incomingSummaries);
|
||||||
|
if (summaries[data.channel_id].length > 50)
|
||||||
|
summaries[data.channel_id] = summaries[data.channel_id].slice(0, 50);
|
||||||
|
|
||||||
|
return summaries;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
await DataStore.update("summaries-data", summaries => {
|
||||||
|
summaries ??= {};
|
||||||
|
for (const key of Object.keys(summaries)) {
|
||||||
|
for (let i = summaries[key].length - 1; i >= 0; i--) {
|
||||||
|
if (summaries[key][i].time < Date.now() - 1000 * 60 * 60 * 24 * settings.store.summaryExpiryThresholdDays) {
|
||||||
|
summaries[key].splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (summaries[key].length === 0) {
|
||||||
|
delete summaries[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(SummaryStore.allSummaries(), summaries);
|
||||||
|
return summaries;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldFetch(channelId: string) {
|
||||||
|
const channel = ChannelStore.getChannel(channelId);
|
||||||
|
// SUMMARIES_ENABLED feature is not in discord-types
|
||||||
|
const guild = GuildStore.getGuild(channel.guild_id);
|
||||||
|
// @ts-ignore
|
||||||
|
return guild.hasFeature("SUMMARIES_ENABLED_GA");
|
||||||
|
}
|
||||||
|
});
|
|
@ -21,8 +21,7 @@ import "./shiki.css";
|
||||||
import { enableStyle } from "@api/Styles";
|
import { enableStyle } from "@api/Styles";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import previewExampleText from "file://previewExample.tsx";
|
||||||
import previewExampleText from "~fileContent/previewExample.tsx";
|
|
||||||
|
|
||||||
import { shiki } from "./api/shiki";
|
import { shiki } from "./api/shiki";
|
||||||
import { createHighlighter } from "./components/Highlighter";
|
import { createHighlighter } from "./components/Highlighter";
|
||||||
|
|
|
@ -89,8 +89,8 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Remove permission checking for getRenderLevel function
|
// Remove permission checking for getRenderLevel function
|
||||||
{
|
{
|
||||||
match: /(?<=getRenderLevel\(\i\){.+?return)!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL,this\.record\)\|\|/,
|
match: /(getRenderLevel\(\i\){.+?return)!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL,this\.record\)\|\|/,
|
||||||
replace: " "
|
replace: (_, rest) => `${rest} `
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -159,8 +159,8 @@ export default definePlugin({
|
||||||
replacement: [
|
replacement: [
|
||||||
// Make the channel appear as muted if it's hidden
|
// Make the channel appear as muted if it's hidden
|
||||||
{
|
{
|
||||||
match: /(?<={channel:(\i),name:\i,muted:(\i).+?;)/,
|
match: /{channel:(\i),name:\i,muted:(\i).+?;/,
|
||||||
replace: (_, channel, muted) => `${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
|
replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
|
||||||
},
|
},
|
||||||
// Add the hidden eye icon if the channel is hidden
|
// Add the hidden eye icon if the channel is hidden
|
||||||
{
|
{
|
||||||
|
@ -186,8 +186,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
// Hide unreads
|
// Hide unreads
|
||||||
predicate: () => settings.store.hideUnreads === true,
|
predicate: () => settings.store.hideUnreads === true,
|
||||||
match: /(?<={channel:(\i),name:\i,.+?unread:(\i).+?;)/,
|
match: /{channel:(\i),name:\i,.+?unread:(\i).+?;/,
|
||||||
replace: (_, channel, unread) => `${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
|
replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -80,11 +80,19 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: "auto_removed:",
|
find: "prod_discoverable_guilds",
|
||||||
predicate: () => settings.store.disableDiscoveryFilters,
|
predicate: () => settings.store.disableDiscoveryFilters,
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /filters:\i\.join\(" AND "\),facets:\[/,
|
match: /\{"auto_removed:.*?\}/,
|
||||||
replace: "facets:["
|
replace: "{}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
find: "MINIMUM_MEMBER_COUNT:",
|
||||||
|
predicate: () => settings.store.disableDiscoveryFilters,
|
||||||
|
replacement: {
|
||||||
|
match: /MINIMUM_MEMBER_COUNT:function\(\)\{return \i}/,
|
||||||
|
replace: "MINIMUM_MEMBER_COUNT:() => \">0\""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,8 +60,8 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
predicate: () => settings.store.keepSpotifyActivityOnIdle,
|
predicate: () => settings.store.keepSpotifyActivityOnIdle,
|
||||||
match: /(?<=shouldShowActivity\(\){.{0,50})&&!\i\.\i\.isIdle\(\)/,
|
match: /(shouldShowActivity\(\){.{0,50})&&!\i\.\i\.isIdle\(\)/,
|
||||||
replace: ""
|
replace: "$1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ",BURST_REACTION_EFFECT_PLAY",
|
find: ",BURST_REACTION_EFFECT_PLAY",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=BURST_REACTION_EFFECT_PLAY:\i=>{.{50,100})(\i\(\i,\i\))>=\d+/,
|
match: /(BURST_REACTION_EFFECT_PLAY:\i=>{.{50,100})(\i\(\i,\i\))>=\d+/,
|
||||||
replace: "!$self.shouldPlayBurstReaction($1)"
|
replace: "$1!$self.shouldPlayBurstReaction($2)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,10 +27,10 @@ import style from "./index.css?managed";
|
||||||
const API_URL = "https://usrbg.is-hardly.online/users";
|
const API_URL = "https://usrbg.is-hardly.online/users";
|
||||||
|
|
||||||
interface UsrbgApiReturn {
|
interface UsrbgApiReturn {
|
||||||
endpoint: string
|
endpoint: string;
|
||||||
bucket: string
|
bucket: string;
|
||||||
prefix: string
|
prefix: string;
|
||||||
users: Record<string, string>
|
users: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
|
@ -73,6 +73,19 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
find: /overrideBannerSrc:\i,profileType:/,
|
||||||
|
replacement: [
|
||||||
|
{
|
||||||
|
match: /(\i)\.premiumType/,
|
||||||
|
replace: "$self.premiumHook($1)||$&"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
match: /(?<=function \i\((\i)\)\{)(?=var.{30,50},overrideBannerSrc:)/,
|
||||||
|
replace: "$1.overrideBannerSrc=$self.useBannerHook($1);"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
find: "\"data-selenium-video-tile\":",
|
find: "\"data-selenium-video-tile\":",
|
||||||
predicate: () => settings.store.voiceBackground,
|
predicate: () => settings.store.voiceBackground,
|
||||||
|
|
|
@ -206,8 +206,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".avatarPositionPanel",
|
find: ".avatarPositionPanel",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=avatarWrapperNonUserBot.{0,50})onClick:(\i\|\|\i)\?void 0(?<=,avatarSrc:(\i).+?)/,
|
match: /(avatarWrapperNonUserBot.{0,50})onClick:(\i\|\|\i)\?void 0(?<=,avatarSrc:(\i).+?)/,
|
||||||
replace: "style:($1)?{cursor:\"pointer\"}:{},onClick:$1?()=>{$self.openImage($2)}"
|
replace: "$1style:($2)?{cursor:\"pointer\"}:{},onClick:$2?()=>{$self.openImage($3)}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Group DMs top small & large icon
|
// Group DMs top small & large icon
|
||||||
|
|
6
src/plugins/watchTogetherAdblock.desktop/README.md
Normal file
6
src/plugins/watchTogetherAdblock.desktop/README.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# WatchTogetherAdblock
|
||||||
|
|
||||||
|
Block ads in the YouTube WatchTogether activity via AdGuard
|
||||||
|
|
||||||
|
Note that this only works for yourself, other users in the activity will still see ads.
|
||||||
|
Powered by a modified version of [Adguard's BlockYoutubeAdsShortcut](https://github.com/AdguardTeam/BlockYouTubeAdsShortcut)
|
262
src/plugins/watchTogetherAdblock.desktop/adguard.js
Normal file
262
src/plugins/watchTogetherAdblock.desktop/adguard.js
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file is part of AdGuard's Block YouTube Ads (https://github.com/AdguardTeam/BlockYouTubeAdsShortcut).
|
||||||
|
*
|
||||||
|
* Copyright (C) AdGuard Team
|
||||||
|
*
|
||||||
|
* AdGuard's Block YouTube Ads is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* AdGuard's Block YouTube Ads is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with AdGuard's Block YouTube Ads. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const LOGO_ID = "block-youtube-ads-logo";
|
||||||
|
const hiddenCSS = [
|
||||||
|
"#__ffYoutube1",
|
||||||
|
"#__ffYoutube2",
|
||||||
|
"#__ffYoutube3",
|
||||||
|
"#__ffYoutube4",
|
||||||
|
"#feed-pyv-container",
|
||||||
|
"#feedmodule-PRO",
|
||||||
|
"#homepage-chrome-side-promo",
|
||||||
|
"#merch-shelf",
|
||||||
|
"#offer-module",
|
||||||
|
'#pla-shelf > ytd-pla-shelf-renderer[class="style-scope ytd-watch"]',
|
||||||
|
"#pla-shelf",
|
||||||
|
"#premium-yva",
|
||||||
|
"#promo-info",
|
||||||
|
"#promo-list",
|
||||||
|
"#promotion-shelf",
|
||||||
|
"#related > ytd-watch-next-secondary-results-renderer > #items > ytd-compact-promoted-video-renderer.ytd-watch-next-secondary-results-renderer",
|
||||||
|
"#search-pva",
|
||||||
|
"#shelf-pyv-container",
|
||||||
|
"#video-masthead",
|
||||||
|
"#watch-branded-actions",
|
||||||
|
"#watch-buy-urls",
|
||||||
|
"#watch-channel-brand-div",
|
||||||
|
"#watch7-branded-banner",
|
||||||
|
"#YtKevlarVisibilityIdentifier",
|
||||||
|
"#YtSparklesVisibilityIdentifier",
|
||||||
|
".carousel-offer-url-container",
|
||||||
|
".companion-ad-container",
|
||||||
|
".GoogleActiveViewElement",
|
||||||
|
'.list-view[style="margin: 7px 0pt;"]',
|
||||||
|
".promoted-sparkles-text-search-root-container",
|
||||||
|
".promoted-videos",
|
||||||
|
".searchView.list-view",
|
||||||
|
".sparkles-light-cta",
|
||||||
|
".watch-extra-info-column",
|
||||||
|
".watch-extra-info-right",
|
||||||
|
".ytd-carousel-ad-renderer",
|
||||||
|
".ytd-compact-promoted-video-renderer",
|
||||||
|
".ytd-companion-slot-renderer",
|
||||||
|
".ytd-merch-shelf-renderer",
|
||||||
|
".ytd-player-legacy-desktop-watch-ads-renderer",
|
||||||
|
".ytd-promoted-sparkles-text-search-renderer",
|
||||||
|
".ytd-promoted-video-renderer",
|
||||||
|
".ytd-search-pyv-renderer",
|
||||||
|
".ytd-video-masthead-ad-v3-renderer",
|
||||||
|
".ytp-ad-action-interstitial-background-container",
|
||||||
|
".ytp-ad-action-interstitial-slot",
|
||||||
|
".ytp-ad-image-overlay",
|
||||||
|
".ytp-ad-overlay-container",
|
||||||
|
".ytp-ad-progress",
|
||||||
|
".ytp-ad-progress-list",
|
||||||
|
'[class*="ytd-display-ad-"]',
|
||||||
|
'[layout*="display-ad-"]',
|
||||||
|
'a[href^="http://www.youtube.com/cthru?"]',
|
||||||
|
'a[href^="https://www.youtube.com/cthru?"]',
|
||||||
|
"ytd-action-companion-ad-renderer",
|
||||||
|
"ytd-banner-promo-renderer",
|
||||||
|
"ytd-compact-promoted-video-renderer",
|
||||||
|
"ytd-companion-slot-renderer",
|
||||||
|
"ytd-display-ad-renderer",
|
||||||
|
"ytd-promoted-sparkles-text-search-renderer",
|
||||||
|
"ytd-promoted-sparkles-web-renderer",
|
||||||
|
"ytd-search-pyv-renderer",
|
||||||
|
"ytd-single-option-survey-renderer",
|
||||||
|
"ytd-video-masthead-ad-advertiser-info-renderer",
|
||||||
|
"ytd-video-masthead-ad-v3-renderer",
|
||||||
|
"YTM-PROMOTED-VIDEO-RENDERER",
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* Adds CSS to the page
|
||||||
|
*/
|
||||||
|
const hideElements = () => {
|
||||||
|
const selectors = hiddenCSS;
|
||||||
|
if (!selectors) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rule = selectors.join(", ") + " { display: none!important; }";
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.innerHTML = rule;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Calls the "callback" function on every DOM change, but not for the tracked events
|
||||||
|
* @param {Function} callback callback function
|
||||||
|
*/
|
||||||
|
const observeDomChanges = callback => {
|
||||||
|
const domMutationObserver = new MutationObserver(mutations => {
|
||||||
|
callback(mutations);
|
||||||
|
});
|
||||||
|
domMutationObserver.observe(document.documentElement, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This function is supposed to be called on every DOM change
|
||||||
|
*/
|
||||||
|
const hideDynamicAds = () => {
|
||||||
|
const elements = document.querySelectorAll("#contents > ytd-rich-item-renderer ytd-display-ad-renderer");
|
||||||
|
if (elements.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elements.forEach(el => {
|
||||||
|
if (el.parentNode && el.parentNode.parentNode) {
|
||||||
|
const parent = el.parentNode.parentNode;
|
||||||
|
if (parent.localName === "ytd-rich-item-renderer") {
|
||||||
|
parent.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This function checks if the video ads are currently running
|
||||||
|
* and auto-clicks the skip button.
|
||||||
|
*/
|
||||||
|
const autoSkipAds = () => {
|
||||||
|
// If there's a video that plays the ad at this moment, scroll this ad
|
||||||
|
if (document.querySelector(".ad-showing")) {
|
||||||
|
const video = document.querySelector("video");
|
||||||
|
if (video && video.duration) {
|
||||||
|
video.currentTime = video.duration;
|
||||||
|
// Skip button should appear after that,
|
||||||
|
// now simply click it automatically
|
||||||
|
setTimeout(() => {
|
||||||
|
const skipBtn = document.querySelector("button.ytp-ad-skip-button");
|
||||||
|
if (skipBtn) {
|
||||||
|
skipBtn.click();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* This function overrides a property on the specified object.
|
||||||
|
*
|
||||||
|
* @param {object} obj object to look for properties in
|
||||||
|
* @param {string} propertyName property to override
|
||||||
|
* @param {*} overrideValue value to set
|
||||||
|
*/
|
||||||
|
const overrideObject = (obj, propertyName, overrideValue) => {
|
||||||
|
if (!obj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let overriden = false;
|
||||||
|
for (const key in obj) {
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
if (obj.hasOwnProperty(key) && key === propertyName) {
|
||||||
|
obj[key] = overrideValue;
|
||||||
|
overriden = true;
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
} else if (obj.hasOwnProperty(key) && typeof obj[key] === "object") {
|
||||||
|
if (overrideObject(obj[key], propertyName, overrideValue)) {
|
||||||
|
overriden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overriden;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Overrides JSON.parse and Response.json functions.
|
||||||
|
* Examines these functions arguments, looks for properties with the specified name there
|
||||||
|
* and if it exists, changes it's value to what was specified.
|
||||||
|
*
|
||||||
|
* @param {string} propertyName name of the property
|
||||||
|
* @param {*} overrideValue new value for the property
|
||||||
|
*/
|
||||||
|
const jsonOverride = (propertyName, overrideValue) => {
|
||||||
|
const nativeJSONParse = JSON.parse;
|
||||||
|
JSON.parse = (...args) => {
|
||||||
|
const obj = nativeJSONParse.apply(this, args);
|
||||||
|
// Override it's props and return back to the caller
|
||||||
|
overrideObject(obj, propertyName, overrideValue);
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
// Override Response.prototype.json
|
||||||
|
const nativeResponseJson = Response.prototype.json;
|
||||||
|
Response.prototype.json = new Proxy(nativeResponseJson, {
|
||||||
|
apply(...args) {
|
||||||
|
// Call the target function, get the original Promise
|
||||||
|
const promise = Reflect.apply(...args);
|
||||||
|
// Create a new one and override the JSON inside
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
promise.then(data => {
|
||||||
|
overrideObject(data, propertyName, overrideValue);
|
||||||
|
resolve(data);
|
||||||
|
}).catch(error => reject(error));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const addAdGuardLogoStyle = () => { };
|
||||||
|
const addAdGuardLogo = () => {
|
||||||
|
if (document.getElementById(LOGO_ID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const logo = document.createElement("span");
|
||||||
|
logo.innerHTML = "__logo_text__";
|
||||||
|
logo.setAttribute("id", LOGO_ID);
|
||||||
|
if (window.location.hostname === "m.youtube.com") {
|
||||||
|
const btn = document.querySelector("header.mobile-topbar-header > button");
|
||||||
|
if (btn) {
|
||||||
|
btn.parentNode?.insertBefore(logo, btn.nextSibling);
|
||||||
|
addAdGuardLogoStyle();
|
||||||
|
}
|
||||||
|
} else if (window.location.hostname === "www.youtube.com") {
|
||||||
|
const code = document.getElementById("country-code");
|
||||||
|
if (code) {
|
||||||
|
code.innerHTML = "";
|
||||||
|
code.appendChild(logo);
|
||||||
|
addAdGuardLogoStyle();
|
||||||
|
}
|
||||||
|
} else if (window.location.hostname === "music.youtube.com") {
|
||||||
|
const el = document.querySelector(".ytmusic-nav-bar#left-content");
|
||||||
|
if (el) {
|
||||||
|
el.appendChild(logo);
|
||||||
|
addAdGuardLogoStyle();
|
||||||
|
}
|
||||||
|
} else if (window.location.hostname === "www.youtube-nocookie.com") {
|
||||||
|
const code = document.querySelector("#yt-masthead #logo-container .content-region");
|
||||||
|
if (code) {
|
||||||
|
code.innerHTML = "";
|
||||||
|
code.appendChild(logo);
|
||||||
|
addAdGuardLogoStyle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Removes ads metadata from YouTube XHR requests
|
||||||
|
jsonOverride("adPlacements", []);
|
||||||
|
jsonOverride("playerAds", []);
|
||||||
|
// Applies CSS that hides YouTube ad elements
|
||||||
|
hideElements();
|
||||||
|
// Some changes should be re-evaluated on every page change
|
||||||
|
addAdGuardLogo();
|
||||||
|
hideDynamicAds();
|
||||||
|
autoSkipAds();
|
||||||
|
observeDomChanges(() => {
|
||||||
|
addAdGuardLogo();
|
||||||
|
hideDynamicAds();
|
||||||
|
autoSkipAds();
|
||||||
|
});
|
15
src/plugins/watchTogetherAdblock.desktop/index.ts
Normal file
15
src/plugins/watchTogetherAdblock.desktop/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
// The entire code of this plugin can be found in native.ts
|
||||||
|
export default definePlugin({
|
||||||
|
name: "WatchTogetherAdblock",
|
||||||
|
description: "Block ads in the YouTube WatchTogether activity via AdGuard",
|
||||||
|
authors: [Devs.ImLvna],
|
||||||
|
});
|
21
src/plugins/watchTogetherAdblock.desktop/native.ts
Normal file
21
src/plugins/watchTogetherAdblock.desktop/native.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RendererSettings } from "@main/settings";
|
||||||
|
import { app } from "electron";
|
||||||
|
import adguard from "file://adguard.js?minify";
|
||||||
|
|
||||||
|
app.on("browser-window-created", (_, win) => {
|
||||||
|
win.webContents.on("frame-created", (_, { frame }) => {
|
||||||
|
frame.once("dom-ready", () => {
|
||||||
|
if (frame.url.includes("discordsays") && frame.url.includes("youtube.com")) {
|
||||||
|
if (!RendererSettings.store.plugins?.WatchTogetherAdblock?.enabled) return;
|
||||||
|
|
||||||
|
frame.executeJavaScript(adguard);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -186,7 +186,7 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
id: 296776625432035328n,
|
id: 296776625432035328n,
|
||||||
},
|
},
|
||||||
TheSun: {
|
TheSun: {
|
||||||
name: "ActuallyTheSun",
|
name: "sunnie",
|
||||||
id: 406028027768733696n
|
id: 406028027768733696n
|
||||||
},
|
},
|
||||||
axyie: {
|
axyie: {
|
||||||
|
@ -402,6 +402,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
name: "maisy",
|
name: "maisy",
|
||||||
id: 257109471589957632n,
|
id: 257109471589957632n,
|
||||||
},
|
},
|
||||||
|
Lexi: {
|
||||||
|
name: "Lexi",
|
||||||
|
id: 506101469787717658n
|
||||||
|
},
|
||||||
Mopi: {
|
Mopi: {
|
||||||
name: "Mopi",
|
name: "Mopi",
|
||||||
id: 1022189106614243350n
|
id: 1022189106614243350n
|
||||||
|
@ -498,6 +502,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
name: "ScattrdBlade",
|
name: "ScattrdBlade",
|
||||||
id: 678007540608532491n
|
id: 678007540608532491n
|
||||||
},
|
},
|
||||||
|
goodbee: {
|
||||||
|
name: "goodbee",
|
||||||
|
id: 658968552606400512n
|
||||||
|
},
|
||||||
Moxxie: {
|
Moxxie: {
|
||||||
name: "Moxxie",
|
name: "Moxxie",
|
||||||
id: 712653921692155965n,
|
id: 712653921692155965n,
|
||||||
|
|
|
@ -35,8 +35,8 @@ const unconfigurable = ["arguments", "caller", "prototype"];
|
||||||
|
|
||||||
const handler: ProxyHandler<any> = {};
|
const handler: ProxyHandler<any> = {};
|
||||||
|
|
||||||
const kGET = Symbol.for("vencord.lazy.get");
|
export const SYM_LAZY_GET = Symbol.for("vencord.lazy.get");
|
||||||
const kCACHE = Symbol.for("vencord.lazy.cached");
|
export const SYM_LAZY_CACHED = Symbol.for("vencord.lazy.cached");
|
||||||
|
|
||||||
for (const method of [
|
for (const method of [
|
||||||
"apply",
|
"apply",
|
||||||
|
@ -53,11 +53,11 @@ for (const method of [
|
||||||
"setPrototypeOf"
|
"setPrototypeOf"
|
||||||
]) {
|
]) {
|
||||||
handler[method] =
|
handler[method] =
|
||||||
(target: any, ...args: any[]) => Reflect[method](target[kGET](), ...args);
|
(target: any, ...args: any[]) => Reflect[method](target[SYM_LAZY_GET](), ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.ownKeys = target => {
|
handler.ownKeys = target => {
|
||||||
const v = target[kGET]();
|
const v = target[SYM_LAZY_GET]();
|
||||||
const keys = Reflect.ownKeys(v);
|
const keys = Reflect.ownKeys(v);
|
||||||
for (const key of unconfigurable) {
|
for (const key of unconfigurable) {
|
||||||
if (!keys.includes(key)) keys.push(key);
|
if (!keys.includes(key)) keys.push(key);
|
||||||
|
@ -69,7 +69,7 @@ handler.getOwnPropertyDescriptor = (target, p) => {
|
||||||
if (typeof p === "string" && unconfigurable.includes(p))
|
if (typeof p === "string" && unconfigurable.includes(p))
|
||||||
return Reflect.getOwnPropertyDescriptor(target, p);
|
return Reflect.getOwnPropertyDescriptor(target, p);
|
||||||
|
|
||||||
const descriptor = Reflect.getOwnPropertyDescriptor(target[kGET](), p);
|
const descriptor = Reflect.getOwnPropertyDescriptor(target[SYM_LAZY_GET](), p);
|
||||||
|
|
||||||
if (descriptor) Object.defineProperty(target, p, descriptor);
|
if (descriptor) Object.defineProperty(target, p, descriptor);
|
||||||
return descriptor;
|
return descriptor;
|
||||||
|
@ -92,31 +92,34 @@ export function proxyLazy<T>(factory: () => T, attempts = 5, isChild = false): T
|
||||||
|
|
||||||
let tries = 0;
|
let tries = 0;
|
||||||
const proxyDummy = Object.assign(function () { }, {
|
const proxyDummy = Object.assign(function () { }, {
|
||||||
[kCACHE]: void 0 as T | undefined,
|
[SYM_LAZY_CACHED]: void 0 as T | undefined,
|
||||||
[kGET]() {
|
[SYM_LAZY_GET]() {
|
||||||
if (!proxyDummy[kCACHE] && attempts > tries++) {
|
if (!proxyDummy[SYM_LAZY_CACHED] && attempts > tries++) {
|
||||||
proxyDummy[kCACHE] = factory();
|
proxyDummy[SYM_LAZY_CACHED] = factory();
|
||||||
if (!proxyDummy[kCACHE] && attempts === tries)
|
if (!proxyDummy[SYM_LAZY_CACHED] && attempts === tries)
|
||||||
console.error("Lazy factory failed:", factory);
|
console.error("Lazy factory failed:", factory);
|
||||||
}
|
}
|
||||||
return proxyDummy[kCACHE];
|
return proxyDummy[SYM_LAZY_CACHED];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Proxy(proxyDummy, {
|
return new Proxy(proxyDummy, {
|
||||||
...handler,
|
...handler,
|
||||||
get(target, p, receiver) {
|
get(target, p, receiver) {
|
||||||
|
if (p === SYM_LAZY_CACHED || p === SYM_LAZY_GET)
|
||||||
|
return Reflect.get(target, p, receiver);
|
||||||
|
|
||||||
// if we're still in the same tick, it means the lazy was immediately used.
|
// if we're still in the same tick, it means the lazy was immediately used.
|
||||||
// thus, we lazy proxy the get access to make things like destructuring work as expected
|
// thus, we lazy proxy the get access to make things like destructuring work as expected
|
||||||
// meow here will also be a lazy
|
// meow here will also be a lazy
|
||||||
// `const { meow } = findByPropsLazy("meow");`
|
// `const { meow } = findByPropsLazy("meow");`
|
||||||
if (!isChild && isSameTick)
|
if (!isChild && isSameTick)
|
||||||
return proxyLazy(
|
return proxyLazy(
|
||||||
() => Reflect.get(target[kGET](), p, receiver),
|
() => Reflect.get(target[SYM_LAZY_GET](), p, receiver),
|
||||||
attempts,
|
attempts,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
const lazyTarget = target[kGET]();
|
const lazyTarget = target[SYM_LAZY_GET]();
|
||||||
if (typeof lazyTarget === "object" || typeof lazyTarget === "function") {
|
if (typeof lazyTarget === "object" || typeof lazyTarget === "function") {
|
||||||
return Reflect.get(lazyTarget, p, receiver);
|
return Reflect.get(lazyTarget, p, receiver);
|
||||||
}
|
}
|
||||||
|
|
2
src/webpack/common/types/fluxEvents.d.ts
vendored
2
src/webpack/common/types/fluxEvents.d.ts
vendored
File diff suppressed because one or more lines are too long
4
src/webpack/common/types/stores.d.ts
vendored
4
src/webpack/common/types/stores.d.ts
vendored
|
@ -63,7 +63,7 @@ export interface CustomEmoji {
|
||||||
originalName?: string;
|
originalName?: string;
|
||||||
require_colons: boolean;
|
require_colons: boolean;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
type: "GUILD_EMOJI";
|
type: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UnicodeEmoji {
|
export interface UnicodeEmoji {
|
||||||
|
@ -75,7 +75,7 @@ export interface UnicodeEmoji {
|
||||||
};
|
};
|
||||||
index: number;
|
index: number;
|
||||||
surrogates: string;
|
surrogates: string;
|
||||||
type: "UNICODE";
|
type: 0;
|
||||||
uniqueName: string;
|
uniqueName: string;
|
||||||
useSpriteSheet: boolean;
|
useSpriteSheet: boolean;
|
||||||
get allNamesString(): string;
|
get allNamesString(): string;
|
||||||
|
|
|
@ -99,6 +99,16 @@ Object.defineProperty(Function.prototype, "O", {
|
||||||
};
|
};
|
||||||
|
|
||||||
onChunksLoaded.toString = originalOnChunksLoaded.toString.bind(originalOnChunksLoaded);
|
onChunksLoaded.toString = originalOnChunksLoaded.toString.bind(originalOnChunksLoaded);
|
||||||
|
|
||||||
|
// Returns whether a chunk has been loaded
|
||||||
|
Object.defineProperty(onChunksLoaded, "j", {
|
||||||
|
set(v) {
|
||||||
|
delete onChunksLoaded.j;
|
||||||
|
onChunksLoaded.j = v;
|
||||||
|
originalOnChunksLoaded.j = v;
|
||||||
|
},
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(this, "O", {
|
Object.defineProperty(this, "O", {
|
||||||
|
|
|
@ -402,7 +402,8 @@ export function findExportedComponentLazy<T extends object = any>(...props: stri
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const DefaultExtractAndLoadChunksRegex = /(?:Promise\.all\((\[\i\.\i\(".+?"\).+?\])\)|Promise\.resolve\(\)).then\(\i\.bind\(\i,"(.+?)"\)\)/;
|
export const DefaultExtractAndLoadChunksRegex = /(?:Promise\.all\(\[(\i\.\i\("[^)]+?"\)[^\]]+?)\]\)|(\i\.\i\("[^)]+?"\))|Promise\.resolve\(\))\.then\(\i\.bind\(\i,"([^)]+?)"\)\)/;
|
||||||
|
export const ChunkIdsRegex = /\("(.+?)"\)/g;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract and load chunks using their entry point
|
* Extract and load chunks using their entry point
|
||||||
|
@ -431,7 +432,7 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, rawChunkIds, entryPointId] = match;
|
const [, rawChunkIdsArray, rawChunkIdsSingle, entryPointId] = match;
|
||||||
if (Number.isNaN(Number(entryPointId))) {
|
if (Number.isNaN(Number(entryPointId))) {
|
||||||
const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number");
|
const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number");
|
||||||
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
logger.warn(err, "Code:", code, "Matcher:", matcher);
|
||||||
|
@ -443,8 +444,9 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = Def
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rawChunkIds = rawChunkIdsArray ?? rawChunkIdsSingle;
|
||||||
if (rawChunkIds) {
|
if (rawChunkIds) {
|
||||||
const chunkIds = Array.from(rawChunkIds.matchAll(/\("(.+?)"\)/g)).map((m: any) => m[1]);
|
const chunkIds = Array.from(rawChunkIds.matchAll(ChunkIdsRegex)).map((m: any) => m[1]);
|
||||||
await Promise.all(chunkIds.map(id => wreq.e(id)));
|
await Promise.all(chunkIds.map(id => wreq.e(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue