Merge branch 'dev' into immediate-finds-modules-proxy
This commit is contained in:
commit
4a590d3d0a
108
.eslintrc.json
108
.eslintrc.json
|
@ -1,108 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"ignorePatterns": ["dist", "browser", "packages/vencord-types"],
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"simple-header",
|
||||
"simple-import-sort",
|
||||
"unused-imports",
|
||||
"path-alias"
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"alias": {
|
||||
"map": [
|
||||
["@webpack", "./src/webpack"],
|
||||
["@webpack/common", "./src/webpack/common"],
|
||||
["@utils", "./src/utils"],
|
||||
["@api", "./src/api"],
|
||||
["@components", "./src/components"]
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
// Since it's only been a month and Vencord has already been stolen
|
||||
// by random skids who rebranded it to "AlphaCord" and erased all license
|
||||
// information
|
||||
"simple-header/header": [
|
||||
"error",
|
||||
{
|
||||
"files": ["scripts/header-new.txt", "scripts/header-old.txt"],
|
||||
"templates": { "author": [".*", "Vendicated and contributors"] }
|
||||
}
|
||||
],
|
||||
"quotes": ["error", "double", { "avoidEscape": true }],
|
||||
"jsx-quotes": ["error", "prefer-double"],
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"arrow-parens": ["error", "as-needed"],
|
||||
"eol-last": ["error", "always"],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"no-multi-spaces": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
"semi": ["error", "always"],
|
||||
"semi-style": ["error", "last"],
|
||||
"space-in-parens": ["error", "never"],
|
||||
"block-spacing": ["error", "always"],
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"eqeqeq": ["error", "always", { "null": "ignore" }],
|
||||
"spaced-comment": ["error", "always", { "markers": ["!"] }],
|
||||
"yoda": "error",
|
||||
"prefer-destructuring": ["error", {
|
||||
"VariableDeclarator": { "array": false, "object": true },
|
||||
"AssignmentExpression": { "array": false, "object": false }
|
||||
}],
|
||||
"operator-assignment": ["error", "always"],
|
||||
"no-useless-computed-key": "error",
|
||||
"no-unneeded-ternary": ["error", { "defaultAssignment": false }],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||
"no-duplicate-imports": "error",
|
||||
"no-extra-semi": "error",
|
||||
"dot-notation": "off",
|
||||
"@typescript-eslint/dot-notation": [
|
||||
"error",
|
||||
{
|
||||
"allowPrivateClassPropertyAccess": true,
|
||||
"allowProtectedClassPropertyAccess": true
|
||||
}
|
||||
],
|
||||
"no-useless-escape": [
|
||||
"error",
|
||||
{
|
||||
"extra": "i"
|
||||
}
|
||||
],
|
||||
"no-fallthrough": "error",
|
||||
"for-direction": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"no-useless-backreference": "error",
|
||||
"use-isnan": "error",
|
||||
"prefer-const": "error",
|
||||
"prefer-spread": "error",
|
||||
|
||||
"simple-import-sort/imports": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
|
||||
"path-alias/no-relative": "error"
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
"extends": "stylelint-config-standard",
|
||||
"rules": {
|
||||
"indentation": 4,
|
||||
"selector-class-pattern": [
|
||||
"^[a-z][a-zA-Z0-9]*(-[a-z0-9][a-zA-Z0-9]*)*$",
|
||||
{
|
||||
|
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -14,8 +14,6 @@
|
|||
"typescript.preferences.quoteStyle": "double",
|
||||
"javascript.preferences.quoteStyle": "double",
|
||||
|
||||
"eslint.experimental.useFlatConfig": false,
|
||||
|
||||
"gitlens.remotes": [
|
||||
{
|
||||
"domain": "codeberg.org",
|
||||
|
|
132
eslint.config.mjs
Normal file
132
eslint.config.mjs
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
import stylistic from "@stylistic/eslint-plugin";
|
||||
import pathAlias from "eslint-plugin-path-alias";
|
||||
import header from "eslint-plugin-simple-header";
|
||||
import simpleImportSort from "eslint-plugin-simple-import-sort";
|
||||
import unusedImports from "eslint-plugin-unused-imports";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ["dist", "browser", "packages/vencord-types"] },
|
||||
{
|
||||
files: ["src/**/*.{tsx,ts,mts,mjs,js,jsx}", "eslint.config.mjs"],
|
||||
plugins: {
|
||||
"simple-header": header,
|
||||
"@stylistic": stylistic,
|
||||
"@typescript-eslint": tseslint.plugin,
|
||||
"simple-import-sort": simpleImportSort,
|
||||
"unused-imports": unusedImports,
|
||||
"path-alias": pathAlias,
|
||||
},
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
map: [
|
||||
["@webpack", "./src/webpack"],
|
||||
["@webpack/common", "./src/webpack/common"],
|
||||
["@utils", "./src/utils"],
|
||||
["@api", "./src/api"],
|
||||
["@components", "./src/components"]
|
||||
]
|
||||
}
|
||||
},
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json"],
|
||||
tsconfigRootDir: import.meta.dirname
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
/*
|
||||
* Since it's only been a month and Vencord has already been stolen
|
||||
* by random skids who rebranded it to "AlphaCord" and erased all license
|
||||
* information
|
||||
*/
|
||||
"simple-header/header": [
|
||||
"error",
|
||||
{
|
||||
"files": ["scripts/header-new.txt", "scripts/header-old.txt"],
|
||||
"templates": { "author": [".*", "Vendicated and contributors"] }
|
||||
}
|
||||
],
|
||||
|
||||
// Style Rules
|
||||
"@stylistic/jsx-quotes": ["error", "prefer-double"],
|
||||
"@stylistic/quotes": ["error", "double", { "avoidEscape": true }],
|
||||
"@stylistic/no-mixed-spaces-and-tabs": "error",
|
||||
"@stylistic/arrow-parens": ["error", "as-needed"],
|
||||
"@stylistic/eol-last": ["error", "always"],
|
||||
"@stylistic/no-multi-spaces": "error",
|
||||
"@stylistic/no-trailing-spaces": "error",
|
||||
"@stylistic/no-whitespace-before-property": "error",
|
||||
"@stylistic/semi": ["error", "always"],
|
||||
"@stylistic/semi-style": ["error", "last"],
|
||||
"@stylistic/space-in-parens": ["error", "never"],
|
||||
"@stylistic/block-spacing": ["error", "always"],
|
||||
"@stylistic/object-curly-spacing": ["error", "always"],
|
||||
"@stylistic/spaced-comment": ["error", "always", { "markers": ["!"] }],
|
||||
"@stylistic/no-extra-semi": "error",
|
||||
|
||||
// TS Rules
|
||||
"@stylistic/func-call-spacing": ["error", "never"],
|
||||
|
||||
// ESLint Rules
|
||||
"yoda": "error",
|
||||
"eqeqeq": ["error", "always", { "null": "ignore" }],
|
||||
"prefer-destructuring": ["error", {
|
||||
"VariableDeclarator": { "array": false, "object": true },
|
||||
"AssignmentExpression": { "array": false, "object": false }
|
||||
}],
|
||||
"operator-assignment": ["error", "always"],
|
||||
"no-useless-computed-key": "error",
|
||||
"no-unneeded-ternary": ["error", { "defaultAssignment": false }],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||
"no-duplicate-imports": "error",
|
||||
"@typescript-eslint/dot-notation": [
|
||||
"error",
|
||||
{
|
||||
"allowPrivateClassPropertyAccess": true,
|
||||
"allowProtectedClassPropertyAccess": true
|
||||
}
|
||||
],
|
||||
"no-useless-escape": [
|
||||
"error",
|
||||
{
|
||||
"extra": "i"
|
||||
}
|
||||
],
|
||||
"no-fallthrough": "error",
|
||||
"for-direction": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"no-useless-backreference": "error",
|
||||
"use-isnan": "error",
|
||||
"prefer-const": "error",
|
||||
"prefer-spread": "error",
|
||||
|
||||
// Plugin Rules
|
||||
"simple-import-sort/imports": "error",
|
||||
"simple-import-sort/exports": "error",
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"path-alias/no-relative": "error"
|
||||
}
|
||||
}
|
||||
);
|
62
package.json
62
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "vencord",
|
||||
"private": "true",
|
||||
"version": "1.9.5",
|
||||
"version": "1.9.7",
|
||||
"description": "The cutest Discord client mod",
|
||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||
"bugs": {
|
||||
|
@ -27,7 +27,7 @@
|
|||
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types",
|
||||
"inject": "node scripts/runInstaller.mjs",
|
||||
"uninject": "node scripts/runInstaller.mjs",
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern src/userplugins",
|
||||
"lint": "eslint",
|
||||
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
|
||||
"lint:fix": "pnpm lint --fix",
|
||||
"test": "pnpm buildStandalone && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson",
|
||||
|
@ -35,53 +35,53 @@
|
|||
"testTsc": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sapphi-red/web-noise-suppressor": "0.3.3",
|
||||
"@sapphi-red/web-noise-suppressor": "0.3.5",
|
||||
"@vap/core": "0.0.12",
|
||||
"@vap/shiki": "0.10.5",
|
||||
"eslint-plugin-simple-header": "^1.0.2",
|
||||
"fflate": "^0.7.4",
|
||||
"fflate": "^0.8.2",
|
||||
"gifenc": "github:mattdesl/gifenc#64842fca317b112a8590f8fef2bf3825da8f6fe3",
|
||||
"monaco-editor": "^0.50.0",
|
||||
"nanoid": "^4.0.2",
|
||||
"nanoid": "^5.0.7",
|
||||
"virtual-merge": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chrome": "^0.0.246",
|
||||
"@types/diff": "^5.0.3",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/node": "^18.16.3",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.1",
|
||||
"@types/yazl": "^2.4.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
||||
"@typescript-eslint/parser": "^5.59.1",
|
||||
"diff": "^5.1.0",
|
||||
"@stylistic/eslint-plugin": "^2.6.1",
|
||||
"@types/chrome": "^0.0.269",
|
||||
"@types/diff": "^5.2.1",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "^22.0.3",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/yazl": "^2.4.5",
|
||||
"diff": "^5.2.0",
|
||||
"discord-types": "^1.3.26",
|
||||
"esbuild": "^0.15.18",
|
||||
"eslint": "^8.46.0",
|
||||
"eslint": "^9.8.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-path-alias": "^1.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"highlight.js": "10.6.0",
|
||||
"eslint-plugin-path-alias": "2.1.0",
|
||||
"eslint-plugin-simple-header": "^1.1.1",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-unused-imports": "^4.0.1",
|
||||
"highlight.js": "10.7.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"moment": "^2.29.4",
|
||||
"puppeteer-core": "^19.11.1",
|
||||
"moment": "^2.30.1",
|
||||
"puppeteer-core": "^22.15.0",
|
||||
"standalone-electron-types": "^1.0.0",
|
||||
"stylelint": "^15.6.0",
|
||||
"stylelint-config-standard": "^33.0.0",
|
||||
"ts-patch": "^3.1.2",
|
||||
"tsx": "^3.12.7",
|
||||
"type-fest": "^3.9.0",
|
||||
"typescript": "^5.4.5",
|
||||
"stylelint": "^16.8.1",
|
||||
"stylelint-config-standard": "^36.0.1",
|
||||
"ts-patch": "^3.2.1",
|
||||
"tsx": "^4.16.5",
|
||||
"type-fest": "^4.23.0",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.0.0",
|
||||
"typescript-transform-paths": "^3.4.7",
|
||||
"zip-local": "^0.3.5"
|
||||
},
|
||||
"packageManager": "pnpm@9.1.0",
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"eslint-plugin-path-alias@1.0.0": "patches/eslint-plugin-path-alias@1.0.0.patch",
|
||||
"eslint@8.46.0": "patches/eslint@8.46.0.patch"
|
||||
"eslint@9.8.0": "patches/eslint@9.8.0.patch",
|
||||
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch"
|
||||
},
|
||||
"peerDependencyRules": {
|
||||
"ignoreMissing": [
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
diff --git a/lib/rules/no-relative.js b/lib/rules/no-relative.js
|
||||
index 71594c83f1f4f733ffcc6047d7f7084348335dbe..d8623d87c89499c442171db3272cba07c9efabbe 100644
|
||||
--- a/lib/rules/no-relative.js
|
||||
+++ b/lib/rules/no-relative.js
|
||||
@@ -41,7 +41,7 @@ module.exports = {
|
||||
ImportDeclaration(node) {
|
||||
const importPath = node.source.value;
|
||||
|
||||
- if (!/^(\.?\.\/)/.test(importPath)) {
|
||||
+ if (!/^(\.\.\/)/.test(importPath)) {
|
||||
return;
|
||||
}
|
||||
|
14
patches/eslint-plugin-path-alias@2.1.0.patch
Normal file
14
patches/eslint-plugin-path-alias@2.1.0.patch
Normal file
|
@ -0,0 +1,14 @@
|
|||
diff --git a/dist/index.js b/dist/index.js
|
||||
index 67de6fb139070fd0e49beca65e3b63c531202e16..aa2883c8126e4952a42872ee920f59547a066430 100644
|
||||
--- a/dist/index.js
|
||||
+++ b/dist/index.js
|
||||
@@ -1 +1 @@
|
||||
-var C=Object.create;var f=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var $=(e,t)=>{for(var r in t)f(e,r,{get:t[r],enumerable:!0})},y=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of U(t))!F.call(e,s)&&s!==r&&f(e,s,{get:()=>t[s],enumerable:!(i=I(t,s))||i.enumerable});return e};var b=(e,t,r)=>(r=e!=null?C(S(e)):{},y(t||!e||!e.__esModule?f(r,"default",{value:e,enumerable:!0}):r,e)),D=e=>y(f({},"__esModule",{value:!0}),e);var N={};$(N,{default:()=>J});module.exports=D(N);var h="eslint-plugin-path-alias",v="2.0.0";var l=require("path"),M=b(require("nanomatch"));function j(e){return`https://github/com/msfragala/eslint-plugin-path-alias/blob/master/docs/rules/${e}.md`}var R=require("get-tsconfig"),a=require("path"),w=b(require("find-pkg")),O=require("fs");function P(e){if(e.options[0]?.paths)return z(e);let t=e.getFilename?.()??e.filename,r=(0,R.getTsconfig)(t);if(r?.config?.compilerOptions?.paths)return q(r);let i=w.default.sync((0,a.dirname)(t));if(!i)return;let s=JSON.parse((0,O.readFileSync)(i).toString());if(s?.imports)return L(s,i)}function L(e,t){let r=new Map,i=e.imports??{},s=(0,a.dirname)(t);return Object.entries(i).forEach(([o,n])=>{if(!n||typeof n!="string")return;let p=(0,a.resolve)(s,n);r.set(o,[p])}),r}function q(e){let t=new Map,r=e?.config?.compilerOptions?.paths??{},i=(0,a.dirname)(e.path);return e.config.compilerOptions?.baseUrl&&(i=(0,a.resolve)((0,a.dirname)(e.path),e.config.compilerOptions.baseUrl)),Object.entries(r).forEach(([s,o])=>{s=s.replace(/\/\*$/,""),o=o.map(n=>(0,a.resolve)(i,n.replace(/\/\*$/,""))),t.set(s,o)}),t}function z(e){let t=new Map,r=e.options[0]?.paths??{};return Object.entries(r).forEach(([i,s])=>{if(!s||typeof s!="string")return;if(s.startsWith("/")){t.set(i,[s]);return}let o=e.getCwd?.()??e.cwd,n=(0,a.resolve)(o,s);t.set(i,[n])}),t}var T={meta:{type:"suggestion",docs:{description:"Ensure imports use path aliases whenever possible vs. relative paths",url:j("no-relative")},fixable:"code",schema:[{type:"object",properties:{exceptions:{type:"array",items:{type:"string"}},paths:{type:"object"}},additionalProperties:!1}],messages:{shouldUseAlias:"Import should use path alias instead of relative path"}},create(e){let t=e.options[0]?.exceptions,r=e.getFilename?.()??e.filename,i=P(e);return i?.size?{ImportExpression(s){if(s.source.type!=="Literal"||typeof s.source.value!="string")return;let o=s.source.raw,n=s.source.value;if(!/^(\.?\.\/)/.test(n))return;let p=(0,l.resolve)((0,l.dirname)(r),n);if(A(p,t))return;let c=k(p,i);c&&e.report({node:s,messageId:"shouldUseAlias",data:{alias:c},fix(m){let g=E(p,c,i.get(c)),d=o.replace(n,g);return m.replaceText(s.source,d)}})},ImportDeclaration(s){if(typeof s.source.value!="string")return;let o=s.source.value;if(!/^(\.?\.\/)/.test(o))return;let n=(0,l.resolve)((0,l.dirname)(r),o),p=A(n,t),u=k(n,i);p||u&&e.report({node:s,messageId:"shouldUseAlias",data:{alias:u},fix(c){let m=s.source.raw,g=E(n,u,i.get(u)),d=m.replace(o,g);return c.replaceText(s.source,d)}})}}:{}}};function k(e,t){return Array.from(t.keys()).find(r=>t.get(r).some(s=>e.indexOf(s)===0))}function A(e,t){if(!t)return!1;let r=(0,l.basename)(e);return(0,M.default)(r,t).includes(r)}function E(e,t,r){for(let i of r)if(e.indexOf(i)===0)return e.replace(i,t)}var J={name:h,version:v,meta:{name:h,version:v},rules:{"no-relative":T}};
|
||||
+var C=Object.create;var f=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,F=Object.prototype.hasOwnProperty;var $=(e,t)=>{for(var r in t)f(e,r,{get:t[r],enumerable:!0})},y=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of U(t))!F.call(e,s)&&s!==r&&f(e,s,{get:()=>t[s],enumerable:!(i=I(t,s))||i.enumerable});return e};var b=(e,t,r)=>(r=e!=null?C(S(e)):{},y(t||!e||!e.__esModule?f(r,"default",{value:e,enumerable:!0}):r,e)),D=e=>y(f({},"__esModule",{value:!0}),e);var N={};$(N,{default:()=>J});module.exports=D(N);var h="eslint-plugin-path-alias",v="2.0.0";var l=require("path"),M=b(require("nanomatch"));function j(e){return`https://github/com/msfragala/eslint-plugin-path-alias/blob/master/docs/rules/${e}.md`}var R=require("get-tsconfig"),a=require("path"),w=b(require("find-pkg")),O=require("fs");function P(e){if(e.options[0]?.paths)return z(e);let t=e.getFilename?.()??e.filename,r=(0,R.getTsconfig)(t);if(r?.config?.compilerOptions?.paths)return q(r);let i=w.default.sync((0,a.dirname)(t));if(!i)return;let s=JSON.parse((0,O.readFileSync)(i).toString());if(s?.imports)return L(s,i)}function L(e,t){let r=new Map,i=e.imports??{},s=(0,a.dirname)(t);return Object.entries(i).forEach(([o,n])=>{if(!n||typeof n!="string")return;let p=(0,a.resolve)(s,n);r.set(o,[p])}),r}function q(e){let t=new Map,r=e?.config?.compilerOptions?.paths??{},i=(0,a.dirname)(e.path);return e.config.compilerOptions?.baseUrl&&(i=(0,a.resolve)((0,a.dirname)(e.path),e.config.compilerOptions.baseUrl)),Object.entries(r).forEach(([s,o])=>{s=s.replace(/\/\*$/,""),o=o.map(n=>(0,a.resolve)(i,n.replace(/\/\*$/,""))),t.set(s,o)}),t}function z(e){let t=new Map,r=e.options[0]?.paths??{};return Object.entries(r).forEach(([i,s])=>{if(!s||typeof s!="string")return;if(s.startsWith("/")){t.set(i,[s]);return}let o=e.getCwd?.()??e.cwd,n=(0,a.resolve)(o,s);t.set(i,[n])}),t}var T={meta:{type:"suggestion",docs:{description:"Ensure imports use path aliases whenever possible vs. relative paths",url:j("no-relative")},fixable:"code",schema:[{type:"object",properties:{exceptions:{type:"array",items:{type:"string"}},paths:{type:"object"}},additionalProperties:!1}],messages:{shouldUseAlias:"Import should use path alias instead of relative path"}},create(e){let t=e.options[0]?.exceptions,r=e.getFilename?.()??e.filename,i=P(e);return i?.size?{ImportExpression(s){if(s.source.type!=="Literal"||typeof s.source.value!="string")return;let o=s.source.raw,n=s.source.value;if(!/^(\.\.\/)/.test(n))return;let p=(0,l.resolve)((0,l.dirname)(r),n);if(A(p,t))return;let c=k(p,i);c&&e.report({node:s,messageId:"shouldUseAlias",data:{alias:c},fix(m){let g=E(p,c,i.get(c)),d=o.replace(n,g);return m.replaceText(s.source,d)}})},ImportDeclaration(s){if(typeof s.source.value!="string")return;let o=s.source.value;if(!/^(\.\.\/)/.test(o))return;let n=(0,l.resolve)((0,l.dirname)(r),o),p=A(n,t),u=k(n,i);p||u&&e.report({node:s,messageId:"shouldUseAlias",data:{alias:u},fix(c){let m=s.source.raw,g=E(n,u,i.get(u)),d=m.replace(o,g);return c.replaceText(s.source,d)}})}}:{}}};function k(e,t){return Array.from(t.keys()).find(r=>t.get(r).some(s=>e.indexOf(s)===0))}function A(e,t){if(!t)return!1;let r=(0,l.basename)(e);return(0,M.default)(r,t).includes(r)}function E(e,t,r){for(let i of r)if(e.indexOf(i)===0)return e.replace(i,t)}var J={name:h,version:v,meta:{name:h,version:v},rules:{"no-relative":T}};
|
||||
diff --git a/dist/index.mjs b/dist/index.mjs
|
||||
index 96de18e06d4cc413e11af038cd760e4804c32e59..27e8c4e3e2c942400cc3982e52159904ca6eedfa 100644
|
||||
--- a/dist/index.mjs
|
||||
+++ b/dist/index.mjs
|
||||
@@ -1 +1 @@
|
||||
-var d="eslint-plugin-path-alias",h="2.0.0";import{dirname as x,resolve as j,basename as I}from"path";import U from"nanomatch";function y(e){return`https://github/com/msfragala/eslint-plugin-path-alias/blob/master/docs/rules/${e}.md`}import{getTsconfig as k}from"get-tsconfig";import{resolve as c,dirname as u}from"path";import A from"find-pkg";import{readFileSync as E}from"fs";function b(e){if(e.options[0]?.paths)return C(e);let s=e.getFilename?.()??e.filename,i=k(s);if(i?.config?.compilerOptions?.paths)return T(i);let r=A.sync(u(s));if(!r)return;let t=JSON.parse(E(r).toString());if(t?.imports)return M(t,r)}function M(e,s){let i=new Map,r=e.imports??{},t=u(s);return Object.entries(r).forEach(([o,n])=>{if(!n||typeof n!="string")return;let a=c(t,n);i.set(o,[a])}),i}function T(e){let s=new Map,i=e?.config?.compilerOptions?.paths??{},r=u(e.path);return e.config.compilerOptions?.baseUrl&&(r=c(u(e.path),e.config.compilerOptions.baseUrl)),Object.entries(i).forEach(([t,o])=>{t=t.replace(/\/\*$/,""),o=o.map(n=>c(r,n.replace(/\/\*$/,""))),s.set(t,o)}),s}function C(e){let s=new Map,i=e.options[0]?.paths??{};return Object.entries(i).forEach(([r,t])=>{if(!t||typeof t!="string")return;if(t.startsWith("/")){s.set(r,[t]);return}let o=e.getCwd?.()??e.cwd,n=c(o,t);s.set(r,[n])}),s}var P={meta:{type:"suggestion",docs:{description:"Ensure imports use path aliases whenever possible vs. relative paths",url:y("no-relative")},fixable:"code",schema:[{type:"object",properties:{exceptions:{type:"array",items:{type:"string"}},paths:{type:"object"}},additionalProperties:!1}],messages:{shouldUseAlias:"Import should use path alias instead of relative path"}},create(e){let s=e.options[0]?.exceptions,i=e.getFilename?.()??e.filename,r=b(e);return r?.size?{ImportExpression(t){if(t.source.type!=="Literal"||typeof t.source.value!="string")return;let o=t.source.raw,n=t.source.value;if(!/^(\.?\.\/)/.test(n))return;let a=j(x(i),n);if(w(a,s))return;let l=R(a,r);l&&e.report({node:t,messageId:"shouldUseAlias",data:{alias:l},fix(f){let m=O(a,l,r.get(l)),g=o.replace(n,m);return f.replaceText(t.source,g)}})},ImportDeclaration(t){if(typeof t.source.value!="string")return;let o=t.source.value;if(!/^(\.?\.\/)/.test(o))return;let n=j(x(i),o),a=w(n,s),p=R(n,r);a||p&&e.report({node:t,messageId:"shouldUseAlias",data:{alias:p},fix(l){let f=t.source.raw,m=O(n,p,r.get(p)),g=f.replace(o,m);return l.replaceText(t.source,g)}})}}:{}}};function R(e,s){return Array.from(s.keys()).find(i=>s.get(i).some(t=>e.indexOf(t)===0))}function w(e,s){if(!s)return!1;let i=I(e);return U(i,s).includes(i)}function O(e,s,i){for(let r of i)if(e.indexOf(r)===0)return e.replace(r,s)}var Q={name:d,version:h,meta:{name:d,version:h},rules:{"no-relative":P}};export{Q as default};
|
||||
+var d="eslint-plugin-path-alias",h="2.0.0";import{dirname as x,resolve as j,basename as I}from"path";import U from"nanomatch";function y(e){return`https://github/com/msfragala/eslint-plugin-path-alias/blob/master/docs/rules/${e}.md`}import{getTsconfig as k}from"get-tsconfig";import{resolve as c,dirname as u}from"path";import A from"find-pkg";import{readFileSync as E}from"fs";function b(e){if(e.options[0]?.paths)return C(e);let s=e.getFilename?.()??e.filename,i=k(s);if(i?.config?.compilerOptions?.paths)return T(i);let r=A.sync(u(s));if(!r)return;let t=JSON.parse(E(r).toString());if(t?.imports)return M(t,r)}function M(e,s){let i=new Map,r=e.imports??{},t=u(s);return Object.entries(r).forEach(([o,n])=>{if(!n||typeof n!="string")return;let a=c(t,n);i.set(o,[a])}),i}function T(e){let s=new Map,i=e?.config?.compilerOptions?.paths??{},r=u(e.path);return e.config.compilerOptions?.baseUrl&&(r=c(u(e.path),e.config.compilerOptions.baseUrl)),Object.entries(i).forEach(([t,o])=>{t=t.replace(/\/\*$/,""),o=o.map(n=>c(r,n.replace(/\/\*$/,""))),s.set(t,o)}),s}function C(e){let s=new Map,i=e.options[0]?.paths??{};return Object.entries(i).forEach(([r,t])=>{if(!t||typeof t!="string")return;if(t.startsWith("/")){s.set(r,[t]);return}let o=e.getCwd?.()??e.cwd,n=c(o,t);s.set(r,[n])}),s}var P={meta:{type:"suggestion",docs:{description:"Ensure imports use path aliases whenever possible vs. relative paths",url:y("no-relative")},fixable:"code",schema:[{type:"object",properties:{exceptions:{type:"array",items:{type:"string"}},paths:{type:"object"}},additionalProperties:!1}],messages:{shouldUseAlias:"Import should use path alias instead of relative path"}},create(e){let s=e.options[0]?.exceptions,i=e.getFilename?.()??e.filename,r=b(e);return r?.size?{ImportExpression(t){if(t.source.type!=="Literal"||typeof t.source.value!="string")return;let o=t.source.raw,n=t.source.value;if(!/^(\.\.\/)/.test(n))return;let a=j(x(i),n);if(w(a,s))return;let l=R(a,r);l&&e.report({node:t,messageId:"shouldUseAlias",data:{alias:l},fix(f){let m=O(a,l,r.get(l)),g=o.replace(n,m);return f.replaceText(t.source,g)}})},ImportDeclaration(t){if(typeof t.source.value!="string")return;let o=t.source.value;if(!/^(\.\.\/)/.test(o))return;let n=j(x(i),o),a=w(n,s),p=R(n,r);a||p&&e.report({node:t,messageId:"shouldUseAlias",data:{alias:p},fix(l){let f=t.source.raw,m=O(n,p,r.get(p)),g=f.replace(o,m);return l.replaceText(t.source,g)}})}}:{}}};function R(e,s){return Array.from(s.keys()).find(i=>s.get(i).some(t=>e.indexOf(t)===0))}function w(e,s){if(!s)return!1;let i=I(e);return U(i,s).includes(i)}function O(e,s,i){for(let r of i)if(e.indexOf(r)===0)return e.replace(r,s)}var Q={name:d,version:h,meta:{name:d,version:h},rules:{"no-relative":P}};export{Q as default};
|
2582
pnpm-lock.yaml
2582
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -36,7 +36,7 @@ for (const variable of ["DISCORD_TOKEN", "CHROMIUM_BIN"]) {
|
|||
const CANARY = process.env.USE_CANARY === "true";
|
||||
|
||||
const browser = await pup.launch({
|
||||
headless: "new",
|
||||
headless: true,
|
||||
executablePath: process.env.CHROMIUM_BIN
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
.vc-expandableheader-center-flex {
|
||||
display: flex;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.vc-expandableheader-btn {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { get } from "@main/utils/simpleGet";
|
||||
import { IpcEvents } from "@shared/IpcEvents";
|
||||
import { VENCORD_USER_AGENT } from "@shared/vencordUserAgent";
|
||||
import { ipcMain } from "electron";
|
||||
|
@ -25,7 +26,6 @@ import { join } from "path";
|
|||
import gitHash from "~git-hash";
|
||||
import gitRemote from "~git-remote";
|
||||
|
||||
import { get } from "../utils/simpleGet";
|
||||
import { serializeErrors, VENCORD_FILES } from "./common";
|
||||
|
||||
const API_BASE = `https://api.github.com/repos/${gitRemote}`;
|
||||
|
|
|
@ -35,7 +35,8 @@ export const ALLOWED_PROTOCOLS = [
|
|||
"steam:",
|
||||
"spotify:",
|
||||
"com.epicgames.launcher:",
|
||||
"tidal:"
|
||||
"tidal:",
|
||||
"itunes:",
|
||||
];
|
||||
|
||||
export const IS_VANILLA = /* @__PURE__ */ process.argv.includes("--vanilla");
|
||||
|
|
1
src/modules.d.ts
vendored
1
src/modules.d.ts
vendored
|
@ -16,7 +16,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line spaced-comment
|
||||
/// <reference types="standalone-electron-types"/>
|
||||
|
||||
declare module "~plugins" {
|
||||
|
|
|
@ -27,12 +27,8 @@ export default definePlugin({
|
|||
find: "Messages.MESSAGE_UTILITIES_A11Y_LABEL",
|
||||
replacement: {
|
||||
// foo && !bar ? createElement(reactionStuffs)... createElement(blah,...makeElement(reply-other))
|
||||
match: /\i&&!\i\?\(0,\i\.jsxs?\)\(.{0,200}renderEmojiPicker:.{0,500}\?(\i)\(\{key:"reply-other"/,
|
||||
replace: (m, makeElement) => {
|
||||
const msg = m.match(/message:(.{1,3}),/)?.[1];
|
||||
if (!msg) throw new Error("Could not find message variable");
|
||||
return `...Vencord.Api.MessagePopover._buildPopoverElements(${msg},${makeElement}),${m}`;
|
||||
}
|
||||
match: /\i&&!\i\?\(0,\i\.jsxs?\)\(.{0,200}renderEmojiPicker:.{0,500}\?(\i)\(\{key:"reply-other"(?<=message:(\i).+?)/,
|
||||
replace: (m, makeElement, msg) => `...Vencord.Api.MessagePopover._buildPopoverElements(${msg},${makeElement}),${m}`
|
||||
}
|
||||
}],
|
||||
});
|
||||
|
|
|
@ -249,6 +249,10 @@ export default definePlugin({
|
|||
dispatchingFoldersClose = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
LOGOUT() {
|
||||
closeFolders();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -25,11 +25,9 @@ export default definePlugin({
|
|||
description: "Upload with a single click, open menu with right click",
|
||||
patches: [
|
||||
{
|
||||
find: "Messages.CHAT_ATTACH_UPLOAD_OR_INVITE",
|
||||
find: '"ChannelAttachButton"',
|
||||
replacement: {
|
||||
// Discord merges multiple props here with Object.assign()
|
||||
// This patch passes a third object to it with which we override onClick and onContextMenu
|
||||
match: /CHAT_ATTACH_UPLOAD_OR_INVITE,onDoubleClick:(.+?:void 0),\.\.\.(\i),/,
|
||||
match: /\.attachButtonInner,"aria-label":.{0,50},onDoubleClick:(.+?:void 0),\.\.\.(\i),/,
|
||||
replace: "$&onClick:$1,onContextMenu:$2.onClick,",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -30,7 +30,7 @@ function onPickColor(color: number) {
|
|||
updateColorVars(hexColor);
|
||||
}
|
||||
|
||||
const saveClientTheme = findByCode('type:"UNSYNCED_USER_SETTINGS_UPDATE",settings:{useSystemTheme:"system"===');
|
||||
const saveClientTheme = findByCode('type:"UNSYNCED_USER_SETTINGS_UPDATE', '"system"===');
|
||||
|
||||
function setTheme(theme: string) {
|
||||
saveClientTheme({ theme });
|
||||
|
|
|
@ -8,7 +8,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
|||
import { Flex } from "@components/Flex";
|
||||
import { openInviteModal } from "@utils/discord";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes } from "@utils/misc";
|
||||
import { classes, copyWithToast } from "@utils/misc";
|
||||
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { findComponentByCode } from "@webpack";
|
||||
import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common";
|
||||
|
@ -45,7 +45,11 @@ interface Section {
|
|||
authorIds?: string[];
|
||||
}
|
||||
|
||||
function SectionHeader({ section }: { section: Section; }) {
|
||||
interface SectionHeaderProps {
|
||||
section: Section;
|
||||
}
|
||||
|
||||
function SectionHeader({ section }: SectionHeaderProps) {
|
||||
const hasSubtitle = typeof section.subtitle !== "undefined";
|
||||
const hasAuthorIds = typeof section.authorIds !== "undefined";
|
||||
|
||||
|
@ -62,6 +66,7 @@ function SectionHeader({ section }: { section: Section; }) {
|
|||
})();
|
||||
}, [section.authorIds]);
|
||||
|
||||
|
||||
return <div>
|
||||
<Flex>
|
||||
<Forms.FormTitle style={{ flexGrow: 1 }}>{section.title}</Forms.FormTitle>
|
||||
|
@ -74,8 +79,7 @@ function SectionHeader({ section }: { section: Section; }) {
|
|||
size={16}
|
||||
showUserPopout
|
||||
className={Margins.bottom8}
|
||||
/>
|
||||
}
|
||||
/>}
|
||||
</Flex>
|
||||
{hasSubtitle &&
|
||||
<Forms.FormText type="description" className={Margins.bottom8}>
|
||||
|
@ -204,7 +208,16 @@ function ChangeDecorationModal(props: ModalProps) {
|
|||
{activeSelectedDecoration?.alt}
|
||||
</Text>
|
||||
}
|
||||
{activeDecorationHasAuthor && <Text key={`createdBy-${activeSelectedDecoration.authorId}`}>Created by {Parser.parse(`<@${activeSelectedDecoration.authorId}>`)}</Text>}
|
||||
{activeDecorationHasAuthor && (
|
||||
<Text key={`createdBy-${activeSelectedDecoration.authorId}`}>
|
||||
Created by {Parser.parse(`<@${activeSelectedDecoration.authorId}>`)}
|
||||
</Text>
|
||||
)}
|
||||
{isActiveDecorationPreset && (
|
||||
<Button onClick={() => copyWithToast(activeDecorationPreset.id)}>
|
||||
Copy Preset ID
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
</ModalContent>
|
||||
|
|
|
@ -57,7 +57,7 @@ function decode(bio: string): Array<number> | null {
|
|||
if (bio == null) return null;
|
||||
|
||||
const colorString = bio.match(
|
||||
/\u{e005b}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]+?)\u{e002c}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]+?)\u{e005d}/u,
|
||||
/\u{e005b}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{1,6})\u{e002c}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{1,6})\u{e005d}/u,
|
||||
);
|
||||
if (colorString != null) {
|
||||
const parsed = [...colorString[0]]
|
||||
|
|
|
@ -171,7 +171,7 @@ export default definePlugin({
|
|||
find: ".handleImageLoad)",
|
||||
replacement: [
|
||||
{
|
||||
match: /placeholderVersion:\i,/,
|
||||
match: /placeholderVersion:\i,(?=.{0,50}children:)/,
|
||||
replace: "...$self.makeProps(this),$&"
|
||||
},
|
||||
|
||||
|
|
|
@ -6,12 +6,21 @@
|
|||
|
||||
import "./styles.css";
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { SelectedGuildStore, useState } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
showAtSymbol: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Whether the the @ symbol should be displayed",
|
||||
default: true
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "MentionAvatars",
|
||||
description: "Shows user avatars inside mentions",
|
||||
|
@ -25,11 +34,13 @@ export default definePlugin({
|
|||
}
|
||||
}],
|
||||
|
||||
settings,
|
||||
|
||||
renderUsername: ErrorBoundary.wrap((props: { user: User, username: string; }) => {
|
||||
const { user, username } = props;
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
|
||||
if (!user) return <>@{username}</>;
|
||||
if (!user) return <>{getUsernameString(username)}</>;
|
||||
|
||||
return (
|
||||
<span
|
||||
|
@ -37,8 +48,15 @@ export default definePlugin({
|
|||
onMouseLeave={() => setIsHovering(false)}
|
||||
>
|
||||
<img src={user.getAvatarURL(SelectedGuildStore.getGuildId(), 16, isHovering)} className="vc-mentionAvatars-avatar" />
|
||||
@{username}
|
||||
{getUsernameString(username)}
|
||||
</span>
|
||||
);
|
||||
}, { noop: true })
|
||||
|
||||
});
|
||||
|
||||
function getUsernameString(username: string) {
|
||||
return settings.store.showAtSymbol
|
||||
? `@${username}`
|
||||
: username;
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ export default definePlugin({
|
|||
contextMenus: {
|
||||
"message": patchMessageContextMenu,
|
||||
"channel-context": patchChannelContextMenu,
|
||||
"thread-context": patchChannelContextMenu,
|
||||
"user-context": patchChannelContextMenu,
|
||||
"gdm-context": patchChannelContextMenu
|
||||
},
|
||||
|
|
|
@ -49,7 +49,7 @@ export default definePlugin({
|
|||
find: ".Messages.MUTUAL_GUILDS_WITH_END_COUNT", // Note: the module is lazy-loaded
|
||||
replacement: {
|
||||
match: /(?<=\.tabBarItem.{0,50}MUTUAL_GUILDS.+?}\),)(?=.+?(\(0,\i\.jsxs?\)\(.{0,100}id:))/,
|
||||
replace: '$self.isBotOrSelf(arguments[0].user)?null:$1"MUTUAL_GDMS",children:"Mutual Groups"}),'
|
||||
replace: '$self.isBotOrSelf(arguments[0].user)?null:$1"MUTUAL_GDMS",children:$self.getMutualGDMCountText(arguments[0].user)}),'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
match: /(?<=onItemSelect:\i,children:)(\i)\.map/,
|
||||
replace: "[...$1, ...($self.isBotOrSelf(arguments[0].user) ? [] : [{section:'MUTUAL_GDMS',text:'Mutual Groups'}])].map"
|
||||
replace: "[...$1, ...($self.isBotOrSelf(arguments[0].user) ? [] : [{section:'MUTUAL_GDMS',text:$self.getMutualGDMCountText(arguments[0].user)}])].map"
|
||||
},
|
||||
{
|
||||
match: /\(0,\i\.jsx\)\(\i,\{items:\i,section:(\i)/,
|
||||
|
@ -76,6 +76,11 @@ export default definePlugin({
|
|||
|
||||
isBotOrSelf: (user: User) => user.bot || user.id === UserStore.getCurrentUser().id,
|
||||
|
||||
getMutualGDMCountText: (user: User) => {
|
||||
const count = ChannelStore.getSortedPrivateChannels().filter(c => c.isGroupDM() && c.recipients.includes(user.id)).length;
|
||||
return `${count === 0 ? "No" : count} Mutual Group${count !== 1 ? "s" : ""}`;
|
||||
},
|
||||
|
||||
renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: User, onClose: () => void; }) => {
|
||||
const entries = ChannelStore.getSortedPrivateChannels().filter(c => c.isGroupDM() && c.recipients.includes(user.id)).map(c => (
|
||||
<Clickable
|
||||
|
|
11
src/plugins/openInApp/README.md
Normal file
11
src/plugins/openInApp/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# OpenInApp
|
||||
|
||||
Open links in their respective apps instead of your browser
|
||||
|
||||
## Currently supports:
|
||||
|
||||
- Spotify
|
||||
- Steam
|
||||
- EpicGames
|
||||
- Tidal
|
||||
- Apple Music (iTunes)
|
|
@ -18,46 +18,70 @@
|
|||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType, PluginNative } from "@utils/types";
|
||||
import definePlugin, { OptionType, PluginNative, SettingsDefinition } from "@utils/types";
|
||||
import { showToast, Toasts } from "@webpack/common";
|
||||
import type { MouseEvent } from "react";
|
||||
|
||||
const ShortUrlMatcher = /^https:\/\/(spotify\.link|s\.team)\/.+$/;
|
||||
const SpotifyMatcher = /^https:\/\/open\.spotify\.com\/(track|album|artist|playlist|user|episode)\/(.+)(?:\?.+?)?$/;
|
||||
const SteamMatcher = /^https:\/\/(steamcommunity\.com|(?:help|store)\.steampowered\.com)\/.+$/;
|
||||
const EpicMatcher = /^https:\/\/store\.epicgames\.com\/(.+)$/;
|
||||
const TidalMatcher = /^https:\/\/tidal\.com\/browse\/(track|album|artist|playlist|user|video|mix)\/(.+)(?:\?.+?)?$/;
|
||||
interface URLReplacementRule {
|
||||
match: RegExp;
|
||||
replace: (...matches: string[]) => string;
|
||||
description: string;
|
||||
shortlinkMatch?: RegExp;
|
||||
accountViewReplace?: (userId: string) => string;
|
||||
}
|
||||
|
||||
const settings = definePluginSettings({
|
||||
// Do not forget to add protocols to the ALLOWED_PROTOCOLS constant
|
||||
const UrlReplacementRules: Record<string, URLReplacementRule> = {
|
||||
spotify: {
|
||||
type: OptionType.BOOLEAN,
|
||||
match: /^https:\/\/open\.spotify\.com\/(track|album|artist|playlist|user|episode)\/(.+)(?:\?.+?)?$/,
|
||||
replace: (_, type, id) => `spotify://${type}/${id}`,
|
||||
description: "Open Spotify links in the Spotify app",
|
||||
default: true,
|
||||
shortlinkMatch: /^https:\/\/spotify\.link\/.+$/,
|
||||
accountViewReplace: userId => `spotify:user:${userId}`,
|
||||
},
|
||||
steam: {
|
||||
type: OptionType.BOOLEAN,
|
||||
match: /^https:\/\/(steamcommunity\.com|(?:help|store)\.steampowered\.com)\/.+$/,
|
||||
replace: match => `steam://openurl/${match}`,
|
||||
description: "Open Steam links in the Steam app",
|
||||
default: true,
|
||||
shortlinkMatch: /^https:\/\/s.team\/.+$/,
|
||||
accountViewReplace: userId => `steam://openurl/https://steamcommunity.com/profiles/${userId}`,
|
||||
},
|
||||
epic: {
|
||||
type: OptionType.BOOLEAN,
|
||||
match: /^https:\/\/store\.epicgames\.com\/(.+)$/,
|
||||
replace: (_, id) => `com.epicgames.launcher://store/${id}`,
|
||||
description: "Open Epic Games links in the Epic Games Launcher",
|
||||
default: true,
|
||||
},
|
||||
tidal: {
|
||||
type: OptionType.BOOLEAN,
|
||||
match: /^https:\/\/tidal\.com\/browse\/(track|album|artist|playlist|user|video|mix)\/(.+)(?:\?.+?)?$/,
|
||||
replace: (_, type, id) => `tidal://${type}/${id}`,
|
||||
description: "Open Tidal links in the Tidal app",
|
||||
default: true,
|
||||
}
|
||||
});
|
||||
},
|
||||
itunes: {
|
||||
match: /^https:\/\/music\.apple\.com\/([a-z]{2}\/)?(album|artist|playlist|song|curator)\/([^/?#]+)\/?([^/?#]+)?(?:\?.*)?(?:#.*)?$/,
|
||||
replace: (_, lang, type, name, id) => id ? `itunes://music.apple.com/us/${type}/${name}/${id}` : `itunes://music.apple.com/us/${type}/${name}`,
|
||||
description: "Open Apple Music links in the iTunes app"
|
||||
},
|
||||
};
|
||||
|
||||
const pluginSettings = definePluginSettings(
|
||||
Object.entries(UrlReplacementRules).reduce((acc, [key, rule]) => {
|
||||
acc[key] = {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: rule.description,
|
||||
default: true,
|
||||
};
|
||||
return acc;
|
||||
}, {} as SettingsDefinition)
|
||||
);
|
||||
|
||||
|
||||
const Native = VencordNative.pluginHelpers.OpenInApp as PluginNative<typeof import("./native")>;
|
||||
|
||||
export default definePlugin({
|
||||
name: "OpenInApp",
|
||||
description: "Open Spotify, Tidal, Steam and Epic Games URLs in their respective apps instead of your browser",
|
||||
authors: [Devs.Ven],
|
||||
settings,
|
||||
description: "Open links in their respective apps instead of your browser",
|
||||
authors: [Devs.Ven, Devs.surgedevs],
|
||||
settings: pluginSettings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
|
@ -70,7 +94,7 @@ export default definePlugin({
|
|||
// Make Spotify profile activity links open in app on web
|
||||
{
|
||||
find: "WEB_OPEN(",
|
||||
predicate: () => !IS_DISCORD_DESKTOP && settings.store.spotify,
|
||||
predicate: () => !IS_DISCORD_DESKTOP && pluginSettings.store.spotify,
|
||||
replacement: {
|
||||
match: /\i\.\i\.isProtocolRegistered\(\)(.{0,100})window.open/g,
|
||||
replace: "true$1VencordNative.native.openExternal"
|
||||
|
@ -79,8 +103,8 @@ export default definePlugin({
|
|||
{
|
||||
find: ".CONNECTED_ACCOUNT_VIEWED,",
|
||||
replacement: {
|
||||
match: /(?<=href:\i,onClick:\i=>\{)(?=.{0,10}\i=(\i)\.type,.{0,100}CONNECTED_ACCOUNT_VIEWED)/,
|
||||
replace: "$self.handleAccountView(arguments[0],$1.type,$1.id);"
|
||||
match: /(?<=href:\i,onClick:(\i)=>\{)(?=.{0,10}\i=(\i)\.type,.{0,100}CONNECTED_ACCOUNT_VIEWED)/,
|
||||
replace: "if($self.handleAccountView($1,$2.type,$2.id)) return;"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -89,61 +113,25 @@ export default definePlugin({
|
|||
if (!data) return false;
|
||||
|
||||
let url = data.href;
|
||||
if (!IS_WEB && ShortUrlMatcher.test(url)) {
|
||||
event?.preventDefault();
|
||||
// CORS jumpscare
|
||||
url = await Native.resolveRedirect(url);
|
||||
}
|
||||
if (!url) return false;
|
||||
|
||||
spotify: {
|
||||
if (!settings.store.spotify) break spotify;
|
||||
for (const [key, rule] of Object.entries(UrlReplacementRules)) {
|
||||
if (!pluginSettings.store[key]) continue;
|
||||
|
||||
const match = SpotifyMatcher.exec(url);
|
||||
if (!match) break spotify;
|
||||
if (rule.shortlinkMatch?.test(url)) {
|
||||
event?.preventDefault();
|
||||
url = await Native.resolveRedirect(url);
|
||||
}
|
||||
|
||||
const [, type, id] = match;
|
||||
VencordNative.native.openExternal(`spotify:${type}:${id}`);
|
||||
if (rule.match.test(url)) {
|
||||
showToast("Opened link in native app", Toasts.Type.SUCCESS);
|
||||
|
||||
event?.preventDefault();
|
||||
return true;
|
||||
}
|
||||
const newUrl = url.replace(rule.match, rule.replace);
|
||||
VencordNative.native.openExternal(newUrl);
|
||||
|
||||
steam: {
|
||||
if (!settings.store.steam) break steam;
|
||||
|
||||
if (!SteamMatcher.test(url)) break steam;
|
||||
|
||||
VencordNative.native.openExternal(`steam://openurl/${url}`);
|
||||
event?.preventDefault();
|
||||
|
||||
// Steam does not focus itself so show a toast so it's slightly less confusing
|
||||
showToast("Opened link in Steam", Toasts.Type.SUCCESS);
|
||||
return true;
|
||||
}
|
||||
|
||||
epic: {
|
||||
if (!settings.store.epic) break epic;
|
||||
|
||||
const match = EpicMatcher.exec(url);
|
||||
if (!match) break epic;
|
||||
|
||||
VencordNative.native.openExternal(`com.epicgames.launcher://store/${match[1]}`);
|
||||
event?.preventDefault();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tidal: {
|
||||
if (!settings.store.tidal) break tidal;
|
||||
|
||||
const match = TidalMatcher.exec(url);
|
||||
if (!match) break tidal;
|
||||
|
||||
const [, type, id] = match;
|
||||
VencordNative.native.openExternal(`tidal://${type}/${id}`);
|
||||
|
||||
event?.preventDefault();
|
||||
return true;
|
||||
event?.preventDefault();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// in case short url didn't end up being something we can handle
|
||||
|
@ -155,14 +143,12 @@ export default definePlugin({
|
|||
return false;
|
||||
},
|
||||
|
||||
handleAccountView(event: { preventDefault(): void; }, platformType: string, userId: string) {
|
||||
if (platformType === "spotify" && settings.store.spotify) {
|
||||
VencordNative.native.openExternal(`spotify:user:${userId}`);
|
||||
event.preventDefault();
|
||||
} else if (platformType === "steam" && settings.store.steam) {
|
||||
VencordNative.native.openExternal(`steam://openurl/https://steamcommunity.com/profiles/${userId}`);
|
||||
showToast("Opened link in Steam", Toasts.Type.SUCCESS);
|
||||
event.preventDefault();
|
||||
handleAccountView(e: MouseEvent, platformType: string, userId: string) {
|
||||
const rule = UrlReplacementRules[platformType];
|
||||
if (rule?.accountViewReplace && pluginSettings.store[platformType]) {
|
||||
VencordNative.native.openExternal(rule.accountViewReplace(userId));
|
||||
e.preventDefault();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ export default definePlugin({
|
|||
{
|
||||
find: ".nonMediaMosaicItem]",
|
||||
replacement: {
|
||||
match: /\.nonMediaMosaicItem\]:!(\i).{0,10}children:\[(\S)/,
|
||||
match: /\.nonMediaMosaicItem\]:!(\i).{0,50}?children:\[(\S)/,
|
||||
replace: "$&,$1&&$2&&$self.renderPiPButton(),"
|
||||
},
|
||||
},
|
||||
|
|
|
@ -26,8 +26,7 @@
|
|||
}
|
||||
|
||||
.vc-st-modal-header {
|
||||
justify-content: space-between;
|
||||
align-content: center;
|
||||
place-content: center space-between;
|
||||
}
|
||||
|
||||
.vc-st-modal-header h1 {
|
||||
|
|
|
@ -211,9 +211,9 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: /\.BITE_SIZE,onOpenProfile:\i,usernameIcon:/,
|
||||
find: '"BiteSizeProfileBody"',
|
||||
replacement: {
|
||||
match: /currentUser:\i,guild:\i,onOpenProfile:.+?}\)(?=])(?<=user:(\i),bio:null==(\i)\?.+?)/,
|
||||
match: /currentUser:\i,guild:\i}\)(?<=user:(\i),bio:null==(\i)\?.+?)/,
|
||||
replace: "$&,$self.profilePopoutComponent({ user: $1, displayProfile: $2, simplified: true })"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -307,7 +307,7 @@ export default definePlugin({
|
|||
]
|
||||
},
|
||||
{
|
||||
find: '+1]})},"overflow"))',
|
||||
find: '})},"overflow"))',
|
||||
replacement: [
|
||||
{
|
||||
// Create a variable for the channel prop
|
||||
|
|
|
@ -66,6 +66,15 @@ export default definePlugin({
|
|||
replace: "return true",
|
||||
}
|
||||
},
|
||||
// fixes a bug where Members page must be loaded to see highest role, why is Discord depending on MemberSafetyStore.getEnhancedMember for something that can be obtained here?
|
||||
{
|
||||
find: "Messages.GUILD_MEMBER_MOD_VIEW_PERMISSION_GRANTED_BY_ARIA_LABEL,allowOverflow",
|
||||
predicate: () => settings.store.showModView,
|
||||
replacement: {
|
||||
match: /(role:)\i(?=,guildId.{0,100}role:(\i\[))/,
|
||||
replace: "$1$2arguments[0].member.highestRoleId]",
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "prod_discoverable_guilds",
|
||||
predicate: () => settings.store.disableDiscoveryFilters,
|
||||
|
|
|
@ -165,7 +165,6 @@ function SeekBar() {
|
|||
|
||||
const [position, setPosition] = useState(storePosition);
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
useEffect(() => {
|
||||
if (isPlaying && !isSettingPosition) {
|
||||
setPosition(SpotifyStore.position);
|
||||
|
@ -358,7 +357,7 @@ export function Player() {
|
|||
const [shouldHide, setShouldHide] = useState(false);
|
||||
|
||||
// Hide player after 5 minutes of inactivity
|
||||
// eslint-disable-next-line consistent-return
|
||||
|
||||
React.useEffect(() => {
|
||||
setShouldHide(false);
|
||||
if (!isPlaying) {
|
||||
|
|
|
@ -51,7 +51,7 @@ export default definePlugin({
|
|||
|
||||
patches: [
|
||||
{
|
||||
find: '"AccountConnected"',
|
||||
find: "this.isCopiedStreakGodlike",
|
||||
replacement: {
|
||||
// react.jsx)(AccountPanel, { ..., showTaglessAccountPanel: blah })
|
||||
match: /(?<=\i\.jsxs?\)\()(\i),{(?=[^}]*?userTag:\i,hidePrivateData:)/,
|
||||
|
|
|
@ -101,9 +101,8 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.2rem;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
align-content: flex-start;
|
||||
place-content: flex-start center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
*/
|
||||
|
||||
import { ChatBarButton } from "@api/ChatButtons";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes } from "@utils/misc";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { Alerts, Forms } from "@webpack/common";
|
||||
import { Alerts, Forms, Tooltip, useEffect, useState } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { TranslateModal } from "./TranslateModal";
|
||||
|
@ -39,9 +38,17 @@ export function TranslateIcon({ height = 24, width = 24, className }: { height?:
|
|||
);
|
||||
}
|
||||
|
||||
export let setShouldShowTranslateEnabledTooltip: undefined | ((show: boolean) => void);
|
||||
|
||||
export const TranslateChatBarIcon: ChatBarButton = ({ isMainChat }) => {
|
||||
const { autoTranslate, showChatBarButton } = settings.use(["autoTranslate", "showChatBarButton"]);
|
||||
|
||||
const [shouldShowTranslateEnabledTooltip, setter] = useState(false);
|
||||
useEffect(() => {
|
||||
setShouldShowTranslateEnabledTooltip = setter;
|
||||
return () => setShouldShowTranslateEnabledTooltip = undefined;
|
||||
}, []);
|
||||
|
||||
if (!isMainChat || !showChatBarButton) return null;
|
||||
|
||||
const toggle = () => {
|
||||
|
@ -52,21 +59,20 @@ export const TranslateChatBarIcon: ChatBarButton = ({ isMainChat }) => {
|
|||
title: "Vencord Auto-Translate Enabled",
|
||||
body: <>
|
||||
<Forms.FormText>
|
||||
You just enabled auto translate (by right clicking the Translate icon). Any message you send will automatically be translated before being sent.
|
||||
</Forms.FormText>
|
||||
<Forms.FormText className={Margins.top16}>
|
||||
If this was an accident, disable it again, or it will change your message content before sending.
|
||||
You just enabled Auto Translate! Any message <b>will automatically be translated</b> before being sent.
|
||||
</Forms.FormText>
|
||||
</>,
|
||||
cancelText: "Disable Auto-Translate",
|
||||
confirmText: "Got it",
|
||||
confirmText: "Disable Auto-Translate",
|
||||
cancelText: "Got it",
|
||||
secondaryConfirmText: "Don't show again",
|
||||
onConfirmSecondary: () => settings.store.showAutoTranslateAlert = false,
|
||||
onCancel: () => settings.store.autoTranslate = false
|
||||
onConfirm: () => settings.store.autoTranslate = false,
|
||||
// troll
|
||||
confirmColor: "vc-notification-log-danger-btn",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
const button = (
|
||||
<ChatBarButton
|
||||
tooltip="Open Translate Modal"
|
||||
onClick={e => {
|
||||
|
@ -76,7 +82,7 @@ export const TranslateChatBarIcon: ChatBarButton = ({ isMainChat }) => {
|
|||
<TranslateModal rootProps={props} />
|
||||
));
|
||||
}}
|
||||
onContextMenu={() => toggle()}
|
||||
onContextMenu={toggle}
|
||||
buttonProps={{
|
||||
"aria-haspopup": "dialog"
|
||||
}}
|
||||
|
@ -84,4 +90,13 @@ export const TranslateChatBarIcon: ChatBarButton = ({ isMainChat }) => {
|
|||
<TranslateIcon className={cl({ "auto-translate": autoTranslate, "chat-button": true })} />
|
||||
</ChatBarButton>
|
||||
);
|
||||
|
||||
if (shouldShowTranslateEnabledTooltip && settings.store.showAutoTranslateTooltip)
|
||||
return (
|
||||
<Tooltip text="Auto Translate Enabled" forceOpen>
|
||||
{() => button}
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
return button;
|
||||
};
|
||||
|
|
|
@ -20,9 +20,8 @@ import { Margins } from "@utils/margins";
|
|||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||
import { Forms, SearchableSelect, Switch, useMemo } from "@webpack/common";
|
||||
|
||||
import { Languages } from "./languages";
|
||||
import { settings } from "./settings";
|
||||
import { cl } from "./utils";
|
||||
import { cl, getLanguages } from "./utils";
|
||||
|
||||
const LanguageSettingKeys = ["receivedInput", "receivedOutput", "sentInput", "sentOutput"] as const;
|
||||
|
||||
|
@ -31,7 +30,7 @@ function LanguageSelect({ settingsKey, includeAuto }: { settingsKey: typeof Lang
|
|||
|
||||
const options = useMemo(
|
||||
() => {
|
||||
const options = Object.entries(Languages).map(([value, label]) => ({ value, label }));
|
||||
const options = Object.entries(getLanguages()).map(([value, label]) => ({ value, label }));
|
||||
if (!includeAuto)
|
||||
options.shift();
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import { Parser, useEffect, useState } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
import { Languages } from "./languages";
|
||||
import { TranslateIcon } from "./TranslateIcon";
|
||||
import { cl, TranslationValue } from "./utils";
|
||||
|
||||
|
@ -59,7 +58,7 @@ export function TranslationAccessory({ message }: { message: Message; }) {
|
|||
<TranslateIcon width={16} height={16} />
|
||||
{Parser.parse(translation.text)}
|
||||
{" "}
|
||||
(translated from {Languages[translation.src] ?? translation.src} - <Dismiss onDismiss={() => setTranslation(undefined)} />)
|
||||
(translated from {translation.sourceLanguage} - <Dismiss onDismiss={() => setTranslation(undefined)} />)
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import definePlugin from "@utils/types";
|
|||
import { ChannelStore, Menu } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { TranslateChatBarIcon, TranslateIcon } from "./TranslateIcon";
|
||||
import { setShouldShowTranslateEnabledTooltip, TranslateChatBarIcon, TranslateIcon } from "./TranslateIcon";
|
||||
import { handleTranslate, TranslationAccessory } from "./TranslationAccessory";
|
||||
import { translate } from "./utils";
|
||||
|
||||
|
@ -53,8 +53,8 @@ const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }) =>
|
|||
|
||||
export default definePlugin({
|
||||
name: "Translate",
|
||||
description: "Translate messages with Google Translate",
|
||||
authors: [Devs.Ven],
|
||||
description: "Translate messages with Google Translate or DeepL",
|
||||
authors: [Devs.Ven, Devs.AshtonMemer],
|
||||
dependencies: ["MessageAccessoriesAPI", "MessagePopoverAPI", "MessageEventsAPI", "ChatInputButtonAPI"],
|
||||
settings,
|
||||
contextMenus: {
|
||||
|
@ -83,11 +83,18 @@ export default definePlugin({
|
|||
};
|
||||
});
|
||||
|
||||
let tooltipTimeout: any;
|
||||
this.preSend = addPreSendListener(async (_, message) => {
|
||||
if (!settings.store.autoTranslate) return;
|
||||
if (!message.content) return;
|
||||
|
||||
message.content = (await translate("sent", message.content)).text;
|
||||
setShouldShowTranslateEnabledTooltip?.(true);
|
||||
clearTimeout(tooltipTimeout);
|
||||
tooltipTimeout = setTimeout(() => setShouldShowTranslateEnabledTooltip?.(false), 2000);
|
||||
|
||||
const trans = await translate("sent", message.content);
|
||||
message.content = trans.text;
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -31,9 +31,10 @@ copy(Object.fromEntries(
|
|||
))
|
||||
*/
|
||||
|
||||
export type Language = keyof typeof Languages;
|
||||
export type GoogleLanguage = keyof typeof GoogleLanguages;
|
||||
export type DeeplLanguage = keyof typeof DeeplLanguages;
|
||||
|
||||
export const Languages = {
|
||||
export const GoogleLanguages = {
|
||||
"auto": "Detect language",
|
||||
"af": "Afrikaans",
|
||||
"sq": "Albanian",
|
||||
|
@ -169,3 +170,57 @@ export const Languages = {
|
|||
"yo": "Yoruba",
|
||||
"zu": "Zulu"
|
||||
} as const;
|
||||
|
||||
export const DeeplLanguages = {
|
||||
"": "Detect language",
|
||||
"ar": "Arabic",
|
||||
"bg": "Bulgarian",
|
||||
"zh-hans": "Chinese (Simplified)",
|
||||
"zh-hant": "Chinese (Traditional)",
|
||||
"cs": "Czech",
|
||||
"da": "Danish",
|
||||
"nl": "Dutch",
|
||||
"en-us": "English (American)",
|
||||
"en-gb": "English (British)",
|
||||
"et": "Estonian",
|
||||
"fi": "Finnish",
|
||||
"fr": "French",
|
||||
"de": "German",
|
||||
"el": "Greek",
|
||||
"hu": "Hungarian",
|
||||
"id": "Indonesian",
|
||||
"it": "Italian",
|
||||
"ja": "Japanese",
|
||||
"ko": "Korean",
|
||||
"lv": "Latvian",
|
||||
"lt": "Lithuanian",
|
||||
"nb": "Norwegian",
|
||||
"pl": "Polish",
|
||||
"pt-br": "Portuguese (Brazilian)",
|
||||
"pt-pt": "Portuguese (European)",
|
||||
"ro": "Romanian",
|
||||
"ru": "Russian",
|
||||
"sk": "Slovak",
|
||||
"sl": "Slovenian",
|
||||
"es": "Spanish",
|
||||
"sv": "Swedish",
|
||||
"tr": "Turkish",
|
||||
"uk": "Ukrainian"
|
||||
} as const;
|
||||
|
||||
export function deeplLanguageToGoogleLanguage(language: string) {
|
||||
switch (language) {
|
||||
case "": return "auto";
|
||||
case "nb": return "no";
|
||||
case "zh-hans": return "zh-CN";
|
||||
case "zh-hant": return "zh-TW";
|
||||
case "en-us":
|
||||
case "en-gb":
|
||||
return "en";
|
||||
case "pt-br":
|
||||
case "pt-pt":
|
||||
return "pt";
|
||||
default:
|
||||
return language;
|
||||
}
|
||||
}
|
||||
|
|
29
src/plugins/translate/native.ts
Normal file
29
src/plugins/translate/native.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { IpcMainInvokeEvent } from "electron";
|
||||
|
||||
export async function makeDeeplTranslateRequest(_: IpcMainInvokeEvent, pro: boolean, apiKey: string, payload: string) {
|
||||
const url = pro
|
||||
? "https://api.deepl.com/v2/translate"
|
||||
: "https://api-free.deepl.com/v2/translate";
|
||||
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": `DeepL-Auth-Key ${apiKey}`
|
||||
},
|
||||
body: payload
|
||||
});
|
||||
|
||||
const data = await res.text();
|
||||
return { status: res.status, data };
|
||||
} catch (e) {
|
||||
return { status: -1, data: String(e) };
|
||||
}
|
||||
}
|
|
@ -22,38 +22,76 @@ import { OptionType } from "@utils/types";
|
|||
export const settings = definePluginSettings({
|
||||
receivedInput: {
|
||||
type: OptionType.STRING,
|
||||
description: "Input language for received messages",
|
||||
description: "Language that received messages should be translated from",
|
||||
default: "auto",
|
||||
hidden: true
|
||||
},
|
||||
receivedOutput: {
|
||||
type: OptionType.STRING,
|
||||
description: "Output language for received messages",
|
||||
description: "Language that received messages should be translated to",
|
||||
default: "en",
|
||||
hidden: true
|
||||
},
|
||||
sentInput: {
|
||||
type: OptionType.STRING,
|
||||
description: "Input language for sent messages",
|
||||
description: "Language that your own messages should be translated from",
|
||||
default: "auto",
|
||||
hidden: true
|
||||
},
|
||||
sentOutput: {
|
||||
type: OptionType.STRING,
|
||||
description: "Output language for sent messages",
|
||||
description: "Language that your own messages should be translated to",
|
||||
default: "en",
|
||||
hidden: true
|
||||
},
|
||||
|
||||
showChatBarButton: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Show translate button in chat bar",
|
||||
default: true
|
||||
},
|
||||
service: {
|
||||
type: OptionType.SELECT,
|
||||
description: IS_WEB ? "Translation service (Not supported on Web!)" : "Translation service",
|
||||
disabled: () => IS_WEB,
|
||||
options: [
|
||||
{ label: "Google Translate", value: "google", default: true },
|
||||
{ label: "DeepL Free", value: "deepl" },
|
||||
{ label: "DeepL Pro", value: "deepl-pro" }
|
||||
] as const,
|
||||
onChange: resetLanguageDefaults
|
||||
},
|
||||
deeplApiKey: {
|
||||
type: OptionType.STRING,
|
||||
description: "DeepL API key",
|
||||
default: "",
|
||||
placeholder: "Get your API key from https://deepl.com/your-account",
|
||||
disabled: () => IS_WEB
|
||||
},
|
||||
autoTranslate: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Automatically translate your messages before sending. You can also shift/right click the translate button to toggle this",
|
||||
default: false
|
||||
},
|
||||
showChatBarButton: {
|
||||
showAutoTranslateTooltip: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Show translate button in chat bar",
|
||||
description: "Show a tooltip on the ChatBar button whenever a message is automatically translated",
|
||||
default: true
|
||||
}
|
||||
},
|
||||
}).withPrivateSettings<{
|
||||
showAutoTranslateAlert: boolean;
|
||||
}>();
|
||||
|
||||
export function resetLanguageDefaults() {
|
||||
if (IS_WEB || settings.store.service === "google") {
|
||||
settings.store.receivedInput = "auto";
|
||||
settings.store.receivedOutput = "en";
|
||||
settings.store.sentInput = "auto";
|
||||
settings.store.sentOutput = "en";
|
||||
} else {
|
||||
settings.store.receivedInput = "";
|
||||
settings.store.receivedOutput = "en-us";
|
||||
settings.store.sentInput = "";
|
||||
settings.store.sentOutput = "en-us";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
}
|
||||
|
||||
.vc-trans-modal-header {
|
||||
justify-content: space-between;
|
||||
align-content: center;
|
||||
place-content: center space-between;
|
||||
}
|
||||
|
||||
.vc-trans-modal-header h1 {
|
||||
|
|
|
@ -17,12 +17,18 @@
|
|||
*/
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { onlyOnce } from "@utils/onlyOnce";
|
||||
import { PluginNative } from "@utils/types";
|
||||
import { showToast, Toasts } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { DeeplLanguages, deeplLanguageToGoogleLanguage, GoogleLanguages } from "./languages";
|
||||
import { resetLanguageDefaults, settings } from "./settings";
|
||||
|
||||
export const cl = classNameFactory("vc-trans-");
|
||||
|
||||
interface TranslationData {
|
||||
const Native = VencordNative.pluginHelpers.Translate as PluginNative<typeof import("./native")>;
|
||||
|
||||
interface GoogleData {
|
||||
src: string;
|
||||
sentences: {
|
||||
// 🏳️⚧️
|
||||
|
@ -30,15 +36,47 @@ interface TranslationData {
|
|||
}[];
|
||||
}
|
||||
|
||||
interface DeeplData {
|
||||
translations: {
|
||||
detected_source_language: string;
|
||||
text: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface TranslationValue {
|
||||
src: string;
|
||||
sourceLanguage: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export async function translate(kind: "received" | "sent", text: string): Promise<TranslationValue> {
|
||||
const sourceLang = settings.store[kind + "Input"];
|
||||
const targetLang = settings.store[kind + "Output"];
|
||||
export const getLanguages = () => IS_WEB || settings.store.service === "google"
|
||||
? GoogleLanguages
|
||||
: DeeplLanguages;
|
||||
|
||||
export async function translate(kind: "received" | "sent", text: string): Promise<TranslationValue> {
|
||||
const translate = IS_WEB || settings.store.service === "google"
|
||||
? googleTranslate
|
||||
: deeplTranslate;
|
||||
|
||||
try {
|
||||
return await translate(
|
||||
text,
|
||||
settings.store[`${kind}Input`],
|
||||
settings.store[`${kind}Output`]
|
||||
);
|
||||
} catch (e) {
|
||||
const userMessage = typeof e === "string"
|
||||
? e
|
||||
: "Something went wrong. If this issue persists, please check the console or ask for help in the support server.";
|
||||
|
||||
showToast(userMessage, Toasts.Type.FAILURE);
|
||||
|
||||
throw e instanceof Error
|
||||
? e
|
||||
: new Error(userMessage);
|
||||
}
|
||||
}
|
||||
|
||||
async function googleTranslate(text: string, sourceLang: string, targetLang: string): Promise<TranslationValue> {
|
||||
const url = "https://translate.googleapis.com/translate_a/single?" + new URLSearchParams({
|
||||
// see https://stackoverflow.com/a/29537590 for more params
|
||||
// holy shidd nvidia
|
||||
|
@ -63,13 +101,69 @@ export async function translate(kind: "received" | "sent", text: string): Promis
|
|||
+ `\n${res.status} ${res.statusText}`
|
||||
);
|
||||
|
||||
const { src, sentences }: TranslationData = await res.json();
|
||||
const { src, sentences }: GoogleData = await res.json();
|
||||
|
||||
return {
|
||||
src,
|
||||
sourceLanguage: GoogleLanguages[src] ?? src,
|
||||
text: sentences.
|
||||
map(s => s?.trans).
|
||||
filter(Boolean).
|
||||
join("")
|
||||
};
|
||||
}
|
||||
|
||||
function fallbackToGoogle(text: string, sourceLang: string, targetLang: string): Promise<TranslationValue> {
|
||||
return googleTranslate(
|
||||
text,
|
||||
deeplLanguageToGoogleLanguage(sourceLang),
|
||||
deeplLanguageToGoogleLanguage(targetLang)
|
||||
);
|
||||
}
|
||||
|
||||
const showDeeplApiQuotaToast = onlyOnce(
|
||||
() => showToast("Deepl API quota exceeded. Falling back to Google Translate", Toasts.Type.FAILURE)
|
||||
);
|
||||
|
||||
async function deeplTranslate(text: string, sourceLang: string, targetLang: string): Promise<TranslationValue> {
|
||||
if (!settings.store.deeplApiKey) {
|
||||
showToast("DeepL API key is not set. Resetting to Google", Toasts.Type.FAILURE);
|
||||
|
||||
settings.store.service = "google";
|
||||
resetLanguageDefaults();
|
||||
|
||||
return fallbackToGoogle(text, sourceLang, targetLang);
|
||||
}
|
||||
|
||||
// CORS jumpscare
|
||||
const { status, data } = await Native.makeDeeplTranslateRequest(
|
||||
settings.store.service === "deepl-pro",
|
||||
settings.store.deeplApiKey,
|
||||
JSON.stringify({
|
||||
text: [text],
|
||||
target_lang: targetLang,
|
||||
source_lang: sourceLang.split("-")[0]
|
||||
})
|
||||
);
|
||||
|
||||
switch (status) {
|
||||
case 200:
|
||||
break;
|
||||
case -1:
|
||||
throw "Failed to connect to DeepL API: " + data;
|
||||
case 403:
|
||||
throw "Invalid DeepL API key or version";
|
||||
case 456:
|
||||
showDeeplApiQuotaToast();
|
||||
return fallbackToGoogle(text, sourceLang, targetLang);
|
||||
default:
|
||||
throw new Error(`Failed to translate "${text}" (${sourceLang} -> ${targetLang})\n${status} ${data}`);
|
||||
}
|
||||
|
||||
const { translations }: DeeplData = JSON.parse(data);
|
||||
const src = translations[0].detected_source_language;
|
||||
|
||||
return {
|
||||
sourceLanguage: DeeplLanguages[src] ?? src,
|
||||
text: translations[0].text
|
||||
};
|
||||
}
|
||||
|
|
|
@ -189,7 +189,8 @@ export default definePlugin({
|
|||
replacement: {
|
||||
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/,
|
||||
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openImage($1)},"
|
||||
}
|
||||
},
|
||||
all: true
|
||||
},
|
||||
// Old Profiles Modal pfp
|
||||
{
|
||||
|
|
|
@ -153,6 +153,7 @@ export default definePlugin({
|
|||
contextMenus: {
|
||||
"guild-context": MakeContextCallback("Guild"),
|
||||
"channel-context": MakeContextCallback("Channel"),
|
||||
"thread-context": MakeContextCallback("Channel"),
|
||||
"user-context": MakeContextCallback("User")
|
||||
},
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# XSOverlay Notifier
|
||||
|
||||
Sends Discord messages to [XSOverlay](https://store.steampowered.com/app/1173510/XSOverlay/) for easier viewing while using VR.
|
||||
|
||||
## Preview
|
||||
|
||||
![](https://github.com/Vendicated/Vencord/assets/24845294/205d2055-bb4a-44e4-b7e3-265391bccd40)
|
||||
|
||||
![](https://github.com/Vendicated/Vencord/assets/24845294/f15eff61-2d52-4620-bcab-808ecb1606d2)
|
||||
|
||||
## Usage
|
||||
- Enable this plugin
|
||||
- Set plugin settings as desired
|
||||
- Open XSOverlay
|
||||
- get ping spammed
|
14
src/plugins/xsOverlay/README.md
Normal file
14
src/plugins/xsOverlay/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# XSOverlay Notifier
|
||||
|
||||
Sends Discord messages to [XSOverlay](https://store.steampowered.com/app/1173510/XSOverlay/) for easier viewing while using VR.
|
||||
|
||||
## Preview
|
||||
|
||||
![Resulting notification inside XSOverlay](https://github.com/Vendicated/Vencord/assets/24845294/205d2055-bb4a-44e4-b7e3-265391bccd40)
|
||||
|
||||
![Test notification inside XSOverlay](https://github.com/user-attachments/assets/d3b0c387-1d67-4697-a470-d4a927e228f4)
|
||||
|
||||
## Usage
|
||||
- Enable this plugin
|
||||
- Set port and plugin settings as desired (defaults should work fine)
|
||||
- Open SteamVR and XSOverlay
|
|
@ -9,8 +9,8 @@ import { makeRange } from "@components/PluginSettings/components";
|
|||
import { Devs } from "@utils/constants";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types";
|
||||
import { find, findByCode } from "@webpack";
|
||||
import { ChannelStore, GuildStore, UserStore } from "@webpack/common";
|
||||
import { findByCode, find } from "@webpack";
|
||||
import { Button, ChannelStore, GuildStore, UserStore } from "@webpack/common";
|
||||
import type { Channel, Embed, GuildMember, MessageAttachment, User } from "discord-types/general";
|
||||
|
||||
const ChannelTypes = find(m => m.ANNOUNCEMENT_THREAD === 10);
|
||||
|
@ -68,10 +68,45 @@ interface Call {
|
|||
ringing: string[];
|
||||
}
|
||||
|
||||
interface ApiObject {
|
||||
sender: string,
|
||||
target: string,
|
||||
command: string,
|
||||
jsonData: string,
|
||||
rawData: string | null,
|
||||
}
|
||||
|
||||
interface NotificationObject {
|
||||
type: number;
|
||||
timeout: number;
|
||||
height: number;
|
||||
opacity: number;
|
||||
volume: number;
|
||||
audioPath: string;
|
||||
title: string;
|
||||
content: string;
|
||||
useBase64Icon: boolean;
|
||||
icon: ArrayBuffer | string;
|
||||
sourceApp: string;
|
||||
}
|
||||
|
||||
const notificationsShouldNotify = findByCode(".SUPPRESS_NOTIFICATIONS))return!1");
|
||||
const XSLog = new Logger("XSOverlay");
|
||||
|
||||
const settings = definePluginSettings({
|
||||
webSocketPort: {
|
||||
type: OptionType.NUMBER,
|
||||
description: "Websocket port",
|
||||
default: 42070,
|
||||
async onChange() {
|
||||
await start();
|
||||
}
|
||||
},
|
||||
preferUDP: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Enable if you use an older build of XSOverlay unable to connect through websockets. This setting is ignored on web.",
|
||||
default: false,
|
||||
disabled: () => IS_WEB
|
||||
},
|
||||
botNotifications: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Allow bot notifications",
|
||||
|
@ -136,6 +171,18 @@ const settings = definePluginSettings({
|
|||
},
|
||||
});
|
||||
|
||||
let socket: WebSocket;
|
||||
|
||||
async function start() {
|
||||
if (socket) socket.close();
|
||||
socket = new WebSocket(`ws://127.0.0.1:${settings.store.webSocketPort ?? 42070}/?client=Vencord`);
|
||||
return new Promise((resolve, reject) => {
|
||||
socket.onopen = resolve;
|
||||
socket.onerror = reject;
|
||||
setTimeout(reject, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
const Native = VencordNative.pluginHelpers.XSOverlay as PluginNative<typeof import("./native")>;
|
||||
|
||||
export default definePlugin({
|
||||
|
@ -248,7 +295,21 @@ export default definePlugin({
|
|||
if (shouldIgnoreForChannelType(channel)) return;
|
||||
sendMsgNotif(titleString, finalMsg, message);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
start,
|
||||
|
||||
stop() {
|
||||
socket.close();
|
||||
},
|
||||
|
||||
settingsAboutComponent: () => (
|
||||
<>
|
||||
<Button onClick={() => sendOtherNotif("This is a test notification! explode", "Hello from Vendor!")}>
|
||||
Send test notification
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
});
|
||||
|
||||
function shouldIgnoreForChannelType(channel: Channel) {
|
||||
|
@ -259,9 +320,8 @@ function shouldIgnoreForChannelType(channel: Channel) {
|
|||
|
||||
function sendMsgNotif(titleString: string, content: string, message: Message) {
|
||||
fetch(`https://cdn.discordapp.com/avatars/${message.author.id}/${message.author.avatar}.png?size=128`).then(response => response.arrayBuffer()).then(result => {
|
||||
const msgData = {
|
||||
messageType: 1,
|
||||
index: 0,
|
||||
const msgData: NotificationObject = {
|
||||
type: 1,
|
||||
timeout: settings.store.lengthBasedTimeout ? calculateTimeout(content) : settings.store.timeout,
|
||||
height: calculateHeight(content),
|
||||
opacity: settings.store.opacity,
|
||||
|
@ -270,17 +330,17 @@ function sendMsgNotif(titleString: string, content: string, message: Message) {
|
|||
title: titleString,
|
||||
content: content,
|
||||
useBase64Icon: true,
|
||||
icon: result,
|
||||
icon: new TextDecoder().decode(result),
|
||||
sourceApp: "Vencord"
|
||||
};
|
||||
Native.sendToOverlay(msgData);
|
||||
|
||||
sendToOverlay(msgData);
|
||||
});
|
||||
}
|
||||
|
||||
function sendOtherNotif(content: string, titleString: string) {
|
||||
const msgData = {
|
||||
messageType: 1,
|
||||
index: 0,
|
||||
const msgData: NotificationObject = {
|
||||
type: 1,
|
||||
timeout: settings.store.lengthBasedTimeout ? calculateTimeout(content) : settings.store.timeout,
|
||||
height: calculateHeight(content),
|
||||
opacity: settings.store.opacity,
|
||||
|
@ -289,10 +349,26 @@ function sendOtherNotif(content: string, titleString: string) {
|
|||
title: titleString,
|
||||
content: content,
|
||||
useBase64Icon: false,
|
||||
icon: null,
|
||||
icon: "default",
|
||||
sourceApp: "Vencord"
|
||||
};
|
||||
Native.sendToOverlay(msgData);
|
||||
sendToOverlay(msgData);
|
||||
}
|
||||
|
||||
async function sendToOverlay(notif: NotificationObject) {
|
||||
if (!IS_WEB && settings.store.preferUDP) {
|
||||
Native.sendToOverlay(notif);
|
||||
return;
|
||||
}
|
||||
const apiObject: ApiObject = {
|
||||
sender: "Vencord",
|
||||
target: "xsoverlay",
|
||||
command: "SendNotification",
|
||||
jsonData: JSON.stringify(notif),
|
||||
rawData: null
|
||||
};
|
||||
if (socket.readyState !== socket.OPEN) await start();
|
||||
socket.send(JSON.stringify(apiObject));
|
||||
}
|
||||
|
||||
function shouldNotify(message: Message, channel: string) {
|
|
@ -9,7 +9,7 @@ import { createSocket, Socket } from "dgram";
|
|||
let xsoSocket: Socket;
|
||||
|
||||
export function sendToOverlay(_, data: any) {
|
||||
data.icon = Buffer.from(data.icon).toString("base64");
|
||||
data.messageType = data.type;
|
||||
const json = JSON.stringify(data);
|
||||
xsoSocket ??= createSocket("udp4");
|
||||
xsoSocket.send(json, 42069, "127.0.0.1");
|
|
@ -1,6 +1,7 @@
|
|||
# WatchTogetherAdblock
|
||||
|
||||
Block ads in the YouTube WatchTogether activity via AdGuard
|
||||
Block ads in YouTube embeds and the 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)
|
|
@ -165,11 +165,9 @@ const overrideObject = (obj, propertyName, overrideValue) => {
|
|||
}
|
||||
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;
|
|
@ -4,12 +4,14 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { migratePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
// The entire code of this plugin can be found in native.ts
|
||||
migratePluginSettings("YoutubeAdblock", "WatchTogetherAdblock");
|
||||
export default definePlugin({
|
||||
name: "WatchTogetherAdblock",
|
||||
description: "Block ads in the YouTube WatchTogether activity via AdGuard",
|
||||
authors: [Devs.ImLvna],
|
||||
name: "YoutubeAdblock",
|
||||
description: "Block ads in YouTube embeds and the WatchTogether activity via AdGuard",
|
||||
authors: [Devs.ImLvna, Devs.Ven],
|
||||
});
|
|
@ -11,9 +11,9 @@ 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;
|
||||
if (!RendererSettings.store.plugins?.YoutubeAdblock?.enabled) return;
|
||||
|
||||
if (frame.url.includes("youtube.com/embed/") || (frame.url.includes("discordsays") && frame.url.includes("youtube.com"))) {
|
||||
frame.executeJavaScript(adguard);
|
||||
}
|
||||
});
|
|
@ -532,6 +532,18 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
Antti: {
|
||||
name: "Antti",
|
||||
id: 312974985876471810n
|
||||
},
|
||||
Joona: {
|
||||
name: "Joona",
|
||||
id: 297410829589020673n
|
||||
},
|
||||
AshtonMemer: {
|
||||
name: "AshtonMemer",
|
||||
id: 373657230530052099n
|
||||
},
|
||||
surgedevs: {
|
||||
name: "Chloe",
|
||||
id: 1084592643784331324n
|
||||
}
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { find, findByProps } from "../api";
|
||||
import { find, findByProps } from "@webpack";
|
||||
|
||||
import * as t from "./types/classes";
|
||||
|
||||
export const ModalImageClasses = find<t.ImageModalClasses>(m => m.image && m.modal && !m.applicationIcon);
|
||||
|
|
|
@ -17,9 +17,8 @@
|
|||
*/
|
||||
|
||||
import { NoopComponent } from "@utils/react";
|
||||
import { filters, findByProps, findComponent, findComponentByCode, findExportedComponent } from "@webpack";
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { filters, findByProps, findComponent, findComponentByCode, findExportedComponent } from "../api";
|
||||
import * as t from "./types/components";
|
||||
|
||||
export let Card: t.Card = NoopComponent as any;
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { filters, findByProps, mapMangledModule } from "../api";
|
||||
import { filters, findByProps, mapMangledModule } from "@webpack";
|
||||
|
||||
import type * as t from "./types/menu";
|
||||
|
||||
export const Menu = findByProps<t.Menu>("MenuItem", "MenuSliderControl");
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { findByProps } from "../api";
|
||||
import { findByProps } from "@webpack";
|
||||
|
||||
export let useState: typeof React.useState;
|
||||
export let useEffect: typeof React.useEffect;
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { findByCode, findByProps, findStore } from "../api";
|
||||
import { findByCode, findByProps, findStore } from "@webpack";
|
||||
|
||||
import * as t from "./types/stores";
|
||||
|
||||
export const Flux = findByProps<t.Flux>("connectStores");
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { find } from "../api";
|
||||
import { find } from "@webpack";
|
||||
|
||||
export const UserSettingsActionCreators = {
|
||||
FrecencyUserSettingsActionCreators: find(m => m.ProtoClass?.typeName?.endsWith(".FrecencyUserSettings")),
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { _resolveDiscordLoaded, filters, find, findByCode, findByProps, mapMangledModule, waitFor } from "../api";
|
||||
import { _resolveDiscordLoaded, filters, find, findByCode, findByProps, mapMangledModule, waitFor } from "@webpack";
|
||||
|
||||
import type * as t from "./types/utils";
|
||||
|
||||
export const FluxDispatcher = findByProps<t.FluxDispatcher>("dispatch", "subscribe", (m: t.FluxDispatcher) => {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"allowJs": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"DOM.Iterable",
|
||||
|
@ -37,7 +38,8 @@
|
|||
"transform": "typescript-transform-paths",
|
||||
"afterDeclarations": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"outDir": "who-fucking-cares-dude"
|
||||
},
|
||||
"include": ["src/**/*", "browser/**/*", "scripts/**/*"]
|
||||
"include": ["src/**/*", "browser/**/*", "scripts/**/*", "eslint.config.mjs"],
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue