Plugin
ReverseImageSearch
Adds ImageSearch to image context menus
1
/*2
* FiveCord — a Discord client mod3
* Copyright (c) 2025 FiveCord4
* SPDX-License-Identifier: GPL-3.0-or-later5
*/6
7
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";8
import { Flex } from "@components/Flex";9
import { OpenExternalIcon } from "@components/Icons";10
import { Devs } from "@utils/constants";11
import definePlugin from "@utils/types";12
import { Menu } from "@webpack/common";13
14
const Engines = {15
Google: "https:class="ts-cmt">//lens.google.com/uploadbyurl?url=",16
Yandex: "https:class="ts-cmt">//yandex.com/images/search?rpt=imageview&url=",17
SauceNAO: "https:class="ts-cmt">//saucenao.com/search.php?url=",18
IQDB: "https:class="ts-cmt">//iqdb.org/?url=",19
Bing: "https:class="ts-cmt">//www.bing.com/images/search?view=detailv2&iss=sbi&q=imgurl:",20
TinEye: "https:class="ts-cmt">//www.tineye.com/search?url=",21
ImgOps: "https:class="ts-cmt">//imgops.com/start?url="22
} as const;23
24
function search(src: string, engine: string) {25
open(engine + encodeURIComponent(src), "_blank");26
}27
28
function makeSearchItem(src: string) {29
return (30
<Menu.MenuItem31
label="Search Image"32
key="search-image"33
id="search-image"34
>35
{Object.keys(Engines).map((engine, i) => {36
const key = "search-image-" + engine;37
return (38
<Menu.MenuItem39
key={key}40
id={key}41
label={42
<Flex alignItems="center" gap="0.5em">43
<img44
style={{45
borderRadius: "50%",46
}}47
aria-hidden="true"48
height={16}49
width={16}50
src={`https:class="ts-cmt">//icons.duckduckgo.com/ip3/${new URL(Engines[engine]).host}.ico`}51
/>52
{engine}53
</Flex>54
}55
action={() => search(src, Engines[engine])}56
/>57
);58
})}59
<Menu.MenuItem60
key="search-image-all"61
id="search-image-all"62
label={63
<Flex alignItems="center" gap="0.5em">64
<OpenExternalIcon height={16} width={16} />65
All66
</Flex>67
}68
action={() => Object.values(Engines).forEach(e => search(src, e))}69
/>70
</Menu.MenuItem>71
);72
}73
74
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {75
if (props?.reverseImageSearchType !== "img") return;76
77
const src = props.itemHref ?? props.itemSrc;78
79
const group = findGroupChildrenByChildId("copy-link", children);80
group?.push(makeSearchItem(src));81
};82
83
const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {84
if (!props?.src) return;85
86
const group = findGroupChildrenByChildId("copy-native-link", children) ?? children;87
group.push(makeSearchItem(props.src));88
};89
90
export default definePlugin({91
name: "ReverseImageSearch",92
description: "Adds ImageSearch to image context menus",93
tags: ["Media", "Utility"],94
authors: [Devs.Ven, Devs.Nuckyz],95
searchTerms: ["ImageUtilities"],96
97
patches: [98
{99
find: "#{intl::MESSAGE_ACTIONS_MENU_LABEL}),shouldHideMediaOptions:",100
replacement: {101
match: /favoriteableType:\i,(?<=(\i)\.getAttribute\("data-type"\).+?)/,102
replace: (m, target) => `${m}reverseImageSearchType:${target}.getAttribute("data-role"),`103
}104
}105
],106
contextMenus: {107
"message": messageContextMenuPatch,108
"image-context": imageContextMenuPatch109
}110
});111