diff --git a/src/plugins/dearrow/README.md b/src/plugins/dearrow/README.md new file mode 100644 index 000000000..81a762c70 --- /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 000000000..7e50bcae7 --- /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) { + 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) { + const { embed } = this.props; + if (!embed?.dearrow) return null; + + return ( + + {({ onMouseEnter, onMouseLeave }) => ( + + )} + + ); +} + +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 000000000..fc7e9e320 --- /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; +}