diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/dearrow/README.md | 5 | ||||
-rw-r--r-- | src/plugins/dearrow/index.tsx | 155 | ||||
-rw-r--r-- | src/plugins/dearrow/styles.css | 12 |
3 files changed, 172 insertions, 0 deletions
diff --git a/src/plugins/dearrow/README.md b/src/plugins/dearrow/README.md new file mode 100644 index 0000000..81a762c --- /dev/null +++ b/src/plugins/dearrow/README.md @@ -0,0 +1,5 @@ +# Dearrow + +Makes YouTube embed titles and thumbnails less sensationalist, powered by [Dearrow](https://dearrow.ajay.app/) + +https://github.com/Vendicated/Vencord/assets/45497981/7bf81108-102d-47c5-8ba5-357db4db1283 diff --git a/src/plugins/dearrow/index.tsx b/src/plugins/dearrow/index.tsx new file mode 100644 index 0000000..7e50bca --- /dev/null +++ b/src/plugins/dearrow/index.tsx @@ -0,0 +1,155 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import "./styles.css"; + +import ErrorBoundary from "@components/ErrorBoundary"; +import { Devs } from "@utils/constants"; +import { Logger } from "@utils/Logger"; +import definePlugin from "@utils/types"; +import { Tooltip } from "@webpack/common"; +import type { Component } from "react"; + +interface Props { + embed: { + rawTitle: string; + provider?: { + name: string; + }; + thumbnail: { + proxyURL: string; + }; + video: { + url: string; + }; + + dearrow: { + enabled: boolean; + oldTitle?: string; + oldThumb?: string; + }; + }; +} + +const embedUrlRe = /https:\/\/www\.youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/; + +async function embedDidMount(this: Component<Props>) { + try { + const { embed } = this.props; + if (!embed || embed.dearrow || embed.provider?.name !== "YouTube" || !embed.video?.url) return; + + const videoId = embedUrlRe.exec(embed.video.url)?.[1]; + if (!videoId) return; + + const res = await fetch(`https://sponsor.ajay.app/api/branding?videoID=${videoId}`); + if (!res.ok) return; + + const { titles, thumbnails } = await res.json(); + + const hasTitle = titles[0]?.votes >= 0; + const hasThumb = thumbnails[0]?.votes >= 0; + + if (!hasTitle && !hasThumb) return; + + embed.dearrow = { + enabled: true + }; + + if (titles[0]?.votes >= 0) { + embed.dearrow.oldTitle = embed.rawTitle; + embed.rawTitle = titles[0].title; + } + + if (thumbnails[0]?.votes >= 0) { + embed.dearrow.oldThumb = embed.thumbnail.proxyURL; + embed.thumbnail.proxyURL = `https://dearrow-thumb.ajay.app/api/v1/getThumbnail?videoID=${videoId}&time=${thumbnails[0].timestamp}`; + } + + this.forceUpdate(); + } catch (err) { + new Logger("Dearrow").error("Failed to dearrow embed", err); + } +} + +function renderButton(this: Component<Props>) { + const { embed } = this.props; + if (!embed?.dearrow) return null; + + return ( + <Tooltip text={embed.dearrow.enabled ? "This embed has been dearrowed, click to restore" : "Click to dearrow"}> + {({ onMouseEnter, onMouseLeave }) => ( + <button + onMouseEnter={onMouseEnter} + onMouseLeave={onMouseLeave} + className={"vc-dearrow-toggle-" + (embed.dearrow.enabled ? "on" : "off")} + onClick={() => { + const { enabled, oldThumb, oldTitle } = embed.dearrow; + embed.dearrow.enabled = !enabled; + if (oldTitle) { + embed.dearrow.oldTitle = embed.rawTitle; + embed.rawTitle = oldTitle; + } + if (oldThumb) { + embed.dearrow.oldThumb = embed.thumbnail.proxyURL; + embed.thumbnail.proxyURL = oldThumb; + } + + this.forceUpdate(); + }} + > + {/* Dearrow Icon, taken from https://dearrow.ajay.app/logo.svg (and optimised) */} + <svg + xmlns="http://www.w3.org/2000/svg" + width="24px" + height="24px" + viewBox="0 0 36 36" + aria-label="Toggle Dearrow" + > + <path + fill="#1213BD" + d="M36 18.302c0 4.981-2.46 9.198-5.655 12.462s-7.323 5.152-12.199 5.152s-9.764-1.112-12.959-4.376S0 23.283 0 18.302s2.574-9.38 5.769-12.644S13.271 0 18.146 0s9.394 2.178 12.589 5.442C33.931 8.706 36 13.322 36 18.302z" + /> + <path + fill="#88c9f9" + d="m 30.394282,18.410186 c 0,3.468849 -1.143025,6.865475 -3.416513,9.137917 -2.273489,2.272442 -5.670115,2.92874 -9.137918,2.92874 -3.467803,0 -6.373515,-1.147212 -8.6470033,-3.419654 -2.2734888,-2.272442 -3.5871299,-5.178154 -3.5871299,-8.647003 0,-3.46885 0.9420533,-6.746149 3.2144954,-9.0196379 2.2724418,-2.2734888 5.5507878,-3.9513905 9.0196378,-3.9513905 3.46885,0 6.492841,1.9322561 8.76633,4.204698 2.273489,2.2724424 3.788101,5.2974804 3.788101,8.7663304 z" + /> + <path + fill="#0a62a5" + d="m 23.95823,17.818306 c 0,3.153748 -2.644888,5.808102 -5.798635,5.808102 -3.153748,0 -5.599825,-2.654354 -5.599825,-5.808102 0,-3.153747 2.446077,-5.721714 5.599825,-5.721714 3.153747,0 5.798635,2.567967 5.798635,5.721714 z" + /> + </svg> + + </button> + )} + </Tooltip> + ); +} + +export default definePlugin({ + name: "Dearrow", + description: "Makes YouTube embed titles and thumbnails less sensationalist, powered by Dearrow", + authors: [Devs.Ven], + + embedDidMount, + renderButton: ErrorBoundary.wrap(renderButton, { noop: true }), + + patches: [{ + find: "this.renderInlineMediaEmbed", + replacement: [ + // patch componentDidMount to replace embed thumbnail and title + { + match: /(\i).render=function.{0,50}\i\.embed/, + replace: "$1.componentDidMount=$self.embedDidMount,$&" + }, + + // add dearrow button + { + match: /children:\[(?=null!=\i\?\i\.renderSuppressButton)/, + replace: "children:[$self.renderButton.call(this)," + } + ] + }], +}); diff --git a/src/plugins/dearrow/styles.css b/src/plugins/dearrow/styles.css new file mode 100644 index 0000000..fc7e9e3 --- /dev/null +++ b/src/plugins/dearrow/styles.css @@ -0,0 +1,12 @@ +.vc-dearrow-toggle-off svg { + filter: grayscale(1); +} + +.vc-dearrow-toggle-on, .vc-dearrow-toggle-off { + all: unset; + display: inline; + cursor: pointer; + position: absolute; + top: 0.75rem; + right: 0.75rem; +} |