/* * 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 . */ import { NavContextMenuPatchCallback } from "@api/ContextMenu"; import { addButton, removeButton } from "@api/MessagePopover"; import { definePluginSettings } from "@api/Settings"; import { CodeBlock } from "@components/CodeBlock"; import ErrorBoundary from "@components/ErrorBoundary"; import { Flex } from "@components/Flex"; import { Devs } from "@utils/constants"; import { Margins } from "@utils/margins"; import { copyWithToast } from "@utils/misc"; import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal"; import definePlugin, { OptionType } from "@utils/types"; import { Button, ChannelStore, Forms, i18n, Menu, Text } from "@webpack/common"; import { Message } from "discord-types/general"; const CopyIcon = () => { return ; }; function sortObject(obj: T): T { return Object.fromEntries(Object.entries(obj).sort(([k1], [k2]) => k1.localeCompare(k2))) as T; } function cleanMessage(msg: Message) { const clone = sortObject(JSON.parse(JSON.stringify(msg))); for (const key of [ "email", "phone", "mfaEnabled", "personalConnectionId" ]) delete clone.author[key]; // message logger added properties const cloneAny = clone as any; delete cloneAny.editHistory; delete cloneAny.deleted; cloneAny.attachments?.forEach(a => delete a.deleted); return clone; } function openViewRawModal(json: string, type: string, msgContent?: string) { const key = openModal(props => ( View Raw closeModal(key)} />
{!!msgContent && ( <> Content )} {type} Data
{!!msgContent && ( )}
)); } function openViewRawModalMessage(msg: Message) { msg = cleanMessage(msg); const msgJson = JSON.stringify(msg, null, 4); return openViewRawModal(msgJson, "Message", msg.content); } const settings = definePluginSettings({ clickMethod: { description: "Change the button to view the raw content/data of any message.", type: OptionType.SELECT, options: [ { label: "Left Click to view the raw content.", value: "Left", default: true }, { label: "Right click to view the raw content.", value: "Right" } ] } }); function MakeContextCallback(name: "Guild" | "User" | "Channel"): NavContextMenuPatchCallback { return (children, props) => { const value = props[name.toLowerCase()]; if (!value) return; if (props.label === i18n.Messages.CHANNEL_ACTIONS_MENU_LABEL) return; // random shit like notification settings const lastChild = children.at(-1); if (lastChild?.key === "developer-actions") { const p = lastChild.props; if (!Array.isArray(p.children)) p.children = [p.children]; children = p.children; } children.splice(-1, 0, openViewRawModal(JSON.stringify(value, null, 4), name)} icon={CopyIcon} /> ); }; } export default definePlugin({ name: "ViewRaw", description: "Copy and view the raw content/data of any message, channel or guild", authors: [Devs.KingFish, Devs.Ven, Devs.rad, Devs.ImLvna], dependencies: ["MessagePopoverAPI"], settings, contextMenus: { "guild-context": MakeContextCallback("Guild"), "channel-context": MakeContextCallback("Channel"), "user-context": MakeContextCallback("User") }, start() { addButton("ViewRaw", msg => { const handleClick = () => { if (settings.store.clickMethod === "Right") { copyWithToast(msg.content); } else { openViewRawModalMessage(msg); } }; const handleContextMenu = e => { if (settings.store.clickMethod === "Left") { e.preventDefault(); e.stopPropagation(); copyWithToast(msg.content); } else { e.preventDefault(); e.stopPropagation(); openViewRawModalMessage(msg); } }; const label = settings.store.clickMethod === "Right" ? "Copy Raw (Left Click) / View Raw (Right Click)" : "View Raw (Left Click) / Copy Raw (Right Click)"; return { label, icon: CopyIcon, message: msg, channel: ChannelStore.getChannel(msg.channel_id), onClick: handleClick, onContextMenu: handleContextMenu }; }); }, stop() { removeButton("ViewRaw"); } });