Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
bf376f9bbd
15 changed files with 1117 additions and 1908 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: pnpm/action-setup@v6
|
||||
|
||||
|
|
|
|||
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
@ -79,7 +79,8 @@ jobs:
|
|||
|
||||
- name: Create sources zip
|
||||
if: steps.check.outputs.release == 'true'
|
||||
run: zip -r dist/extension-sources.zip . -x "node_modules/*" -x "dist/*" -x
|
||||
run:
|
||||
zip -r dist/extension-sources.zip . -x "node_modules/*" -x "dist/*" -x
|
||||
".git/*"
|
||||
|
||||
- name: Publish extension
|
||||
|
|
|
|||
7
.github/workflows/reportBrokenPlugins.yml
vendored
7
.github/workflows/reportBrokenPlugins.yml
vendored
|
|
@ -12,7 +12,8 @@ on:
|
|||
default: both
|
||||
webhook_url:
|
||||
type: string
|
||||
description: "Webhook URL that the report will be posted to. This will be
|
||||
description:
|
||||
"Webhook URL that the report will be posted to. This will be
|
||||
visible for everyone, so DO NOT pass sensitive webhooks like
|
||||
discord webhook. This is meant to be used by Equibot."
|
||||
required: false
|
||||
|
|
@ -29,11 +30,11 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ github.event_name == 'schedule' && 'dev' || github.ref }}
|
||||
|
||||
- uses: pnpm/action-setup@v6 # Install pnpm using packageManager key in package.json
|
||||
- uses: pnpm/action-setup@v6
|
||||
|
||||
- name: Use Node.js 24
|
||||
uses: actions/setup-node@v6
|
||||
|
|
|
|||
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
|
|
@ -15,8 +15,8 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: pnpm/action-setup@v6 # Install pnpm using packageManager key in package.json
|
||||
- uses: actions/checkout@v7
|
||||
- uses: pnpm/action-setup@v6
|
||||
|
||||
- name: Use Node.js 24
|
||||
uses: actions/setup-node@v6
|
||||
|
|
|
|||
2
.npmrc
2
.npmrc
|
|
@ -1,2 +0,0 @@
|
|||
strict-peer-dependencies=false
|
||||
package-manager-strict=false
|
||||
32
package.json
32
package.json
|
|
@ -52,13 +52,13 @@
|
|||
"@types/tinycolor2": "^1.4.6",
|
||||
"@vap/core": "0.0.12",
|
||||
"@vap/shiki": "0.10.5",
|
||||
"fflate": "^0.8.2",
|
||||
"fflate": "^0.8.3",
|
||||
"gifenc": "github:mattdesl/gifenc#64842fca317b112a8590f8fef2bf3825da8f6fe3",
|
||||
"gifuct-js": "^2.1.2",
|
||||
"idb": "8.0.3",
|
||||
"jsqr": "1.4.0",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"nanoid": "^5.1.6",
|
||||
"nanoid": "^5.1.16",
|
||||
"native-file-system-adapter": "^3.0.1",
|
||||
"usercss-meta": "^0.12.0",
|
||||
"virtual-merge": "^1.0.1",
|
||||
|
|
@ -67,16 +67,16 @@
|
|||
"devDependencies": {
|
||||
"@electron/asar": "^4.2.0",
|
||||
"@stylistic/eslint-plugin": "^5.10.0",
|
||||
"@types/chrome": "^0.1.40",
|
||||
"@types/chrome": "^0.2.0",
|
||||
"@types/lodash": "^4.17.24",
|
||||
"@types/node": "^25.6.0",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@types/node": "^26.0.1",
|
||||
"@types/react": "19.1.0",
|
||||
"@types/react-dom": "19.1.0",
|
||||
"@types/yazl": "^3.3.1",
|
||||
"@vencord/discord-types": "link:packages/discord-types",
|
||||
"diff": "^9.0.0",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "10.2.0",
|
||||
"esbuild": "^0.28.1",
|
||||
"eslint": "10.6.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-simple-header": "^1.2.1",
|
||||
|
|
@ -86,22 +86,22 @@
|
|||
"html-minifier-terser": "^7.2.0",
|
||||
"moment": "^2.22.2",
|
||||
"p-limit": "^7.3.0",
|
||||
"puppeteer-core": "^24.41.0",
|
||||
"puppeteer-core": "^25.2.1",
|
||||
"standalone-electron-types": "^41.2.1",
|
||||
"stylelint": "^17.8.0",
|
||||
"stylelint": "^17.14.0",
|
||||
"stylelint-config-standard": "^40.0.0",
|
||||
"svgo": "^4.0.1",
|
||||
"ts-patch": "^3.3.0",
|
||||
"ts-pattern": "^5.9.0",
|
||||
"tsx": "^4.21.0",
|
||||
"type-fest": "^5.5.0",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript-eslint": "^8.58.2",
|
||||
"tsx": "^4.22.4",
|
||||
"type-fest": "^5.7.0",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.62.1",
|
||||
"typescript-transform-paths": "^3.5.6",
|
||||
"zip-local": "^0.3.5"
|
||||
},
|
||||
"packageManager": "pnpm@11.8.0",
|
||||
"packageManager": "pnpm@11.9.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=22"
|
||||
}
|
||||
}
|
||||
|
|
@ -13,10 +13,10 @@
|
|||
"directory": "packages/discord-types"
|
||||
},
|
||||
"dependencies": {
|
||||
"moment": "^2.22.2",
|
||||
"type-fest": "^4.41.0"
|
||||
"moment": "2.22.2",
|
||||
"type-fest": "^5.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.0.10"
|
||||
"@types/react": "19.1.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@equicord/types",
|
||||
"private": false,
|
||||
"version": "1.14.2",
|
||||
"version": "1.14.15",
|
||||
"description": "",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
|
|
@ -10,23 +10,23 @@
|
|||
},
|
||||
"keywords": [],
|
||||
"author": "Equicord & Vencord Contributors",
|
||||
"license": "GPL-3.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^11.0.4",
|
||||
"fs-extra": "^11.3.0",
|
||||
"tsx": "^4.19.2"
|
||||
"fs-extra": "^11.3.6",
|
||||
"tsx": "^4.22.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/lodash": "4.17.15",
|
||||
"@types/node": "^22.13.4",
|
||||
"@vencord/discord-types": "^1.0.0",
|
||||
"@types/lodash": "4.17.19",
|
||||
"@types/node": "^26.0.1",
|
||||
"@vencord/discord-types": "^1.0.1",
|
||||
"highlight.js": "11.11.1",
|
||||
"moment": "^2.22.2",
|
||||
"ts-pattern": "^5.6.0",
|
||||
"type-fest": "^4.35.0"
|
||||
"type-fest": "^5.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "19.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
2504
pnpm-lock.yaml
generated
2504
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,25 +1,19 @@
|
|||
packages:
|
||||
- packages/*
|
||||
|
||||
allowBuilds:
|
||||
esbuild: true
|
||||
|
||||
overrides:
|
||||
"@eslint/plugin-kit@<0.3.4": ">=0.3.4"
|
||||
|
||||
patchedDependencies:
|
||||
"@types/less@3.0.8": patches/@types__less@3.0.8.patch
|
||||
|
||||
peerDependencyRules:
|
||||
ignoreMissing:
|
||||
- eslint-plugin-import
|
||||
- eslint
|
||||
|
||||
allowedDeprecatedVersions:
|
||||
source-map-resolve: "*"
|
||||
resolve-url: "*"
|
||||
source-map-url: "*"
|
||||
urix: "*"
|
||||
q: "*"
|
||||
|
||||
strictPeerDependencies: false
|
||||
allowBuilds:
|
||||
esbuild: true
|
||||
pmOnFail: warn
|
||||
verifyDepsBeforeRun: prompt
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
import { Logger } from "@utils/Logger";
|
||||
import type { Channel, CloudUpload, CustomEmoji, Message } from "@vencord/discord-types";
|
||||
import type { Channel, CustomEmoji, Message } from "@vencord/discord-types";
|
||||
import { MessageStore } from "@webpack/common";
|
||||
import type { Promisable } from "type-fest";
|
||||
|
||||
|
|
@ -30,37 +30,40 @@ export interface MessageObject {
|
|||
tts: boolean;
|
||||
}
|
||||
|
||||
export interface MessageReplyOptions {
|
||||
messageReference: Message["messageReference"];
|
||||
export interface SendMessageOptions {
|
||||
messageReference?: Message["messageReference"];
|
||||
allowedMentions?: {
|
||||
parse: Array<string>;
|
||||
users?: Array<string>;
|
||||
roles?: Array<string>;
|
||||
parse: string[];
|
||||
repliedUser: boolean;
|
||||
};
|
||||
location: string;
|
||||
stickerIds?: string[];
|
||||
alsoForwardToChannelId?: string;
|
||||
|
||||
// If you end up using these, update their type
|
||||
scheduledTimestamp?: unknown;
|
||||
mediaMention?: unknown;
|
||||
}
|
||||
|
||||
export interface MessageOptions {
|
||||
stickers?: string[];
|
||||
uploads?: CloudUpload[];
|
||||
replyOptions: MessageReplyOptions;
|
||||
export interface SendMessageProps {
|
||||
hasStickers: boolean;
|
||||
hasAttachments: boolean;
|
||||
content: string;
|
||||
channel: Channel;
|
||||
type?: any;
|
||||
openWarningPopout: (props: any) => any;
|
||||
}
|
||||
|
||||
export type MessageSendListener = (channelId: string, messageObj: MessageObject, options: MessageOptions) => Promisable<void | { cancel: boolean; }>;
|
||||
export type MessageSendListener = (channelId: string, messageObj: MessageObject, options: SendMessageOptions, props: SendMessageProps) => Promisable<void | { cancel: boolean; }>;
|
||||
export type MessageEditListener = (channelId: string, messageId: string, messageObj: MessageObject) => Promisable<void | { cancel: boolean; }>;
|
||||
|
||||
const sendListeners = new Set<MessageSendListener>();
|
||||
const editListeners = new Set<MessageEditListener>();
|
||||
|
||||
export async function _handlePreSend(channelId: string, messageObj: MessageObject, options: MessageOptions, replyOptions: MessageReplyOptions) {
|
||||
options.replyOptions = replyOptions;
|
||||
export async function _handlePreSend(channelId: string, messageObj: MessageObject, options: SendMessageOptions, props: SendMessageProps) {
|
||||
for (const listener of sendListeners) {
|
||||
try {
|
||||
const result = await listener(channelId, messageObj, options);
|
||||
const result = await listener(channelId, messageObj, options, props);
|
||||
if (result?.cancel) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ async function calculateGitChanges() {
|
|||
|
||||
return data.commits.map((c: any) => ({
|
||||
hash: c.sha,
|
||||
author: c.author?.login ?? c.commit?.author?.name ?? "Ghost",
|
||||
author: c.author?.login ?? c.commit?.author?.name ?? "Unknown Author",
|
||||
message: c.commit.message.split("\n")[0]
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ export default definePlugin({
|
|||
replacement: {
|
||||
// https://regex101.com/r/7iswuk/1
|
||||
match: /let (\i)=\i\.\i\.parse\((\i),.+?\.getSendMessageOptions\(\{.+?\}\)?;(?=.+?(\i)\.flags=)(?<=\)\(({.+?})\)\.then.+?)/,
|
||||
replace: (m, parsedMessage, channel, replyOptions, extra) => m +
|
||||
`if(await Vencord.Api.MessageEvents._handlePreSend(${channel}.id,${parsedMessage},${extra},${replyOptions}))` +
|
||||
replace: (m, parsedMessage, channel, options, props) => m +
|
||||
`if(await Vencord.Api.MessageEvents._handlePreSend(${channel}.id,${parsedMessage},${options},${props}))` +
|
||||
"return{shouldClear:false,shouldRefocus:true};"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -827,7 +827,7 @@ export default definePlugin({
|
|||
return;
|
||||
}
|
||||
|
||||
this.preSend = addMessagePreSendListener(async (channelId, messageObj, extra) => {
|
||||
this.preSend = addMessagePreSendListener(async (channelId, messageObj, options) => {
|
||||
const { guildId } = this;
|
||||
|
||||
let hasBypass = false;
|
||||
|
|
@ -836,7 +836,7 @@ export default definePlugin({
|
|||
if (!s.enableStickerBypass)
|
||||
break stickerBypass;
|
||||
|
||||
const sticker = StickersStore.getStickerById(extra.stickers?.[0]!);
|
||||
const sticker = StickersStore.getStickerById(options.stickerIds?.[0]!);
|
||||
if (!sticker)
|
||||
break stickerBypass;
|
||||
|
||||
|
|
@ -882,7 +882,7 @@ export default definePlugin({
|
|||
const linkText = s.hyperLinkText.replaceAll("{{NAME}}", sticker.name);
|
||||
|
||||
messageObj.content += `${getWordBoundary(messageObj.content, messageObj.content.length - 1)}${s.useStickerHyperLinks ? `[${linkText}](${url})` : url}`;
|
||||
extra.stickers!.length = 0;
|
||||
options.stickerIds!.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,201 +18,203 @@
|
|||
* 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/>.
|
||||
*/
|
||||
(() => {
|
||||
if (window.adguardInjected) return;
|
||||
window.adguardInjected = true;
|
||||
|
||||
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.textContent = 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";
|
||||
}
|
||||
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;
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
if (obj.hasOwnProperty(key) && key === propertyName) {
|
||||
obj[key] = overrideValue;
|
||||
overriden = true;
|
||||
|
||||
} 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;
|
||||
const rule = selectors.join(", ") + " { display: none!important; }";
|
||||
const style = document.createElement("style");
|
||||
style.textContent = rule;
|
||||
document.head.appendChild(style);
|
||||
};
|
||||
// Override Response.prototype.json
|
||||
Response.prototype.json = new Proxy(Response.prototype.json, {
|
||||
async apply(...args) {
|
||||
// Call the target function, get the original Promise
|
||||
const result = await Reflect.apply(...args);
|
||||
// Create a new one and override the JSON inside
|
||||
overrideObject(result, propertyName, overrideValue);
|
||||
return result;
|
||||
},
|
||||
});
|
||||
};
|
||||
// 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
|
||||
hideDynamicAds();
|
||||
autoSkipAds();
|
||||
observeDomChanges(() => {
|
||||
/**
|
||||
* 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) {
|
||||
if (obj.hasOwnProperty(key) && key === propertyName) {
|
||||
obj[key] = overrideValue;
|
||||
overriden = true;
|
||||
} 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
|
||||
Response.prototype.json = new Proxy(Response.prototype.json, {
|
||||
async apply(...args) {
|
||||
// Call the target function, get the original Promise
|
||||
const result = await Reflect.apply(...args);
|
||||
// Create a new one and override the JSON inside
|
||||
overrideObject(result, propertyName, overrideValue);
|
||||
return result;
|
||||
},
|
||||
});
|
||||
};
|
||||
// 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
|
||||
hideDynamicAds();
|
||||
autoSkipAds();
|
||||
});
|
||||
observeDomChanges(() => {
|
||||
hideDynamicAds();
|
||||
autoSkipAds();
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue