mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-02-24 23:38:32 +00:00
159 lines
5.9 KiB
TypeScript
159 lines
5.9 KiB
TypeScript
/*
|
|
* Vencord, a modification for Discord's desktop app
|
|
* Copyright (c) 2023 Vendicated and contributors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import { definePluginSettings } from "@api/Settings";
|
|
import { Devs } from "@utils/constants";
|
|
import definePlugin, { OptionType, PluginNative, SettingsDefinition } from "@utils/types";
|
|
import { showToast, Toasts } from "@webpack/common";
|
|
import type { MouseEvent } from "react";
|
|
|
|
interface URLReplacementRule {
|
|
match: RegExp;
|
|
replace: (...matches: string[]) => string;
|
|
description: string;
|
|
shortlinkMatch?: RegExp;
|
|
accountViewReplace?: (userId: string) => string;
|
|
}
|
|
|
|
// Do not forget to add protocols to the ALLOWED_PROTOCOLS constant
|
|
const UrlReplacementRules: Record<string, URLReplacementRule> = {
|
|
spotify: {
|
|
match: /^https:\/\/open\.spotify\.com\/(?:intl-[a-z]{2}\/)?(track|album|artist|playlist|user|episode|prerelease)\/(.+)(?:\?.+?)?$/,
|
|
replace: (_, type, id) => `spotify://${type}/${id}`,
|
|
description: "Open Spotify links in the Spotify app",
|
|
shortlinkMatch: /^https:\/\/spotify\.link\/.+$/,
|
|
accountViewReplace: userId => `spotify:user:${userId}`,
|
|
},
|
|
steam: {
|
|
match: /^https:\/\/(steamcommunity\.com|(?:help|store)\.steampowered\.com)\/.+$/,
|
|
replace: match => `steam://openurl/${match}`,
|
|
description: "Open Steam links in the Steam app",
|
|
shortlinkMatch: /^https:\/\/s.team\/.+$/,
|
|
accountViewReplace: userId => `steam://openurl/https://steamcommunity.com/profiles/${userId}`,
|
|
},
|
|
epic: {
|
|
match: /^https:\/\/store\.epicgames\.com\/(.+)$/,
|
|
replace: (_, id) => `com.epicgames.launcher://store/${id}`,
|
|
description: "Open Epic Games links in the Epic Games Launcher",
|
|
},
|
|
tidal: {
|
|
match: /^https:\/\/tidal\.com\/browse\/(track|album|artist|playlist|user|video|mix)\/(.+)(?:\?.+?)?$/,
|
|
replace: (_, type, id) => `tidal://${type}/${id}`,
|
|
description: "Open Tidal links in the Tidal app",
|
|
},
|
|
itunes: {
|
|
match: /^https:\/\/(?:geo\.)?music\.apple\.com\/([a-z]{2}\/)?(album|artist|playlist|song|curator)\/([^/?#]+)\/?([^/?#]+)?(?:\?.*)?(?:#.*)?$/,
|
|
replace: (_, lang, type, name, id) => id ? `itunes://music.apple.com/us/${type}/${name}/${id}` : `itunes://music.apple.com/us/${type}/${name}`,
|
|
description: "Open Apple Music links in the iTunes app"
|
|
},
|
|
};
|
|
|
|
const pluginSettings = definePluginSettings(
|
|
Object.entries(UrlReplacementRules).reduce((acc, [key, rule]) => {
|
|
acc[key] = {
|
|
type: OptionType.BOOLEAN,
|
|
description: rule.description,
|
|
default: true,
|
|
};
|
|
return acc;
|
|
}, {} as SettingsDefinition)
|
|
);
|
|
|
|
|
|
const Native = VencordNative.pluginHelpers.OpenInApp as PluginNative<typeof import("./native")>;
|
|
|
|
export default definePlugin({
|
|
name: "OpenInApp",
|
|
description: "Open links in their respective apps instead of your browser",
|
|
authors: [Devs.Ven, Devs.surgedevs],
|
|
settings: pluginSettings,
|
|
|
|
patches: [
|
|
{
|
|
find: "trackAnnouncementMessageLinkClicked({",
|
|
replacement: {
|
|
match: /function (\i\(\i,\i\)\{)(?=.{0,150}trusted:)/,
|
|
replace: "async function $1 if(await $self.handleLink(...arguments)) return;"
|
|
}
|
|
},
|
|
{
|
|
find: "no artist ids in metadata",
|
|
predicate: () => !IS_DISCORD_DESKTOP && pluginSettings.store.spotify,
|
|
replacement: [
|
|
{
|
|
match: /\i\.\i\.isProtocolRegistered\(\)/g,
|
|
replace: "true"
|
|
},
|
|
{
|
|
match: /!\(0,\i\.isDesktop\)\(\)/,
|
|
replace: "false"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
find: ".CONNECTED_ACCOUNT_VIEWED,",
|
|
replacement: {
|
|
match: /(?<=href:\i,onClick:(\i)=>\{)(?=.{0,10}\i=(\i)\.type,.{0,100}CONNECTED_ACCOUNT_VIEWED)/,
|
|
replace: "if($self.handleAccountView($1,$2.type,$2.id)) return;"
|
|
}
|
|
}
|
|
],
|
|
|
|
async handleLink(data: { href: string; }, event?: MouseEvent) {
|
|
if (!data) return false;
|
|
|
|
let url = data.href;
|
|
if (!url) return false;
|
|
|
|
for (const [key, rule] of Object.entries(UrlReplacementRules)) {
|
|
if (!pluginSettings.store[key]) continue;
|
|
|
|
if (rule.shortlinkMatch?.test(url)) {
|
|
event?.preventDefault();
|
|
url = await Native.resolveRedirect(url);
|
|
}
|
|
|
|
if (rule.match.test(url)) {
|
|
showToast("Opened link in native app", Toasts.Type.SUCCESS);
|
|
|
|
const newUrl = url.replace(rule.match, rule.replace);
|
|
VencordNative.native.openExternal(newUrl);
|
|
|
|
event?.preventDefault();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// in case short url didn't end up being something we can handle
|
|
if (event?.defaultPrevented) {
|
|
window.open(url, "_blank");
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
handleAccountView(e: MouseEvent, platformType: string, userId: string) {
|
|
const rule = UrlReplacementRules[platformType];
|
|
if (rule?.accountViewReplace && pluginSettings.store[platformType]) {
|
|
VencordNative.native.openExternal(rule.accountViewReplace(userId));
|
|
e.preventDefault();
|
|
return true;
|
|
}
|
|
}
|
|
});
|