mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-19 11:27:02 -04:00
Merge remote-tracking branch 'upstream/dev'
This commit is contained in:
commit
68343dc8e2
20 changed files with 669 additions and 86 deletions
|
@ -23,12 +23,11 @@ import "./settings";
|
|||
import { debounce } from "@shared/debounce";
|
||||
import { IpcEvents } from "@shared/IpcEvents";
|
||||
import { BrowserWindow, ipcMain, shell, systemPreferences } from "electron";
|
||||
import monacoHtml from "file://monacoWin.html?minify&base64";
|
||||
import { FSWatcher, mkdirSync, watch, writeFileSync } from "fs";
|
||||
import { open, readdir, readFile } from "fs/promises";
|
||||
import { join, normalize } from "path";
|
||||
|
||||
import monacoHtml from "~fileContent/monacoWin.html;base64";
|
||||
|
||||
import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, THEMES_DIR } from "./utils/constants";
|
||||
import { makeLinksOpenExternally } from "./utils/externalLinks";
|
||||
|
||||
|
|
2
src/modules.d.ts
vendored
2
src/modules.d.ts
vendored
|
@ -38,7 +38,7 @@ declare module "~git-remote" {
|
|||
export default remote;
|
||||
}
|
||||
|
||||
declare module "~fileContent/*" {
|
||||
declare module "file://*" {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
|
|
@ -182,8 +182,8 @@ export default definePlugin({
|
|||
|
||||
// add dearrow button
|
||||
{
|
||||
match: /children:\[(?=null!=\i\?\i\.renderSuppressButton)/,
|
||||
replace: "children:[$self.renderButton(this),",
|
||||
match: /children:\[(?=null!=\i\?(\i)\.renderSuppressButton)/,
|
||||
replace: "children:[$self.renderButton($1),",
|
||||
predicate: () => !settings.store.hideButton
|
||||
}
|
||||
]
|
||||
|
|
35
src/plugins/dontRoundMyTimestamps/index.ts
Normal file
35
src/plugins/dontRoundMyTimestamps/index.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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 { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { moment } from "@webpack/common";
|
||||
|
||||
export default definePlugin({
|
||||
name: "DontRoundMyTimestamps",
|
||||
authors: [Devs.Lexi],
|
||||
description: "Always rounds relative timestamps down, so 7.6y becomes 7y instead of 8y",
|
||||
|
||||
start() {
|
||||
moment.relativeTimeRounding(Math.floor);
|
||||
},
|
||||
|
||||
stop() {
|
||||
moment.relativeTimeRounding(Math.round);
|
||||
}
|
||||
});
|
|
@ -67,15 +67,18 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
|||
}
|
||||
};
|
||||
const syncVideos = () => {
|
||||
currentVideoElementRef.current!.currentTime = originalVideoElementRef.current!.currentTime;
|
||||
if (currentVideoElementRef.current && originalVideoElementRef.current)
|
||||
currentVideoElementRef.current.currentTime = originalVideoElementRef.current.currentTime;
|
||||
};
|
||||
|
||||
const updateMousePosition = (e: MouseEvent) => {
|
||||
if (!element.current) return;
|
||||
|
||||
if (instance.state.mouseOver && instance.state.mouseDown) {
|
||||
const offset = size.current / 2;
|
||||
const pos = { x: e.pageX, y: e.pageY };
|
||||
const x = -((pos.x - element.current!.getBoundingClientRect().left) * zoom.current - offset);
|
||||
const y = -((pos.y - element.current!.getBoundingClientRect().top) * zoom.current - offset);
|
||||
const x = -((pos.x - element.current.getBoundingClientRect().left) * zoom.current - offset);
|
||||
const y = -((pos.y - element.current.getBoundingClientRect().top) * zoom.current - offset);
|
||||
setLensPosition({ x: e.x - offset, y: e.y - offset });
|
||||
setImagePosition({ x, y });
|
||||
setOpacity(1);
|
||||
|
@ -184,6 +187,7 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
|
|||
src={originalVideoElementRef.current?.src ?? instance.props.src}
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
|
|
|
@ -18,88 +18,82 @@
|
|||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import presetQuotesText from "file://quotes.txt";
|
||||
|
||||
// These are Xor encrypted to prevent you from spoiling yourself when you read the source code.
|
||||
// don't worry about it :P
|
||||
const quotes = [
|
||||
"Eyrokac",
|
||||
"Rdcg$l`'k|~n",
|
||||
'H`tf$d&iajo+d`{"',
|
||||
"Sucqplh`(Eclhualva()&",
|
||||
"Lncgmka'8KNMDC,shpanf'`x./,",
|
||||
"Ioqweijnfn*IeuvfvAotkfxo./,",
|
||||
'Hd{#cp\x7Ft$)nbd!{lq%mig~*\x7Fh`v#mk&sm{gx nd#idjb(a\x7Ffao"bja&amdkge!Rloìkhf)hyedfjjb*\'^hzdrdmm$lu\'|ao+mnqw$fijxh~bbmg#Tjmîefd+fnp#lpkffz5',
|
||||
"h",
|
||||
"sijklm&cam*rot\"hjjq'|ak\x7F xmv#wc'ep*mawmvvlrb(|ynr>\"Aqq&cgg-\x7F ugoh%rom)e\x7Fhdpp%$",
|
||||
'Tnfb}"u\'~`nno!kp$vvhfzeyee"a}%Tfam*Xh`fls%Jboldos-"lj`&hn)~ce!`jcbct|)gdbhnf$wikm$zgaxkmc%afely+og"144?\'ign+iu%p$qisiefr gpfa$',
|
||||
"Ndtfv%ahfgk+ghtf$|ir(|z' Oguaw&`ggdj mgw$|ir(me|n",
|
||||
"(!ͣ³$͙ʐ'ͩ¹#",
|
||||
"(ネ◗ロ◑,マ-2ャユ✬",
|
||||
"Ynw#hjil(ze+psgwp|&sgmkr!",
|
||||
"Tikmolh`(fl+a!dvjk\x7F'y|e\x7Fe/,-",
|
||||
"3/3750?5><9>885:7",
|
||||
"mdmt",
|
||||
"Wdn`khc+(oxbeof",
|
||||
'Ig"zkp*\'g{*xolglj`&~g|*gowg/$mgt(Eclm`.#ticf{l*xed"wl`&Kangj igbhqn\'d`dn `v#lqrw{3%$bhv-h|)kangj_imwhlhb',
|
||||
"Tscmw%Tnoa~x",
|
||||
"I‘f#npus(ec`e!vl$lhsm{`ncu\"ekw&f(defeov-$Rnf|)sdu‘pf$wcam{ceg!vl$du'D`d~x-\"jw%oi(okht-\"DJP)Kags,!mq$du'A‐|n sg`akrkq)~jkdl#pj&diefbnf\"jp)&@F\\*{ltq#Hlhrp'",
|
||||
"Ynw$v`&cg`dl fml`%rhlhs*",
|
||||
"Dnl$p%qhz{s' hv$w%hh|aceg!;#gpvt(fl+cndea`&dg|fon&v#wjjqm(",
|
||||
"\ud83d)pft`gs(ec`e!13$qojmz#",
|
||||
"a!njcmr'ide~nu\"lb%rheoedldpz$lu'gbkr",
|
||||
"dn\"zkp&kgo4",
|
||||
"hnpqkw",
|
||||
"sn\"fau",
|
||||
"Sn\"tmqnh}}*musvkaw&flf&+ldv$w%lr{}*aulr#vlao|)cetn\"jp$",
|
||||
"Dxkmc%ot(hhxomwwai'{hln",
|
||||
"hd{#}js&(pe~'sg#gprb(3#\"",
|
||||
"hd{b${",
|
||||
"<;vqkijbq33271:56<3799?24944:",
|
||||
"Thof$lu'ofdn,!qsefc'az*bnrcma+&Om{o+iu\"`khct$)bnrd\"bcdoi&",
|
||||
"snofplkb{)c'r\"lod'|f*aurv#cpno`abchijklmno",
|
||||
"Wdn`khc'|f*eghl{%"
|
||||
];
|
||||
const presetQuotes = presetQuotesText.split("\n").map(quote => /^\s*[^#\s]/.test(quote) && quote.trim()).filter(Boolean) as string[];
|
||||
const noQuotesQuote = "Did you really disable all loading quotes? What a buffoon you are...";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
replaceEvents: {
|
||||
description: "Replace Event Quotes too",
|
||||
description: "Should this plugin also apply during events with special event themed quotes? (e.g. Halloween)",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
enablePluginPresetQuotes: {
|
||||
description: "Enable the quotes preset by this plugin",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: true
|
||||
},
|
||||
enableDiscordPresetQuotes: {
|
||||
description: "Enable Discord's preset quotes (including event quotes, during events)",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false
|
||||
},
|
||||
additionalQuotes: {
|
||||
description: "Additional custom quotes to possibly appear, separated by the below delimiter",
|
||||
type: OptionType.STRING,
|
||||
default: "",
|
||||
},
|
||||
additionalQuotesDelimiter: {
|
||||
description: "Delimiter for additional quotes",
|
||||
type: OptionType.STRING,
|
||||
default: "|",
|
||||
},
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "LoadingQuotes",
|
||||
description: "Replace Discords loading quotes",
|
||||
authors: [Devs.Ven, Devs.KraXen72],
|
||||
authors: [Devs.Ven, Devs.KraXen72, Devs.UlyssesZhan],
|
||||
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: ".LOADING_DID_YOU_KNOW}",
|
||||
find: ".LOADING_DID_YOU_KNOW",
|
||||
replacement: [
|
||||
{
|
||||
match: /"_loadingText",function\(\)\{/,
|
||||
replace: "$&return $self.quote;",
|
||||
match: /"_loadingText".+?(?=(\i)\[.{0,10}\.random)/,
|
||||
replace: "$&$self.mutateQuotes($1),"
|
||||
},
|
||||
{
|
||||
match: /"_eventLoadingText",function\(\)\{/,
|
||||
replace: "$&return $self.quote;",
|
||||
match: /"_eventLoadingText".+?(?=(\i)\[.{0,10}\.random)/,
|
||||
replace: "$&$self.mutateQuotes($1),",
|
||||
predicate: () => settings.store.replaceEvents
|
||||
}
|
||||
],
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
xor(quote: string) {
|
||||
const key = "read if cute";
|
||||
const codes = Array.from(quote, (s, i) => s.charCodeAt(0) ^ (i % key.length));
|
||||
return String.fromCharCode(...codes);
|
||||
},
|
||||
mutateQuotes(quotes: string[]) {
|
||||
try {
|
||||
const { enableDiscordPresetQuotes, additionalQuotes, additionalQuotesDelimiter, enablePluginPresetQuotes } = settings.store;
|
||||
|
||||
get quote() {
|
||||
return this.xor(quotes[Math.floor(Math.random() * quotes.length)]);
|
||||
if (!enableDiscordPresetQuotes)
|
||||
quotes.length = 0;
|
||||
|
||||
|
||||
if (enablePluginPresetQuotes)
|
||||
quotes.push(...presetQuotes);
|
||||
|
||||
quotes.push(...additionalQuotes.split(additionalQuotesDelimiter).filter(Boolean));
|
||||
|
||||
if (!quotes.length)
|
||||
quotes.push(noQuotesQuote);
|
||||
} catch (e) {
|
||||
new Logger("LoadingQuotes").error("Failed to mutate quotes", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
37
src/plugins/loadingQuotes/quotes.txt
Normal file
37
src/plugins/loadingQuotes/quotes.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Blank lines and lines starting with "#" are ignored
|
||||
|
||||
Explode
|
||||
Read if cute
|
||||
Have a nice day!
|
||||
Starting Lightcord...
|
||||
Loading 0BDFDB.plugin.js...
|
||||
Installing BetterDiscord...
|
||||
h
|
||||
shhhhh did you know that you're my favourite user? But don't tell the others!!
|
||||
Today's video is sponsored by Raid Shadow Legends, one of the biggest mobile role-playing games of 2019 and it's totally free!
|
||||
Never gonna give you up, Never gonna let you down
|
||||
( ͡° ͜ʖ ͡°)
|
||||
(ノ◕ヮ◕)ノ*:・゚✧
|
||||
You look so pretty today!
|
||||
Thinking of a funny quote...
|
||||
3.141592653589793
|
||||
meow
|
||||
Welcome, friend
|
||||
If you, or someone you love, has Ligma, please see the Ligma health line at https://bit.ly/ligma_hotline
|
||||
Trans Rights
|
||||
I’d just like to interject for a moment. What you’re refering to as Linux, is in fact, GNU/Linux, or as I’ve recently taken to calling it, GNU plus Linux.
|
||||
You're doing good today!
|
||||
Don't worry, it's nothing 9 cups of coffee couldn't solve!
|
||||
<EFBFBD>(repeat like 30 times)
|
||||
a light amount of tomfoolery is okay
|
||||
do you love?
|
||||
horror
|
||||
so eepy
|
||||
So without further ado, let's just jump right into it!
|
||||
Dying is absolutely safe
|
||||
hey you! you're cute :))
|
||||
heya ~
|
||||
<:trolley:997086295010594867>
|
||||
Time is gone, space is insane. Here it comes, here again.
|
||||
sometimes it's okay to just guhhhhhhhhhhhhhh
|
||||
Welcome to nginx!
|
36
src/plugins/maskedLinkPaste/index.ts
Normal file
36
src/plugins/maskedLinkPaste/index.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants.js";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
||||
const linkRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
|
||||
|
||||
const { SlateTransforms } = findByPropsLazy("SlateTransforms");
|
||||
|
||||
export default definePlugin({
|
||||
name: "MaskedLinkPaste",
|
||||
authors: [Devs.TheSun],
|
||||
description: "Pasting a link while having text selected will paste a hyperlink",
|
||||
patches: [{
|
||||
find: ".selection,preventEmojiSurrogates:",
|
||||
replacement: {
|
||||
match: /(?<=SlateTransforms.delete.{0,50})(\i)\.insertText\((\i)\)/,
|
||||
replace: "$self.handlePaste($1, $2, () => $&)"
|
||||
}
|
||||
}],
|
||||
|
||||
handlePaste(editor, content: string, originalBehavior: () => void) {
|
||||
if (content && linkRegex.test(content) && editor.operations?.[0]?.type === "remove_text") {
|
||||
SlateTransforms.insertText(
|
||||
editor,
|
||||
`[${editor.operations[0].text}](${content})`
|
||||
);
|
||||
}
|
||||
else originalBehavior();
|
||||
}
|
||||
});
|
|
@ -3,6 +3,11 @@
|
|||
color: var(--status-danger, #f04747) !important;
|
||||
}
|
||||
|
||||
/* Markdown title highlighting */
|
||||
.messagelogger-deleted [class*="contents"] :is(h1, h2, h3) {
|
||||
color: var(--status-danger, #f04747) !important;
|
||||
}
|
||||
|
||||
/* Bot "thinking" text highlighting */
|
||||
.messagelogger-deleted [class*="colorStandard"] {
|
||||
color: var(--status-danger, #f04747) !important;
|
||||
|
|
|
@ -87,6 +87,7 @@ export default definePlugin({
|
|||
|
||||
async start() {
|
||||
await DataStore.update("summaries-data", summaries => {
|
||||
summaries ??= {};
|
||||
for (const key of Object.keys(summaries)) {
|
||||
for (let i = summaries[key].length - 1; i >= 0; i--) {
|
||||
if (summaries[key][i].time < Date.now() - 1000 * 60 * 60 * 24 * settings.store.summaryExpiryThresholdDays) {
|
||||
|
|
|
@ -21,8 +21,7 @@ import "./shiki.css";
|
|||
import { enableStyle } from "@api/Styles";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
import previewExampleText from "~fileContent/previewExample.tsx";
|
||||
import previewExampleText from "file://previewExample.tsx";
|
||||
|
||||
import { shiki } from "./api/shiki";
|
||||
import { createHighlighter } from "./components/Highlighter";
|
||||
|
|
262
src/plugins/watchTogetherAdblock.desktop/adguard.js
Normal file
262
src/plugins/watchTogetherAdblock.desktop/adguard.js
Normal file
|
@ -0,0 +1,262 @@
|
|||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* This file is part of AdGuard's Block YouTube Ads (https://github.com/AdguardTeam/BlockYouTubeAdsShortcut).
|
||||
*
|
||||
* Copyright (C) AdGuard Team
|
||||
*
|
||||
* AdGuard's Block YouTube Ads 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.
|
||||
*
|
||||
* AdGuard's Block YouTube Ads 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 AdGuard's Block YouTube Ads. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const LOGO_ID = "block-youtube-ads-logo";
|
||||
const hiddenCSS = [
|
||||
"#__ffYoutube1",
|
||||
"#__ffYoutube2",
|
||||
"#__ffYoutube3",
|
||||
"#__ffYoutube4",
|
||||
"#feed-pyv-container",
|
||||
"#feedmodule-PRO",
|
||||
"#homepage-chrome-side-promo",
|
||||
"#merch-shelf",
|
||||
"#offer-module",
|
||||
'#pla-shelf > ytd-pla-shelf-renderer[class="style-scope ytd-watch"]',
|
||||
"#pla-shelf",
|
||||
"#premium-yva",
|
||||
"#promo-info",
|
||||
"#promo-list",
|
||||
"#promotion-shelf",
|
||||
"#related > ytd-watch-next-secondary-results-renderer > #items > ytd-compact-promoted-video-renderer.ytd-watch-next-secondary-results-renderer",
|
||||
"#search-pva",
|
||||
"#shelf-pyv-container",
|
||||
"#video-masthead",
|
||||
"#watch-branded-actions",
|
||||
"#watch-buy-urls",
|
||||
"#watch-channel-brand-div",
|
||||
"#watch7-branded-banner",
|
||||
"#YtKevlarVisibilityIdentifier",
|
||||
"#YtSparklesVisibilityIdentifier",
|
||||
".carousel-offer-url-container",
|
||||
".companion-ad-container",
|
||||
".GoogleActiveViewElement",
|
||||
'.list-view[style="margin: 7px 0pt;"]',
|
||||
".promoted-sparkles-text-search-root-container",
|
||||
".promoted-videos",
|
||||
".searchView.list-view",
|
||||
".sparkles-light-cta",
|
||||
".watch-extra-info-column",
|
||||
".watch-extra-info-right",
|
||||
".ytd-carousel-ad-renderer",
|
||||
".ytd-compact-promoted-video-renderer",
|
||||
".ytd-companion-slot-renderer",
|
||||
".ytd-merch-shelf-renderer",
|
||||
".ytd-player-legacy-desktop-watch-ads-renderer",
|
||||
".ytd-promoted-sparkles-text-search-renderer",
|
||||
".ytd-promoted-video-renderer",
|
||||
".ytd-search-pyv-renderer",
|
||||
".ytd-video-masthead-ad-v3-renderer",
|
||||
".ytp-ad-action-interstitial-background-container",
|
||||
".ytp-ad-action-interstitial-slot",
|
||||
".ytp-ad-image-overlay",
|
||||
".ytp-ad-overlay-container",
|
||||
".ytp-ad-progress",
|
||||
".ytp-ad-progress-list",
|
||||
'[class*="ytd-display-ad-"]',
|
||||
'[layout*="display-ad-"]',
|
||||
'a[href^="http://www.youtube.com/cthru?"]',
|
||||
'a[href^="https://www.youtube.com/cthru?"]',
|
||||
"ytd-action-companion-ad-renderer",
|
||||
"ytd-banner-promo-renderer",
|
||||
"ytd-compact-promoted-video-renderer",
|
||||
"ytd-companion-slot-renderer",
|
||||
"ytd-display-ad-renderer",
|
||||
"ytd-promoted-sparkles-text-search-renderer",
|
||||
"ytd-promoted-sparkles-web-renderer",
|
||||
"ytd-search-pyv-renderer",
|
||||
"ytd-single-option-survey-renderer",
|
||||
"ytd-video-masthead-ad-advertiser-info-renderer",
|
||||
"ytd-video-masthead-ad-v3-renderer",
|
||||
"YTM-PROMOTED-VIDEO-RENDERER",
|
||||
];
|
||||
/**
|
||||
* Adds CSS to the page
|
||||
*/
|
||||
const hideElements = () => {
|
||||
const selectors = hiddenCSS;
|
||||
if (!selectors) {
|
||||
return;
|
||||
}
|
||||
const rule = selectors.join(", ") + " { display: none!important; }";
|
||||
const style = document.createElement("style");
|
||||
style.innerHTML = rule;
|
||||
document.head.appendChild(style);
|
||||
};
|
||||
/**
|
||||
* Calls the "callback" function on every DOM change, but not for the tracked events
|
||||
* @param {Function} callback callback function
|
||||
*/
|
||||
const observeDomChanges = callback => {
|
||||
const domMutationObserver = new MutationObserver(mutations => {
|
||||
callback(mutations);
|
||||
});
|
||||
domMutationObserver.observe(document.documentElement, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
};
|
||||
/**
|
||||
* This function is supposed to be called on every DOM change
|
||||
*/
|
||||
const hideDynamicAds = () => {
|
||||
const elements = document.querySelectorAll("#contents > ytd-rich-item-renderer ytd-display-ad-renderer");
|
||||
if (elements.length === 0) {
|
||||
return;
|
||||
}
|
||||
elements.forEach(el => {
|
||||
if (el.parentNode && el.parentNode.parentNode) {
|
||||
const parent = el.parentNode.parentNode;
|
||||
if (parent.localName === "ytd-rich-item-renderer") {
|
||||
parent.style.display = "none";
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* This function checks if the video ads are currently running
|
||||
* and auto-clicks the skip button.
|
||||
*/
|
||||
const autoSkipAds = () => {
|
||||
// If there's a video that plays the ad at this moment, scroll this ad
|
||||
if (document.querySelector(".ad-showing")) {
|
||||
const video = document.querySelector("video");
|
||||
if (video && video.duration) {
|
||||
video.currentTime = video.duration;
|
||||
// Skip button should appear after that,
|
||||
// now simply click it automatically
|
||||
setTimeout(() => {
|
||||
const skipBtn = document.querySelector("button.ytp-ad-skip-button");
|
||||
if (skipBtn) {
|
||||
skipBtn.click();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This function overrides a property on the specified object.
|
||||
*
|
||||
* @param {object} obj object to look for properties in
|
||||
* @param {string} propertyName property to override
|
||||
* @param {*} overrideValue value to set
|
||||
*/
|
||||
const overrideObject = (obj, propertyName, overrideValue) => {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
let overriden = false;
|
||||
for (const key in obj) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (obj.hasOwnProperty(key) && key === propertyName) {
|
||||
obj[key] = overrideValue;
|
||||
overriden = true;
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
} else if (obj.hasOwnProperty(key) && typeof obj[key] === "object") {
|
||||
if (overrideObject(obj[key], propertyName, overrideValue)) {
|
||||
overriden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return overriden;
|
||||
};
|
||||
/**
|
||||
* Overrides JSON.parse and Response.json functions.
|
||||
* Examines these functions arguments, looks for properties with the specified name there
|
||||
* and if it exists, changes it's value to what was specified.
|
||||
*
|
||||
* @param {string} propertyName name of the property
|
||||
* @param {*} overrideValue new value for the property
|
||||
*/
|
||||
const jsonOverride = (propertyName, overrideValue) => {
|
||||
const nativeJSONParse = JSON.parse;
|
||||
JSON.parse = (...args) => {
|
||||
const obj = nativeJSONParse.apply(this, args);
|
||||
// Override it's props and return back to the caller
|
||||
overrideObject(obj, propertyName, overrideValue);
|
||||
return obj;
|
||||
};
|
||||
// Override Response.prototype.json
|
||||
const nativeResponseJson = Response.prototype.json;
|
||||
Response.prototype.json = new Proxy(nativeResponseJson, {
|
||||
apply(...args) {
|
||||
// Call the target function, get the original Promise
|
||||
const promise = Reflect.apply(...args);
|
||||
// Create a new one and override the JSON inside
|
||||
return new Promise((resolve, reject) => {
|
||||
promise.then(data => {
|
||||
overrideObject(data, propertyName, overrideValue);
|
||||
resolve(data);
|
||||
}).catch(error => reject(error));
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
const addAdGuardLogoStyle = () => { };
|
||||
const addAdGuardLogo = () => {
|
||||
if (document.getElementById(LOGO_ID)) {
|
||||
return;
|
||||
}
|
||||
const logo = document.createElement("span");
|
||||
logo.innerHTML = "__logo_text__";
|
||||
logo.setAttribute("id", LOGO_ID);
|
||||
if (window.location.hostname === "m.youtube.com") {
|
||||
const btn = document.querySelector("header.mobile-topbar-header > button");
|
||||
if (btn) {
|
||||
btn.parentNode?.insertBefore(logo, btn.nextSibling);
|
||||
addAdGuardLogoStyle();
|
||||
}
|
||||
} else if (window.location.hostname === "www.youtube.com") {
|
||||
const code = document.getElementById("country-code");
|
||||
if (code) {
|
||||
code.innerHTML = "";
|
||||
code.appendChild(logo);
|
||||
addAdGuardLogoStyle();
|
||||
}
|
||||
} else if (window.location.hostname === "music.youtube.com") {
|
||||
const el = document.querySelector(".ytmusic-nav-bar#left-content");
|
||||
if (el) {
|
||||
el.appendChild(logo);
|
||||
addAdGuardLogoStyle();
|
||||
}
|
||||
} else if (window.location.hostname === "www.youtube-nocookie.com") {
|
||||
const code = document.querySelector("#yt-masthead #logo-container .content-region");
|
||||
if (code) {
|
||||
code.innerHTML = "";
|
||||
code.appendChild(logo);
|
||||
addAdGuardLogoStyle();
|
||||
}
|
||||
}
|
||||
};
|
||||
// Removes ads metadata from YouTube XHR requests
|
||||
jsonOverride("adPlacements", []);
|
||||
jsonOverride("playerAds", []);
|
||||
// Applies CSS that hides YouTube ad elements
|
||||
hideElements();
|
||||
// Some changes should be re-evaluated on every page change
|
||||
addAdGuardLogo();
|
||||
hideDynamicAds();
|
||||
autoSkipAds();
|
||||
observeDomChanges(() => {
|
||||
addAdGuardLogo();
|
||||
hideDynamicAds();
|
||||
autoSkipAds();
|
||||
});
|
15
src/plugins/watchTogetherAdblock.desktop/index.ts
Normal file
15
src/plugins/watchTogetherAdblock.desktop/index.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
// The entire code of this plugin can be found in native.ts
|
||||
export default definePlugin({
|
||||
name: "WatchTogetherAdblock",
|
||||
description: "Block ads in the YouTube WatchTogether activity via AdGuard",
|
||||
authors: [Devs.ImLvna],
|
||||
});
|
21
src/plugins/watchTogetherAdblock.desktop/native.ts
Normal file
21
src/plugins/watchTogetherAdblock.desktop/native.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { RendererSettings } from "@main/settings";
|
||||
import { app } from "electron";
|
||||
import adguard from "file://adguard.js?minify";
|
||||
|
||||
app.on("browser-window-created", (_, win) => {
|
||||
win.webContents.on("frame-created", (_, { frame }) => {
|
||||
frame.once("dom-ready", () => {
|
||||
if (frame.url.includes("discordsays") && frame.url.includes("youtube.com")) {
|
||||
if (!RendererSettings.store.plugins?.WatchTogetherAdblock?.enabled) return;
|
||||
|
||||
frame.executeJavaScript(adguard);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -188,7 +188,7 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
id: 296776625432035328n,
|
||||
},
|
||||
TheSun: {
|
||||
name: "ActuallyTheSun",
|
||||
name: "sunnie",
|
||||
id: 406028027768733696n
|
||||
},
|
||||
axyie: {
|
||||
|
@ -404,6 +404,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
name: "maisy",
|
||||
id: 257109471589957632n,
|
||||
},
|
||||
Lexi: {
|
||||
name: "Lexi",
|
||||
id: 506101469787717658n
|
||||
},
|
||||
Mopi: {
|
||||
name: "Mopi",
|
||||
id: 1022189106614243350n
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue