aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/dearrow/README.md5
-rw-r--r--src/plugins/dearrow/index.tsx155
-rw-r--r--src/plugins/dearrow/styles.css12
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;
+}