feat(plugin): FakeProfileThemes (#710)
This commit is contained in:
		
							parent
							
								
									265c7a18a7
								
							
						
					
					
						commit
						62f74f5917
					
				
					 4 changed files with 147 additions and 11 deletions
				
			
		|  | @ -34,12 +34,12 @@ | |||
|         "@vap/core": "0.0.12", | ||||
|         "@vap/shiki": "0.10.3", | ||||
|         "fflate": "^0.7.4", | ||||
|         "nanoid": "^4.0.2" | ||||
|         "nanoid": "^4.0.2", | ||||
|         "virtual-merge": "^1.0.1" | ||||
|     }, | ||||
|     "devDependencies": { | ||||
|         "@types/diff": "^5.0.2", | ||||
|         "@types/lodash": "^4.14.191", | ||||
|         "@types/nanoid": "^3.0.0", | ||||
|         "@types/node": "^18.11.18", | ||||
|         "@types/react": "^18.0.27", | ||||
|         "@types/react-dom": "^18.0.10", | ||||
|  |  | |||
							
								
								
									
										16
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								pnpm-lock.yaml
									
										
									
										generated
									
									
									
								
							|  | @ -11,7 +11,6 @@ patchedDependencies: | |||
| specifiers: | ||||
|   '@types/diff': ^5.0.2 | ||||
|   '@types/lodash': ^4.14.191 | ||||
|   '@types/nanoid': ^3.0.0 | ||||
|   '@types/node': ^18.11.18 | ||||
|   '@types/react': ^18.0.27 | ||||
|   '@types/react-dom': ^18.0.10 | ||||
|  | @ -40,17 +39,18 @@ specifiers: | |||
|   tsx: ^3.12.6 | ||||
|   type-fest: ^3.5.3 | ||||
|   typescript: ^4.9.4 | ||||
|   virtual-merge: ^1.0.1 | ||||
| 
 | ||||
| dependencies: | ||||
|   '@vap/core': 0.0.12 | ||||
|   '@vap/shiki': 0.10.3 | ||||
|   fflate: 0.7.4 | ||||
|   nanoid: 4.0.2 | ||||
|   virtual-merge: 1.0.1 | ||||
| 
 | ||||
| devDependencies: | ||||
|   '@types/diff': 5.0.2 | ||||
|   '@types/lodash': 4.14.191 | ||||
|   '@types/nanoid': 3.0.0 | ||||
|   '@types/node': 18.11.18 | ||||
|   '@types/react': 18.0.27 | ||||
|   '@types/react-dom': 18.0.10 | ||||
|  | @ -421,13 +421,6 @@ packages: | |||
|     resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} | ||||
|     dev: true | ||||
| 
 | ||||
|   /@types/nanoid/3.0.0: | ||||
|     resolution: {integrity: sha512-UXitWSmXCwhDmAKe7D3hNQtQaHeHt5L8LO1CB8GF8jlYVzOv5cBWDNqiJ+oPEWrWei3i3dkZtHY/bUtd0R/uOQ==} | ||||
|     deprecated: This is a stub types definition. nanoid provides its own type definitions, so you do not need this installed. | ||||
|     dependencies: | ||||
|       nanoid: 4.0.2 | ||||
|     dev: true | ||||
| 
 | ||||
|   /@types/node/18.11.18: | ||||
|     resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} | ||||
|     dev: true | ||||
|  | @ -2260,6 +2253,7 @@ packages: | |||
|     resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==} | ||||
|     engines: {node: ^14 || ^16 || >=18} | ||||
|     hasBin: true | ||||
|     dev: false | ||||
| 
 | ||||
|   /nanomatch/1.2.13: | ||||
|     resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} | ||||
|  | @ -3139,6 +3133,10 @@ packages: | |||
|       spdx-expression-parse: 3.0.1 | ||||
|     dev: true | ||||
| 
 | ||||
|   /virtual-merge/1.0.1: | ||||
|     resolution: {integrity: sha512-h7rzV6n5fZJbDu2lP4iu+IOtsZ00uqECFUxFePK1uY0pz/S5B7FNDJpmdDVfyGL7poyJECEHfTaIpJaknNkU0Q==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /vscode-oniguruma/1.7.0: | ||||
|     resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} | ||||
|     dev: false | ||||
|  |  | |||
							
								
								
									
										130
									
								
								src/plugins/fakeProfileThemes.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/plugins/fakeProfileThemes.tsx
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,130 @@ | |||
| /* | ||||
|  * 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/>.
 | ||||
| */ | ||||
| 
 | ||||
| // This plugin is a port from Alyxia's Vendetta plugin
 | ||||
| import { definePluginSettings } from "@api/settings"; | ||||
| import ErrorBoundary from "@components/ErrorBoundary"; | ||||
| import { Devs } from "@utils/constants"; | ||||
| import { Margins } from "@utils/margins"; | ||||
| import { copyWithToast } from "@utils/misc"; | ||||
| import definePlugin, { OptionType } from "@utils/types"; | ||||
| import { Button } from "@webpack/common"; | ||||
| import { User } from "discord-types/general"; | ||||
| import virtualMerge from "virtual-merge"; | ||||
| 
 | ||||
| interface UserProfile extends User { | ||||
|     themeColors?: Array<number>; | ||||
| } | ||||
| 
 | ||||
| interface Colors { | ||||
|     primary: number; | ||||
|     accent: number; | ||||
| } | ||||
| 
 | ||||
| function encode(primary: number, accent: number): string { | ||||
|     const message = `[#${primary.toString(16).padStart(6, "0")},#${accent.toString(16).padStart(6, "0")}]`; | ||||
|     const padding = ""; | ||||
|     const encoded = Array.from(message) | ||||
|         .map(x => x.codePointAt(0)) | ||||
|         .filter(x => x! >= 0x20 && x! <= 0x7f) | ||||
|         .map(x => String.fromCodePoint(x! + 0xe0000)) | ||||
|         .join(""); | ||||
| 
 | ||||
|     return (padding || "") + " " + encoded; | ||||
| } | ||||
| 
 | ||||
| // Courtesy of Cynthia.
 | ||||
| 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, | ||||
|     ); | ||||
|     if (colorString != null) { | ||||
|         const parsed = [...colorString[0]] | ||||
|             .map(x => String.fromCodePoint(x.codePointAt(0)! - 0xe0000)) | ||||
|             .join(""); | ||||
|         const colors = parsed | ||||
|             .substring(1, parsed.length - 1) | ||||
|             .split(",") | ||||
|             .map(x => parseInt(x.replace("#", "0x"), 16)); | ||||
| 
 | ||||
|         return colors; | ||||
|     } else { | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const settings = definePluginSettings({ | ||||
|     nitroFirst: { | ||||
|         description: "Default color source if both are present", | ||||
|         type: OptionType.SELECT, | ||||
|         options: [ | ||||
|             { label: "Nitro colors", value: true, default: true }, | ||||
|             { label: "Fake colors", value: false }, | ||||
|         ] | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| export default definePlugin({ | ||||
|     name: "FakeProfileThemes", | ||||
|     description: "Allows profile theming by hiding the colors in your bio thanks to invisible 3y3 encoding.", | ||||
|     authors: [Devs.Alyxia, Devs.Remty], | ||||
|     patches: [ | ||||
|         { | ||||
|             find: "getUserProfile=", | ||||
|             replacement: { | ||||
|                 match: /(?<=getUserProfile=function\(\i\){return )(\i\[\i\])/, | ||||
|                 replace: "$self.colorDecodeHook($1)" | ||||
|             } | ||||
|         }, { | ||||
|             find: ".USER_SETTINGS_PROFILE_THEME_ACCENT", | ||||
|             replacement: { | ||||
|                 match: /RESET_PROFILE_THEME}\)(?<=},color:(\i).+?},color:(\i).+?)/, | ||||
|                 replace: "$&,$self.addCopy3y3Button({primary:$1,accent:$2})" | ||||
|             } | ||||
|         } | ||||
|     ], | ||||
|     settings, | ||||
|     colorDecodeHook(user: UserProfile) { | ||||
|         if (user) { | ||||
|             // don't replace colors if already set with nitro
 | ||||
|             if (settings.store.nitroFirst && user.themeColors) return user; | ||||
|             const colors = decode(user.bio); | ||||
|             if (colors) { | ||||
|                 return virtualMerge(user, { | ||||
|                     premiumType: 2, | ||||
|                     themeColors: colors | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|         return user; | ||||
|     }, | ||||
|     addCopy3y3Button: ErrorBoundary.wrap(function ({ primary, accent }: Colors) { | ||||
|         return <Button | ||||
|             onClick={() => { | ||||
|                 const colorString = encode(primary, accent); | ||||
|                 copyWithToast(colorString); | ||||
|             }} | ||||
|             color={Button.Colors.PRIMARY} | ||||
|             size={Button.Sizes.XLARGE} | ||||
|             className={Margins.left16} | ||||
|         >Copy 3y3 | ||||
|         </Button >; | ||||
|     }, { noop: true }), | ||||
| }); | ||||
|  | @ -226,6 +226,14 @@ export const Devs = /* #__PURE__*/ Object.freeze({ | |||
|         name: "TheKodeToad", | ||||
|         id: 706152404072267788n | ||||
|     }, | ||||
|     Alyxia: { | ||||
|         name: "Alyxia Sother", | ||||
|         id: 952185386350829688n | ||||
|     }, | ||||
|     Remty: { | ||||
|         name: "Remty", | ||||
|         id: 335055032204656642n | ||||
|     }, | ||||
|     skyevg: { | ||||
|         name: "skyevg", | ||||
|         id: 1090310844283363348n | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue