Skip to content

Commit

Permalink
First version
Browse files Browse the repository at this point in the history
  • Loading branch information
cafeed28 committed Dec 23, 2022
1 parent f53afe2 commit d6a6c66
Show file tree
Hide file tree
Showing 10 changed files with 152 additions and 116 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ overrides:
- files: "src/**/*.ts"
parserOptions:
project: tsconfig.json

ignorePatterns:
- "dist/*"
24 changes: 12 additions & 12 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always",
"proseWrap": "always"
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always",
"proseWrap": "always"
}
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
"editor.formatOnSave": true,
"[markdown]": {
"editor.defaultFormatter": "denoland.vscode-deno"
}
}
81 changes: 9 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,13 @@
# Replugged plugin template
# NitroSpoof

[Use this template](https://github.com/replugged-org/plugin-template/generate)
Send Nitro emojis as images.

## Prerequisites
## Features

- NodeJS
- pnpm: `npm i -g pnpm`
- [Replugged](https://github.com/replugged-org/replugged#installation)
- Supports emoji escaping
- Can use emojis if they are unavailable due to a lack of boosts (grayed out in
emoji picker)
- Removes unavailable emoji tint in emoji picker
- Doesn't spoof premiumType

## Install

1. [Create a copy of this template](https://github.com/replugged-org/plugin-template/generate)
2. Clone your new repository and cd into it
3. Install dependencies: `pnpm i`
4. Build the plugin: `pnpm run build`
5. Reload Discord to load the plugin

The unmodified plugin will log "Typing prevented" in the console when you start typing in any
channel.

## Development

The code must be rebuilt after every change. You can use `pnpm run watch` to automatically rebuild
the plugin when you save a file.

Building using the script above will automatically install the updated version of the plugin in
Replugged. You can find the plugin folder directories for your OS
[here](https://github.com/replugged-org/replugged#installing-plugins-and-themes).
If you don't want to install the updated version, append the `--no-install` flag:
`pnpm run build --no-install`.

You can format the code by running `pnpm run lint:fix`. The repository includes VSCode settings to
automatically format on save.

API docs coming soon(tm)

## Distribution

For plugin distribution, Replugged uses bundled `.asar` files. Bundled plugins can be installed to
the same plugin folder as listed above.

This repository includes a GitHub workflow to compile and publish a release with the asar file. To
trigger it, create a tag with the version number preceded by a `v` (e.g. `v1.0.0`) and push it to
GitHub:

```sh
git tag v1.0.0
git push --tags
```

The Replugged updater (coming soon™) will automatically check for updates on the repository
specified in the manifest. Make sure to update it to point to the correct repository!

You can manually compile the asar file with `pnpm run build-and-bundle`.

## Troubleshooting

### Make sure Replugged is installed and running.

Open Discord settings and make sure the Replugged tab is there. If not,
[follow these instructions](https://github.com/replugged-org/replugged#installation) to install
Replugged.

### Make sure the plugin is installed.

Check the [plugin folder](https://github.com/replugged-org/replugged#installing-plugins-and-themes)
for your OS and make sure the plugin is there. If not, make sure you have built the plugin and that
the `NO_INSTALL` environment variable is not set.
You can run `replugged.plugins.list().then(console.log)` in the console to see a list of plugins in
the plugin folder.

### Make sure the plugin is running.

Check the console for a message saying `[Replugged:Plugin:Plugin Template] Plugin started`. If you
don't see it, try reloading Discord. If that doesn't work, check for any errors in the console.
![image](https://cdn.discordapp.com/emojis/962730564840996964.png?size=20)
17 changes: 9 additions & 8 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
{
"id": "dev.replugged.PluginTemplate",
"name": "Plugin Template",
"description": "A plugin template",
"id": "com.cafeed28.NitroSpoof",
"name": "NitroSpoof",
"description": "Send Nitro emojis as images",
"author": {
"name": "replugged",
"name": "кафіф#0238",
"discordID": "1000992611840049192",
"github": "replugged-org"
"github": "cafeed28"
},
"version": "1.0.3",
"version": "1.0.0",
"updater": {
"type": "github",
"id": "replugged-org/plugin-template"
"id": "cafeed28/replugged-nitrospoof"
},
"license": "MIT",
"type": "replugged-plugin",
"renderer": "src/index.ts"
"renderer": "src/index.ts",
"plaintextPatches": "src/plaintextPatches.ts"
}
74 changes: 53 additions & 21 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,57 @@
import { Injector, webpack } from "replugged";

const inject = new Injector();

export async function start(): Promise<void> {
const typingMod = await webpack.waitForModule<{
startTyping: (channelId: string) => void;
}>(webpack.filters.byProps("startTyping"));
const getChannelMod = await webpack.waitForModule<{
getChannel: (id: string) => {
name: string;
};
}>(webpack.filters.byProps("getChannel"));

if (typingMod && getChannelMod) {
inject.instead(typingMod, "startTyping", ([channel]) => {
const channelObj = getChannelMod.getChannel(channel);
console.log(`Typing prevented! Channel: #${channelObj?.name ?? "unknown"} (${channel}).`);
});
}
import { Injector } from "replugged";
import { EmojiInfo, MessageActions, SelectedGuildStore } from "./webpack";
import { Emoji } from "./types";

const injector = new Injector();

// TODO: test with nitro
function isEmojiAvailable(emoji: Emoji): boolean {
// Emoji not available on Discord (e.g. emoji was in slot 50+ and the server ran out of boosts)
if (!emoji.available) return false;

if (emoji.animated) return false;

// Emoji from the current guild
// Note: getGuildId will return null if user is in DMs
if (emoji.guildId == SelectedGuildStore.getGuildId()) return true;

return false;
}

export function start(): void {
injector.before(MessageActions, "sendMessage", (args) => {
const [, message] = args;
const escapedIds: string[] = [];

for (const match of message.content.matchAll(/\\<(a?):(.*?):(.*?)>/gm)) {
escapedIds.push(match[3]);
}

for (const emoji of message.validNonShortcutEmojis) {
if (escapedIds.includes(emoji.id)) continue;
console.log(emoji);
if (isEmojiAvailable(emoji)) continue;

const animated = emoji.animated ? "a" : "";
const name = emoji.originalName || emoji.name;

const searchString = `<${animated}:${name}:${emoji.id}>`;

message.content = message.content.replace(searchString, emoji.url);
}

return args;
});

injector.instead(EmojiInfo, "getEmojiUnavailableReason", () => {
return null;
});

injector.instead(EmojiInfo, "isEmojiPremiumLocked", () => {
return false;
});
}

export function stop(): void {
inject.uninjectAll();
injector.uninjectAll();
}
16 changes: 16 additions & 0 deletions src/plaintextPatches.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { types } from "replugged";

const patches: types.PlaintextPatch[] = [
{
replacements: [
{
match: /(\.emojiItemDisabled)/g,
replace: (_, _prefix, _suffix) => {
return ".emojiItem";
},
},
],
},
];

export default patches;
27 changes: 27 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ModuleExports } from "replugged/dist/types";

export interface Emoji {
animated: boolean;
available: boolean;

name: string;
originalName?: string; // when a name ends with ~num
url: string;
id: string;
guildId: string;
}

export interface Message {
content: string;
invalidEmojis: Emoji[];
validNonShortcutEmojis: Emoji[];
}

export type SelectedGuildStoreType = ModuleExports & {
getGuildId: () => string;
};

export type EmojiInfoType = ModuleExports & {
getEmojiUnavailableReason: (id: string) => string | undefined;
isEmojiPremiumLocked: (...args: unknown[]) => boolean;
};
17 changes: 17 additions & 0 deletions src/webpack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { webpack } from "replugged";

import { EmojiInfoType, Message, SelectedGuildStoreType } from "./types";

export const SelectedGuildStore: SelectedGuildStoreType = webpack.getExportsForProps(
webpack.getByProps("getLastSelectedGuildId")!,
["getLastSelectedGuildId"],
) as unknown as SelectedGuildStoreType;

export const EmojiInfo: EmojiInfoType = webpack.getExportsForProps(
webpack.getByProps("getEmojiUnavailableReason")!,
["getEmojiUnavailableReason"],
) as unknown as EmojiInfoType;

export const MessageActions = await webpack.waitForModule<{
sendMessage: (channelId: string, message: Message) => void;
}>(webpack.filters.byProps("_sendMessage"));
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */

/* Language and Environment */
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "react" /* Specify what JSX code is generated. */,
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
Expand All @@ -25,7 +25,7 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */

/* Modules */
"module": "commonjs" /* Specify what module code is generated. */,
"module": "es2022" /* Specify what module code is generated. */,
"rootDir": "./" /* Specify the root folder within your source files. */,
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
Expand Down

0 comments on commit d6a6c66

Please sign in to comment.