aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/dearrow/index.tsx
blob: 7e50bcae796a0150739bb8ce44c46e493a3dbf7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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),"
            }
        ]
    }],
});