Skip to content

Commit 4006bcf

Browse files
committed
feat: add tvtropes-anti-adblock-bypass
1 parent a1ce4f6 commit 4006bcf

10 files changed

Lines changed: 258 additions & 0 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# vscode
66
.vscode/
77
.history/
8+
.claude/
89

910
# npm
1011
node_modules/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# TVTropes Anti-Adblock Bypass
2+
3+
A userscript that bypasses anti-adblock detection on TVTropes.org, allowing you to browse the site with your adblocker enabled.
4+
5+
## What it does
6+
7+
This userscript intercepts and modifies scripts that detect ad blockers on TVTropes, preventing the anti-adblock warning from appearing. It also blocks ad-related scripts from loading.
8+
9+
## Installation
10+
11+
1. Install a userscript manager like [Tampermonkey](https://www.tampermonkey.net/) or [Greasemonkey](https://www.greasespot.net/)
12+
2. Download the userscript from <https://github.com/rxliuli/userscripts/releases/latest/download/tvtropes-anti-adblock-bypass.user.js>
13+
14+
## How it works
15+
16+
The userscript runs at document-start and:
17+
18+
- Intercepts script loading via DOM manipulation hooks and MutationObserver
19+
- Blocks ad scripts from Google (googlesyndication, doubleclick, googletagservices) and BigCrunch
20+
- Modifies the anti-adblock detection script to prevent it from triggering
21+
22+
## Disclaimer
23+
24+
This userscript is for personal use. Please consider supporting TVTropes by subscribing or allowing ads if you find their content valuable.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "tvtropes-anti-adblock-bypass",
3+
"private": true,
4+
"version": "0.1.0",
5+
"type": "module",
6+
"scripts": {
7+
"build": "tsc && vite build",
8+
"preview": "vite preview"
9+
},
10+
"devDependencies": {
11+
"typescript": "^5.9.2",
12+
"vite": "^7.1.3",
13+
"vite-plugin-monkey": "^7.1.1"
14+
}
15+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* hijackScript - Intercept script loading
3+
* @param callback Callback function that receives the script node and can modify or block script execution
4+
*/
5+
export function hijackScript(callback: (node: HTMLScriptElement) => void) {
6+
const dynamicScripts = new WeakSet<HTMLScriptElement>()
7+
8+
const originalCreateElement = document.createElement.bind(document)
9+
document.createElement = ((tagName: string, options?: any) => {
10+
const element = originalCreateElement(tagName, options)
11+
if (tagName.toLowerCase() === 'script') {
12+
dynamicScripts.add(element as HTMLScriptElement)
13+
}
14+
return element
15+
}) as typeof document.createElement
16+
17+
const originalAppendChild = Node.prototype.appendChild
18+
Node.prototype.appendChild = function <T extends Node>(node: T): T {
19+
if (node instanceof HTMLScriptElement && dynamicScripts.has(node)) {
20+
callback(node)
21+
}
22+
return originalAppendChild.call(this, node) as T
23+
}
24+
25+
const originalInsertBefore = Node.prototype.insertBefore
26+
Node.prototype.insertBefore = function <T extends Node>(node: T, child: Node | null): T {
27+
if (node instanceof HTMLScriptElement && dynamicScripts.has(node)) {
28+
callback(node)
29+
}
30+
return originalInsertBefore.call(this, node, child) as T
31+
}
32+
33+
const observer = new MutationObserver((mutations) => {
34+
mutations.forEach((mutation) => {
35+
mutation.addedNodes.forEach((node) => {
36+
if (node instanceof HTMLScriptElement && !dynamicScripts.has(node)) {
37+
callback(node)
38+
}
39+
})
40+
})
41+
})
42+
43+
observer.observe(document.documentElement, {
44+
childList: true,
45+
subtree: true,
46+
})
47+
48+
return () => {
49+
document.createElement = originalCreateElement
50+
Node.prototype.appendChild = originalAppendChild
51+
Node.prototype.insertBefore = originalInsertBefore
52+
observer.disconnect()
53+
}
54+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { hijackScript } from './lib/hijackScript'
2+
3+
hijackScript((node) => {
4+
let text = node.textContent
5+
if (text.includes('Please allow ads on our site or subscribe')) {
6+
// Modify detection logic to never trigger
7+
text = text.replace(text.match(/if\((\w+?>=2.+?===false\))\)/)?.[1]!, 'false')
8+
text = text.replace(text.match(/else if\((\(.+?<40)\){/)?.[1]!, 'false')
9+
node.textContent = text
10+
console.log('✏️ Modified anti-adblock script')
11+
}
12+
})
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// <reference types="vite/client" />
2+
/// <reference types="vite-plugin-monkey/client" />
3+
//// <reference types="vite-plugin-monkey/global" />
4+
/// <reference types="vite-plugin-monkey/style" />
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ESNext",
4+
"useDefineForClassFields": true,
5+
"module": "ESNext",
6+
"lib": ["ESNext", "DOM"],
7+
"moduleResolution": "Node",
8+
"strict": true,
9+
"sourceMap": true,
10+
"resolveJsonModule": true,
11+
"isolatedModules": true,
12+
"esModuleInterop": true,
13+
"noEmit": true,
14+
"noUnusedLocals": true,
15+
"noUnusedParameters": true,
16+
"noImplicitReturns": true,
17+
"skipLibCheck": true
18+
},
19+
"include": ["src"]
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { defineConfig, Plugin, build as viteBuild } from 'vite'
2+
import monkey from 'vite-plugin-monkey'
3+
4+
export default defineConfig({
5+
plugins: [
6+
monkey({
7+
entry: 'src/main.ts',
8+
userscript: {
9+
name: 'TVTropes Anti-Adblock Bypass',
10+
namespace: 'https://rxliuli.com',
11+
description: 'Bypass anti-adblock on TVTropes.',
12+
match: ['https://tvtropes.org/**'],
13+
author: 'rxliuli',
14+
license: 'GPL-3.0-only',
15+
version: (await import('./package.json')).version,
16+
'run-at': 'document-start',
17+
},
18+
}),
19+
],
20+
})

pnpm-lock.yaml

Lines changed: 84 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)