2022-10-21 23:17:06 +00:00
|
|
|
/*
|
|
|
|
* Vencord, a modification for Discord's desktop app
|
|
|
|
* Copyright (c) 2022 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/>.
|
|
|
|
*/
|
|
|
|
|
2022-11-28 12:37:55 +00:00
|
|
|
import { addPreEditListener, addPreSendListener, removePreEditListener, removePreSendListener } from "@api/MessageEvents";
|
|
|
|
import { migratePluginSettings, Settings } from "@api/settings";
|
|
|
|
import { Devs } from "@utils/constants";
|
|
|
|
import { ApngDisposeOp, getGifEncoder, importApngJs } from "@utils/dependencies";
|
2023-03-19 08:44:11 +00:00
|
|
|
import { getCurrentGuild } from "@utils/discord";
|
2023-03-23 05:11:28 +00:00
|
|
|
import { proxyLazy } from "@utils/proxyLazy";
|
2022-11-28 12:37:55 +00:00
|
|
|
import definePlugin, { OptionType } from "@utils/types";
|
2023-03-22 03:01:32 +00:00
|
|
|
import { findByCodeLazy, findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
|
|
|
|
import { ChannelStore, FluxDispatcher, PermissionStore, UserStore } from "@webpack/common";
|
2022-11-07 21:23:34 +00:00
|
|
|
|
|
|
|
const DRAFT_TYPE = 0;
|
2022-11-28 12:37:55 +00:00
|
|
|
const promptToUpload = findByCodeLazy("UPLOAD_FILE_LIMIT_ERROR");
|
2023-03-21 09:03:28 +00:00
|
|
|
const UserSettingsProtoStore = findStoreLazy("UserSettingsProtoStore");
|
2023-03-23 05:11:28 +00:00
|
|
|
const PreloadedUserSettingsProtoHandler = findLazy(m => m.ProtoClass?.typeName === "discord_protos.discord_users.v1.PreloadedUserSettings");
|
|
|
|
const ReaderFactory = findByPropsLazy("readerFactory");
|
|
|
|
|
|
|
|
function searchProtoClass(localName: string, parentProtoClass: any) {
|
|
|
|
if (!parentProtoClass) return;
|
|
|
|
|
|
|
|
const field = parentProtoClass.fields.find(field => field.localName === localName);
|
|
|
|
if (!field) return;
|
|
|
|
|
|
|
|
const getter: any = Object.values(field).find(value => typeof value === "function");
|
|
|
|
return getter?.();
|
|
|
|
}
|
|
|
|
|
|
|
|
const AppearanceSettingsProto = proxyLazy(() => searchProtoClass("appearance", PreloadedUserSettingsProtoHandler.ProtoClass));
|
|
|
|
const ClientThemeSettingsProto = proxyLazy(() => searchProtoClass("clientThemeSettings", AppearanceSettingsProto));
|
2022-11-07 21:23:34 +00:00
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
const USE_EXTERNAL_EMOJIS = 1n << 18n;
|
|
|
|
const USE_EXTERNAL_STICKERS = 1n << 37n;
|
|
|
|
|
2023-02-16 01:00:09 +00:00
|
|
|
enum EmojiIntentions {
|
|
|
|
REACTION = 0,
|
|
|
|
STATUS = 1,
|
|
|
|
COMMUNITY_CONTENT = 2,
|
|
|
|
CHAT = 3,
|
|
|
|
GUILD_STICKER_RELATED_EMOJI = 4,
|
|
|
|
GUILD_ROLE_BENEFIT_EMOJI = 5,
|
|
|
|
COMMUNITY_CONTENT_ONLY = 6,
|
|
|
|
SOUNDBOARD = 7
|
|
|
|
}
|
|
|
|
|
2022-11-12 15:25:28 +00:00
|
|
|
interface BaseSticker {
|
2022-11-07 21:23:34 +00:00
|
|
|
available: boolean;
|
|
|
|
description: string;
|
|
|
|
format_type: number;
|
|
|
|
id: string;
|
|
|
|
name: string;
|
|
|
|
tags: string;
|
|
|
|
type: number;
|
|
|
|
}
|
2022-11-12 15:25:28 +00:00
|
|
|
interface GuildSticker extends BaseSticker {
|
|
|
|
guild_id: string;
|
|
|
|
}
|
|
|
|
interface DiscordSticker extends BaseSticker {
|
|
|
|
pack_id: string;
|
|
|
|
}
|
|
|
|
type Sticker = GuildSticker | DiscordSticker;
|
2022-11-07 21:23:34 +00:00
|
|
|
|
|
|
|
interface StickerPack {
|
|
|
|
id: string;
|
|
|
|
name: string;
|
|
|
|
sku_id: string;
|
|
|
|
description: string;
|
|
|
|
cover_sticker_id: string;
|
|
|
|
banner_asset_id: string;
|
|
|
|
stickers: Sticker[];
|
|
|
|
}
|
2022-08-31 18:53:36 +00:00
|
|
|
|
2022-11-14 17:05:41 +00:00
|
|
|
migratePluginSettings("FakeNitro", "NitroBypass");
|
|
|
|
|
2022-08-31 18:53:36 +00:00
|
|
|
export default definePlugin({
|
2022-11-14 17:05:41 +00:00
|
|
|
name: "FakeNitro",
|
2023-03-08 03:11:59 +00:00
|
|
|
authors: [Devs.Arjix, Devs.D3SOX, Devs.Ven, Devs.obscurity, Devs.captain, Devs.Nuckyz],
|
2023-02-18 02:32:02 +00:00
|
|
|
description: "Allows you to stream in nitro quality, send fake emojis/stickers and use client themes.",
|
2022-08-31 18:58:21 +00:00
|
|
|
dependencies: ["MessageEventsAPI"],
|
2022-11-07 21:23:34 +00:00
|
|
|
|
2022-08-31 18:53:36 +00:00
|
|
|
patches: [
|
|
|
|
{
|
2023-02-16 01:00:09 +00:00
|
|
|
find: ".PREMIUM_LOCKED;",
|
2022-11-14 17:05:41 +00:00
|
|
|
predicate: () => Settings.plugins.FakeNitro.enableEmojiBypass === true,
|
2022-08-31 18:53:36 +00:00
|
|
|
replacement: [
|
2023-02-16 01:00:09 +00:00
|
|
|
{
|
2023-03-08 03:11:59 +00:00
|
|
|
match: /(?<=(\i)=\i\.intention)/,
|
|
|
|
replace: (_, intention) => `,fakeNitroIntention=${intention}`
|
2023-02-18 02:32:02 +00:00
|
|
|
},
|
|
|
|
{
|
2023-03-21 06:07:16 +00:00
|
|
|
match: /\.(?:canUseEmojisEverywhere|canUseAnimatedEmojis)\(\i(?=\))/g,
|
|
|
|
replace: '$&,typeof fakeNitroIntention!=="undefined"?fakeNitroIntention:void 0'
|
2023-02-16 01:00:09 +00:00
|
|
|
},
|
|
|
|
{
|
2023-03-21 06:41:11 +00:00
|
|
|
match: /(&&!\i&&)!(\i)(?=\)return \i\.\i\.DISALLOW_EXTERNAL;)/,
|
2023-03-21 06:07:16 +00:00
|
|
|
replace: (_, rest, canUseExternal) => `${rest}(!${canUseExternal}&&(typeof fakeNitroIntention==="undefined"||![${EmojiIntentions.CHAT},${EmojiIntentions.GUILD_STICKER_RELATED_EMOJI}].includes(fakeNitroIntention)))`
|
2023-02-16 01:00:09 +00:00
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
find: "canUseAnimatedEmojis:function",
|
|
|
|
predicate: () => Settings.plugins.FakeNitro.enableEmojiBypass === true,
|
|
|
|
replacement: {
|
2023-03-21 06:07:16 +00:00
|
|
|
match: /((?:canUseEmojisEverywhere|canUseAnimatedEmojis):function\(\i)\){(.+?\))/g,
|
|
|
|
replace: (_, rest, premiumCheck) => `${rest},fakeNitroIntention){${premiumCheck}||fakeNitroIntention==null||[${EmojiIntentions.CHAT},${EmojiIntentions.GUILD_STICKER_RELATED_EMOJI}].includes(fakeNitroIntention)`
|
2023-02-16 01:00:09 +00:00
|
|
|
}
|
2022-10-21 11:37:53 +00:00
|
|
|
},
|
2022-11-07 21:23:34 +00:00
|
|
|
{
|
2023-02-18 02:32:02 +00:00
|
|
|
find: "canUseStickersEverywhere:function",
|
2022-11-14 17:05:41 +00:00
|
|
|
predicate: () => Settings.plugins.FakeNitro.enableStickerBypass === true,
|
2022-11-07 21:23:34 +00:00
|
|
|
replacement: {
|
2023-03-21 06:07:16 +00:00
|
|
|
match: /canUseStickersEverywhere:function\(\i\){/,
|
|
|
|
replace: "$&return true;"
|
2022-11-07 21:23:34 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
find: "\"SENDABLE\"",
|
2022-11-15 08:34:53 +00:00
|
|
|
predicate: () => Settings.plugins.FakeNitro.enableStickerBypass === true,
|
2022-11-07 21:23:34 +00:00
|
|
|
replacement: {
|
|
|
|
match: /(\w+)\.available\?/,
|
|
|
|
replace: "true?"
|
|
|
|
}
|
|
|
|
},
|
2022-10-21 11:37:53 +00:00
|
|
|
{
|
2023-02-18 02:32:02 +00:00
|
|
|
find: "canStreamHighQuality:function",
|
2022-11-14 17:05:41 +00:00
|
|
|
predicate: () => Settings.plugins.FakeNitro.enableStreamQualityBypass === true,
|
2022-10-21 11:37:53 +00:00
|
|
|
replacement: [
|
2022-10-19 10:27:20 +00:00
|
|
|
"canUseHighVideoUploadQuality",
|
2022-10-06 14:33:30 +00:00
|
|
|
"canStreamHighQuality",
|
|
|
|
"canStreamMidQuality"
|
2022-08-31 18:53:36 +00:00
|
|
|
].map(func => {
|
|
|
|
return {
|
2023-03-21 06:07:16 +00:00
|
|
|
match: new RegExp(`${func}:function\\(\\i\\){`),
|
|
|
|
replace: "$&return true;"
|
2022-08-31 18:55:58 +00:00
|
|
|
};
|
2022-08-31 18:53:36 +00:00
|
|
|
})
|
|
|
|
},
|
2022-10-01 15:04:57 +00:00
|
|
|
{
|
|
|
|
find: "STREAM_FPS_OPTION.format",
|
2022-11-14 17:05:41 +00:00
|
|
|
predicate: () => Settings.plugins.FakeNitro.enableStreamQualityBypass === true,
|
2022-10-01 15:04:57 +00:00
|
|
|
replacement: {
|
|
|
|
match: /(userPremiumType|guildPremiumTier):.{0,10}TIER_\d,?/g,
|
|
|
|
replace: ""
|
|
|
|
}
|
2022-11-07 21:23:34 +00:00
|
|
|
},
|
2023-02-18 02:32:02 +00:00
|
|
|
{
|
|
|
|
find: "canUseClientThemes:function",
|
|
|
|
replacement: {
|
2023-03-21 06:07:16 +00:00
|
|
|
match: /canUseClientThemes:function\(\i\){/,
|
|
|
|
replace: "$&return true;"
|
2023-02-18 02:32:02 +00:00
|
|
|
}
|
2023-03-21 09:03:28 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
find: '.displayName="UserSettingsProtoStore"',
|
|
|
|
replacement: [
|
|
|
|
{
|
|
|
|
match: /CONNECTION_OPEN:function\((\i)\){/,
|
|
|
|
replace: (m, props) => `${m}$self.handleProtoChange(${props}.userSettingsProto,${props}.user);`
|
|
|
|
},
|
|
|
|
{
|
|
|
|
match: /=(\i)\.local;/,
|
|
|
|
replace: (m, props) => `${m}${props}.local||$self.handleProtoChange(${props}.settings.proto);`
|
|
|
|
}
|
|
|
|
]
|
2023-03-22 03:01:32 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
find: "updateTheme:function",
|
|
|
|
replacement: {
|
2023-03-23 05:11:28 +00:00
|
|
|
match: /(function \i\(\i\){var (\i)=\i\.backgroundGradientPresetId.+?)(\i\.\i\.updateAsync.+?theme=(.+?);.+?\),\i\))/,
|
|
|
|
replace: (_, rest, backgroundGradientPresetId, originalCall, theme) => `${rest}$self.handleGradientThemeSelect(${backgroundGradientPresetId},${theme},()=>${originalCall});`
|
2023-03-22 03:01:32 +00:00
|
|
|
}
|
2023-03-23 10:45:39 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
find: 'jumboable?"jumbo":"default"',
|
|
|
|
predicate: () => Settings.plugins.FakeNitro.transformEmojis === true,
|
|
|
|
replacement: {
|
|
|
|
match: /jumboable\?"jumbo":"default",emojiId.+?}}\)},(?<=(\i)=function\(\i\){var \i=\i\.node.+?)/,
|
|
|
|
replace: (m, component) => `${m}fakeNitroEmojiComponentExport=($self.EmojiComponent=${component},void 0),`
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
find: '["strong","em","u","text","inlineCode","s","spoiler"]',
|
|
|
|
predicate: () => Settings.plugins.FakeNitro.transformEmojis === true,
|
|
|
|
replacement: [
|
|
|
|
{
|
|
|
|
match: /1!==(\i)\.length\|\|1!==\i\.length/,
|
|
|
|
replace: (m, content) => `${m}||${content}[0].target?.startsWith("https://cdn.discordapp.com/emojis/")`
|
|
|
|
},
|
|
|
|
{
|
|
|
|
match: /(?=return{hasSpoilerEmbeds:\i,content:(\i)})/,
|
|
|
|
replace: (_, content) => `${content}=$self.patchFakeNitroEmojis(${content});`
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
find: "renderEmbeds=function",
|
|
|
|
predicate: () => Settings.plugins.FakeNitro.transformEmojis === true,
|
|
|
|
replacement: {
|
|
|
|
match: /renderEmbeds=function\(\i\){.+?embeds\.map\(\(function\((\i)\){/,
|
|
|
|
replace: (m, embed) => `${m}if(${embed}.url?.startsWith("https://cdn.discordapp.com/emojis/"))return null;`
|
|
|
|
}
|
2023-02-18 02:32:02 +00:00
|
|
|
}
|
2022-08-31 18:53:36 +00:00
|
|
|
],
|
2022-11-07 21:23:34 +00:00
|
|
|
|
2022-10-21 11:37:53 +00:00
|
|
|
options: {
|
|
|
|
enableEmojiBypass: {
|
|
|
|
description: "Allow sending fake emojis",
|
|
|
|
type: OptionType.BOOLEAN,
|
|
|
|
default: true,
|
|
|
|
restartNeeded: true,
|
|
|
|
},
|
2022-11-21 02:43:16 +00:00
|
|
|
emojiSize: {
|
|
|
|
description: "Size of the emojis when sending",
|
|
|
|
type: OptionType.SLIDER,
|
|
|
|
default: 48,
|
|
|
|
markers: [32, 48, 64, 128, 160, 256, 512],
|
|
|
|
},
|
2023-03-23 10:45:39 +00:00
|
|
|
transformEmojis: {
|
|
|
|
description: "Whether to transform fake emojis into real ones",
|
|
|
|
type: OptionType.BOOLEAN,
|
|
|
|
default: true,
|
|
|
|
restartNeeded: true,
|
|
|
|
},
|
2022-11-07 21:23:34 +00:00
|
|
|
enableStickerBypass: {
|
|
|
|
description: "Allow sending fake stickers",
|
|
|
|
type: OptionType.BOOLEAN,
|
|
|
|
default: true,
|
|
|
|
restartNeeded: true,
|
|
|
|
},
|
|
|
|
stickerSize: {
|
|
|
|
description: "Size of the stickers when sending",
|
|
|
|
type: OptionType.SLIDER,
|
|
|
|
default: 160,
|
|
|
|
markers: [32, 64, 128, 160, 256, 512],
|
|
|
|
},
|
2022-10-21 11:37:53 +00:00
|
|
|
enableStreamQualityBypass: {
|
|
|
|
description: "Allow streaming in nitro quality",
|
|
|
|
type: OptionType.BOOLEAN,
|
|
|
|
default: true,
|
|
|
|
restartNeeded: true,
|
|
|
|
}
|
|
|
|
},
|
2022-08-31 20:08:05 +00:00
|
|
|
|
2022-10-01 15:04:57 +00:00
|
|
|
get guildId() {
|
2023-03-19 08:44:11 +00:00
|
|
|
return getCurrentGuild()?.id;
|
2022-10-01 15:04:57 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
get canUseEmotes() {
|
2022-11-08 16:51:09 +00:00
|
|
|
return (UserStore.getCurrentUser().premiumType ?? 0) > 0;
|
|
|
|
},
|
|
|
|
|
2022-11-12 15:25:28 +00:00
|
|
|
get canUseStickers() {
|
2022-11-08 16:51:09 +00:00
|
|
|
return (UserStore.getCurrentUser().premiumType ?? 0) > 1;
|
2022-10-01 15:04:57 +00:00
|
|
|
},
|
|
|
|
|
2023-03-21 09:03:28 +00:00
|
|
|
handleProtoChange(proto: any, user: any) {
|
2023-03-23 05:11:28 +00:00
|
|
|
if ((!proto.appearance && !AppearanceSettingsProto) || !UserSettingsProtoStore) return;
|
2023-03-21 09:03:28 +00:00
|
|
|
|
2023-03-23 05:11:28 +00:00
|
|
|
const premiumType: number = user?.premium_type ?? UserStore?.getCurrentUser()?.premiumType ?? 0;
|
2023-03-22 03:01:32 +00:00
|
|
|
|
2023-03-23 05:11:28 +00:00
|
|
|
if (premiumType !== 2) {
|
|
|
|
proto.appearance ??= AppearanceSettingsProto.create();
|
2023-03-22 03:01:32 +00:00
|
|
|
|
|
|
|
if (UserSettingsProtoStore.settings.appearance?.theme != null) {
|
|
|
|
proto.appearance.theme = UserSettingsProtoStore.settings.appearance.theme;
|
|
|
|
}
|
2023-03-21 09:03:28 +00:00
|
|
|
|
2023-03-23 05:11:28 +00:00
|
|
|
if (UserSettingsProtoStore.settings.appearance?.clientThemeSettings?.backgroundGradientPresetId?.value != null && ClientThemeSettingsProto) {
|
|
|
|
const clientThemeSettingsDummyProto = ClientThemeSettingsProto.create({
|
|
|
|
backgroundGradientPresetId: {
|
|
|
|
value: UserSettingsProtoStore.settings.appearance.clientThemeSettings.backgroundGradientPresetId.value
|
2023-03-22 03:01:32 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-03-23 05:11:28 +00:00
|
|
|
proto.appearance.clientThemeSettings ??= clientThemeSettingsDummyProto;
|
|
|
|
proto.appearance.clientThemeSettings.backgroundGradientPresetId = clientThemeSettingsDummyProto.backgroundGradientPresetId;
|
2023-03-21 09:03:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-03-23 05:11:28 +00:00
|
|
|
handleGradientThemeSelect(backgroundGradientPresetId: number | undefined, theme: number, original: () => void) {
|
|
|
|
const premiumType = UserStore?.getCurrentUser()?.premiumType ?? 0;
|
|
|
|
if (premiumType === 2 || backgroundGradientPresetId == null) return original();
|
|
|
|
|
|
|
|
if (!AppearanceSettingsProto || !ClientThemeSettingsProto || !ReaderFactory) return;
|
|
|
|
|
|
|
|
const currentAppearanceProto = PreloadedUserSettingsProtoHandler.getCurrentValue().appearance;
|
|
|
|
|
|
|
|
const newAppearanceProto = currentAppearanceProto != null
|
|
|
|
? AppearanceSettingsProto.fromBinary(AppearanceSettingsProto.toBinary(currentAppearanceProto), ReaderFactory)
|
|
|
|
: AppearanceSettingsProto.create();
|
|
|
|
|
|
|
|
newAppearanceProto.theme = theme;
|
|
|
|
|
|
|
|
const clientThemeSettingsDummyProto = ClientThemeSettingsProto.create({
|
|
|
|
backgroundGradientPresetId: {
|
|
|
|
value: backgroundGradientPresetId
|
2023-03-22 03:01:32 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-03-23 05:11:28 +00:00
|
|
|
newAppearanceProto.clientThemeSettings ??= clientThemeSettingsDummyProto;
|
|
|
|
newAppearanceProto.clientThemeSettings.backgroundGradientPresetId = clientThemeSettingsDummyProto.backgroundGradientPresetId;
|
|
|
|
|
|
|
|
const proto = PreloadedUserSettingsProtoHandler.ProtoClass.create();
|
|
|
|
proto.appearance = newAppearanceProto;
|
|
|
|
|
2023-03-22 03:01:32 +00:00
|
|
|
FluxDispatcher.dispatch({
|
|
|
|
type: "USER_SETTINGS_PROTO_UPDATE",
|
|
|
|
local: true,
|
|
|
|
partial: true,
|
|
|
|
settings: {
|
|
|
|
type: 1,
|
|
|
|
proto
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2023-03-23 10:45:39 +00:00
|
|
|
EmojiComponent: null as any,
|
|
|
|
|
|
|
|
patchFakeNitroEmojis(content: Array<any>) {
|
|
|
|
if (!this.EmojiComponent) return content;
|
|
|
|
|
|
|
|
const newContent: Array<any> = [];
|
|
|
|
|
|
|
|
for (const element of content) {
|
|
|
|
if (element.props?.trusted == null) {
|
|
|
|
newContent.push(element);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const fakeNitroMatch = element.props.href.match(/https:\/\/cdn\.discordapp\.com\/emojis\/(\d+?)\.(png|webp|gif).+?(?=\s|$)/);
|
|
|
|
if (!fakeNitroMatch) {
|
|
|
|
newContent.push(element);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
newContent.push((
|
|
|
|
<this.EmojiComponent node={{
|
|
|
|
type: "customEmoji",
|
|
|
|
jumboable: content.length === 1,
|
|
|
|
animated: fakeNitroMatch[2] === "gif",
|
|
|
|
name: ":FakeNitroEmoji:",
|
|
|
|
emojiId: fakeNitroMatch[1]
|
|
|
|
}} />
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
return newContent;
|
|
|
|
},
|
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
hasPermissionToUseExternalEmojis(channelId: string) {
|
|
|
|
const channel = ChannelStore.getChannel(channelId);
|
|
|
|
|
|
|
|
if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return true;
|
|
|
|
|
|
|
|
return PermissionStore.can(USE_EXTERNAL_EMOJIS, channel);
|
|
|
|
},
|
|
|
|
|
|
|
|
hasPermissionToUseExternalStickers(channelId: string) {
|
|
|
|
const channel = ChannelStore.getChannel(channelId);
|
|
|
|
|
|
|
|
if (!channel || channel.isDM() || channel.isGroupDM() || channel.isMultiUserDM()) return true;
|
|
|
|
|
|
|
|
return PermissionStore.can(USE_EXTERNAL_STICKERS, channel);
|
|
|
|
},
|
|
|
|
|
2022-11-07 21:23:34 +00:00
|
|
|
getStickerLink(stickerId: string) {
|
2022-11-14 17:05:41 +00:00
|
|
|
return `https://media.discordapp.net/stickers/${stickerId}.png?size=${Settings.plugins.FakeNitro.stickerSize}`;
|
2022-11-07 21:23:34 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
async sendAnimatedSticker(stickerLink: string, stickerId: string, channelId: string) {
|
|
|
|
const [{ parseURL }, {
|
|
|
|
GIFEncoder,
|
|
|
|
quantize,
|
|
|
|
applyPalette
|
|
|
|
}] = await Promise.all([importApngJs(), getGifEncoder()]);
|
|
|
|
|
|
|
|
const { frames, width, height } = await parseURL(stickerLink);
|
|
|
|
|
|
|
|
const gif = new GIFEncoder();
|
2022-11-14 17:05:41 +00:00
|
|
|
const resolution = Settings.plugins.FakeNitro.stickerSize;
|
2022-11-07 21:23:34 +00:00
|
|
|
|
|
|
|
const canvas = document.createElement("canvas");
|
2022-11-09 16:30:37 +00:00
|
|
|
canvas.width = resolution;
|
|
|
|
canvas.height = resolution;
|
2022-11-07 21:23:34 +00:00
|
|
|
|
|
|
|
const ctx = canvas.getContext("2d", {
|
|
|
|
willReadFrequently: true
|
|
|
|
})!;
|
|
|
|
|
2022-11-09 16:30:37 +00:00
|
|
|
const scale = resolution / Math.max(width, height);
|
2022-11-07 21:23:34 +00:00
|
|
|
ctx.scale(scale, scale);
|
|
|
|
|
|
|
|
let lastImg: HTMLImageElement | null = null;
|
|
|
|
for (const { left, top, width, height, disposeOp, img, delay } of frames) {
|
|
|
|
ctx.drawImage(img, left, top, width, height);
|
|
|
|
|
|
|
|
const { data } = ctx.getImageData(0, 0, resolution, resolution);
|
|
|
|
|
|
|
|
const palette = quantize(data, 256);
|
|
|
|
const index = applyPalette(data, palette);
|
|
|
|
|
|
|
|
gif.writeFrame(index, resolution, resolution, {
|
|
|
|
transparent: true,
|
|
|
|
palette,
|
|
|
|
delay,
|
|
|
|
});
|
|
|
|
|
2022-11-09 19:29:35 +00:00
|
|
|
if (disposeOp === ApngDisposeOp.BACKGROUND) {
|
|
|
|
ctx.clearRect(left, top, width, height);
|
|
|
|
} else if (disposeOp === ApngDisposeOp.PREVIOUS && lastImg) {
|
2022-11-07 21:23:34 +00:00
|
|
|
ctx.drawImage(lastImg, left, top, width, height);
|
|
|
|
}
|
2022-11-09 19:29:35 +00:00
|
|
|
|
2022-11-07 21:23:34 +00:00
|
|
|
lastImg = img;
|
2022-10-21 11:37:53 +00:00
|
|
|
}
|
|
|
|
|
2022-11-07 21:23:34 +00:00
|
|
|
gif.finish();
|
|
|
|
const file = new File([gif.bytesView()], `${stickerId}.gif`, { type: "image/gif" });
|
|
|
|
promptToUpload([file], ChannelStore.getChannel(channelId), DRAFT_TYPE);
|
|
|
|
},
|
|
|
|
|
|
|
|
start() {
|
2022-11-14 17:05:41 +00:00
|
|
|
const settings = Settings.plugins.FakeNitro;
|
2022-11-07 21:23:34 +00:00
|
|
|
if (!settings.enableEmojiBypass && !settings.enableStickerBypass) {
|
2022-10-01 15:04:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-08-31 18:53:36 +00:00
|
|
|
|
2022-11-28 12:37:55 +00:00
|
|
|
const EmojiStore = findByPropsLazy("getCustomEmojiById");
|
|
|
|
const StickerStore = findByPropsLazy("getAllGuildStickers") as {
|
2022-11-07 21:23:34 +00:00
|
|
|
getPremiumPacks(): StickerPack[];
|
|
|
|
getAllGuildStickers(): Map<string, Sticker[]>;
|
|
|
|
getStickerById(id: string): Sticker | undefined;
|
|
|
|
};
|
2022-08-31 18:53:36 +00:00
|
|
|
|
2022-11-07 21:23:34 +00:00
|
|
|
function getWordBoundary(origStr: string, offset: number) {
|
2022-10-02 20:12:48 +00:00
|
|
|
return (!origStr[offset] || /\s/.test(origStr[offset])) ? "" : " ";
|
|
|
|
}
|
|
|
|
|
2022-11-07 21:23:34 +00:00
|
|
|
this.preSend = addPreSendListener((channelId, messageObj, extra) => {
|
2022-10-08 18:36:57 +00:00
|
|
|
const { guildId } = this;
|
2022-10-01 15:04:57 +00:00
|
|
|
|
2022-11-12 15:25:28 +00:00
|
|
|
stickerBypass: {
|
|
|
|
if (!settings.enableStickerBypass)
|
|
|
|
break stickerBypass;
|
|
|
|
|
|
|
|
const sticker = StickerStore.getStickerById(extra?.stickerIds?.[0]!);
|
|
|
|
if (!sticker)
|
|
|
|
break stickerBypass;
|
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
if (sticker.available !== false && ((this.canUseStickers && this.hasPermissionToUseExternalStickers(channelId)) || (sticker as GuildSticker)?.guild_id === guildId))
|
2022-11-12 15:25:28 +00:00
|
|
|
break stickerBypass;
|
|
|
|
|
|
|
|
let link = this.getStickerLink(sticker.id);
|
|
|
|
if (sticker.format_type === 2) {
|
|
|
|
this.sendAnimatedSticker(this.getStickerLink(sticker.id), sticker.id, channelId);
|
|
|
|
return { cancel: true };
|
|
|
|
} else {
|
|
|
|
if ("pack_id" in sticker) {
|
|
|
|
const packId = sticker.pack_id === "847199849233514549"
|
|
|
|
// Discord moved these stickers into a different pack at some point, but
|
|
|
|
// Distok still uses the old id
|
|
|
|
? "749043879713701898"
|
|
|
|
: sticker.pack_id;
|
|
|
|
|
|
|
|
link = `https://distok.top/stickers/${packId}/${sticker.id}.gif`;
|
2022-11-07 21:23:34 +00:00
|
|
|
}
|
|
|
|
|
2022-11-12 15:25:28 +00:00
|
|
|
delete extra.stickerIds;
|
|
|
|
messageObj.content += " " + link;
|
2022-11-07 21:23:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
if ((!this.canUseEmotes || !this.hasPermissionToUseExternalEmojis(channelId)) && settings.enableEmojiBypass) {
|
2022-11-07 21:23:34 +00:00
|
|
|
for (const emoji of messageObj.validNonShortcutEmojis) {
|
|
|
|
if (!emoji.require_colons) continue;
|
|
|
|
if (emoji.guildId === guildId && !emoji.animated) continue;
|
2022-08-31 18:53:36 +00:00
|
|
|
|
2022-11-07 21:23:34 +00:00
|
|
|
const emojiString = `<${emoji.animated ? "a" : ""}:${emoji.originalName || emoji.name}:${emoji.id}>`;
|
2022-11-21 02:43:16 +00:00
|
|
|
const url = emoji.url.replace(/\?size=\d+/, `?size=${Settings.plugins.FakeNitro.emojiSize}`);
|
2022-11-07 21:23:34 +00:00
|
|
|
messageObj.content = messageObj.content.replace(emojiString, (match, offset, origStr) => {
|
|
|
|
return `${getWordBoundary(origStr, offset - 1)}${url}${getWordBoundary(origStr, offset + match.length)}`;
|
|
|
|
});
|
|
|
|
}
|
2022-08-31 18:53:36 +00:00
|
|
|
}
|
2022-11-07 21:23:34 +00:00
|
|
|
|
|
|
|
return { cancel: false };
|
2022-08-31 18:55:58 +00:00
|
|
|
});
|
2022-11-07 21:23:34 +00:00
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
this.preEdit = addPreEditListener((channelId, __, messageObj) => {
|
|
|
|
if (this.canUseEmotes && this.hasPermissionToUseExternalEmojis(channelId)) return;
|
2022-11-07 21:23:34 +00:00
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
const { guildId } = this;
|
2022-11-07 21:23:34 +00:00
|
|
|
|
2023-02-18 02:32:02 +00:00
|
|
|
for (const [emojiStr, _, emojiId] of messageObj.content.matchAll(/(?<!\\)<a?:(\w+):(\d+)>/ig)) {
|
|
|
|
const emoji = EmojiStore.getCustomEmojiById(emojiId);
|
|
|
|
if (emoji == null || (emoji.guildId === guildId && !emoji.animated)) continue;
|
|
|
|
if (!emoji.require_colons) continue;
|
|
|
|
|
|
|
|
const url = emoji.url.replace(/\?size=\d+/, `?size=${Settings.plugins.FakeNitro.emojiSize}`);
|
|
|
|
messageObj.content = messageObj.content.replace(emojiStr, (match, offset, origStr) => {
|
|
|
|
return `${getWordBoundary(origStr, offset - 1)}${url}${getWordBoundary(origStr, offset + match.length)}`;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2022-08-31 18:53:36 +00:00
|
|
|
},
|
2022-08-31 20:08:05 +00:00
|
|
|
|
|
|
|
stop() {
|
|
|
|
removePreSendListener(this.preSend);
|
|
|
|
removePreEditListener(this.preEdit);
|
|
|
|
}
|
2022-08-31 18:55:58 +00:00
|
|
|
});
|