Watch Together Plugin + Electron Desktop App mit Ad-Blocker
Neuer Tab: Watch Together - gemeinsam Videos schauen (w2g.tv-Style) - Raum-System mit optionalem Passwort und Host-Kontrolle - Video-Queue mit Hinzufuegen/Entfernen/Umordnen - YouTube (IFrame API) + direkte Video-URLs (.mp4, .webm) - Synchronisierte Wiedergabe via WebSocket (/ws/watch-together) - Server-autoritative Playback-State mit Drift-Korrektur (2.5s Sync-Pulse) - Host-Transfer bei Disconnect, Room-Cleanup nach 30s Electron Desktop App (electron/): - Wrapper fuer Gaming Hub mit integriertem Ad-Blocker - uBlock-Style Request-Filtering via session.webRequest - 100+ Ad-Domains + YouTube-spezifische Filter - Download-Button im Web-Header (nur sichtbar wenn nicht in Electron) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4943bbf4a1
commit
73f247ada3
16 changed files with 7386 additions and 4833 deletions
87
electron/ad-blocker.js
Normal file
87
electron/ad-blocker.js
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function setupAdBlocker(session) {
|
||||
// Load filter domains
|
||||
const filtersPath = path.join(__dirname, 'filters.txt');
|
||||
let rawFilters;
|
||||
try {
|
||||
rawFilters = fs.readFileSync(filtersPath, 'utf-8');
|
||||
} catch (err) {
|
||||
console.error('[AdBlocker] Could not load filters.txt:', err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse: each line is either a domain, a URL path pattern, or a regex
|
||||
const blockedDomains = new Set();
|
||||
const blockedPatterns = [];
|
||||
|
||||
for (const line of rawFilters.split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
|
||||
if (trimmed.startsWith('/') && trimmed.endsWith('/')) {
|
||||
// Regex pattern
|
||||
try {
|
||||
blockedPatterns.push(new RegExp(trimmed.slice(1, -1)));
|
||||
} catch {
|
||||
// invalid regex, skip
|
||||
}
|
||||
} else if (trimmed.includes('/')) {
|
||||
// URL path pattern (string match)
|
||||
blockedPatterns.push(trimmed);
|
||||
} else {
|
||||
// Domain
|
||||
blockedDomains.add(trimmed);
|
||||
}
|
||||
}
|
||||
|
||||
let blockedCount = 0;
|
||||
|
||||
session.webRequest.onBeforeRequest((details, callback) => {
|
||||
try {
|
||||
const url = new URL(details.url);
|
||||
const hostname = url.hostname;
|
||||
|
||||
// Check domain blocklist (including subdomains)
|
||||
for (const domain of blockedDomains) {
|
||||
if (hostname === domain || hostname.endsWith('.' + domain)) {
|
||||
blockedCount++;
|
||||
callback({ cancel: true });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check URL patterns
|
||||
const fullUrl = details.url;
|
||||
for (const pattern of blockedPatterns) {
|
||||
if (pattern instanceof RegExp) {
|
||||
if (pattern.test(fullUrl)) {
|
||||
blockedCount++;
|
||||
callback({ cancel: true });
|
||||
return;
|
||||
}
|
||||
} else if (fullUrl.includes(pattern)) {
|
||||
blockedCount++;
|
||||
callback({ cancel: true });
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// URL parsing error, allow request
|
||||
}
|
||||
|
||||
callback({});
|
||||
});
|
||||
|
||||
// Log stats periodically
|
||||
setInterval(() => {
|
||||
if (blockedCount > 0) {
|
||||
console.log(`[AdBlocker] ${blockedCount} requests blocked`);
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
console.log(`[AdBlocker] Loaded ${blockedDomains.size} domains + ${blockedPatterns.length} patterns`);
|
||||
}
|
||||
|
||||
module.exports = { setupAdBlocker };
|
||||
253
electron/filters.txt
Normal file
253
electron/filters.txt
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
# ============================================================
|
||||
# Gaming Hub Ad-Blocker Filter List
|
||||
# Focused on YouTube ads, general ad networks, and trackers
|
||||
# ============================================================
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Google Ads & Ad Networks
|
||||
# ------------------------------------------------------------
|
||||
doubleclick.net
|
||||
googlesyndication.com
|
||||
googleadservices.com
|
||||
google-analytics.com
|
||||
googletagmanager.com
|
||||
googletagservices.com
|
||||
adservice.google.com
|
||||
pagead2.googlesyndication.com
|
||||
ads.google.com
|
||||
adclick.g.doubleclick.net
|
||||
googleads.g.doubleclick.net
|
||||
www.googleadservices.com
|
||||
partner.googleadservices.com
|
||||
tpc.googlesyndication.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Major Ad Exchanges & Programmatic
|
||||
# ------------------------------------------------------------
|
||||
adnxs.com
|
||||
adsrvr.org
|
||||
adform.net
|
||||
amazon-adsystem.com
|
||||
adsymptotic.com
|
||||
adtilt.com
|
||||
advertising.com
|
||||
bidswitch.net
|
||||
casalemedia.com
|
||||
criteo.com
|
||||
criteo.net
|
||||
demdex.net
|
||||
dotomi.com
|
||||
exelator.com
|
||||
eyeblaster.com
|
||||
flashtalking.com
|
||||
moat.com
|
||||
moatads.com
|
||||
mookie1.com
|
||||
pubmatic.com
|
||||
quantserve.com
|
||||
rubiconproject.com
|
||||
scorecardresearch.com
|
||||
serving-sys.com
|
||||
sharethrough.com
|
||||
smartadserver.com
|
||||
tapad.com
|
||||
turn.com
|
||||
yieldmo.com
|
||||
openx.net
|
||||
indexww.com
|
||||
lijit.com
|
||||
mathtag.com
|
||||
rlcdn.com
|
||||
bluekai.com
|
||||
krxd.net
|
||||
agkn.com
|
||||
adzerk.net
|
||||
contextweb.com
|
||||
3lift.com
|
||||
triplelift.com
|
||||
media.net
|
||||
medianet.com
|
||||
admixer.net
|
||||
revenuecat.com
|
||||
adcolony.com
|
||||
vungle.com
|
||||
unity3d.com
|
||||
unityads.unity3d.com
|
||||
applovin.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Outbrain / Taboola / Content Recommendations
|
||||
# ------------------------------------------------------------
|
||||
outbrain.com
|
||||
taboola.com
|
||||
outbrain-com.cdn.ampproject.org
|
||||
revcontent.com
|
||||
mgid.com
|
||||
zergnet.com
|
||||
content-recommendation.net
|
||||
nativo.com
|
||||
adblade.com
|
||||
content.ad
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Popup & Overlay Ad Networks
|
||||
# ------------------------------------------------------------
|
||||
popads.net
|
||||
popcash.net
|
||||
propellerads.com
|
||||
propellerpops.com
|
||||
popunder.net
|
||||
clickadu.com
|
||||
hilltopads.net
|
||||
ad-maven.com
|
||||
admaven.com
|
||||
juicyads.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# YouTube-Specific Ad Patterns (URL path matches)
|
||||
# ------------------------------------------------------------
|
||||
/pagead/
|
||||
/ptracking
|
||||
/get_midroll_
|
||||
/api/stats/ads
|
||||
/api/stats/atr
|
||||
/log_interaction
|
||||
/ad_data_204
|
||||
/generate_204
|
||||
/s/player/*/player_ias
|
||||
/youtubei/v1/log_event?alt=
|
||||
/youtubei/v1/player/ad_break
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# YouTube Ad Regex Patterns
|
||||
# ------------------------------------------------------------
|
||||
/googlevideo\.com\/videoplayback\?.*&ctier=L&/
|
||||
/googlevideo\.com\/videoplayback\?.*&oad=/
|
||||
/youtube\.com\/api\/stats\/ads/
|
||||
/youtube\.com\/pagead\//
|
||||
/youtube\.com\/ptracking/
|
||||
/youtube\.com\/get_midroll_/
|
||||
/doubleclick\.net\/pagead\//
|
||||
/youtube\.com\/sw\.js_data/
|
||||
/youtube\.com\/api\/stats\/qoe\?.*adformat/
|
||||
/youtube\.com\/youtubei\/v1\/log_event\?alt=/
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# YouTube Tracking & Telemetry
|
||||
# ------------------------------------------------------------
|
||||
s.youtube.com
|
||||
video-stats.l.google.com
|
||||
www.youtube.com/api/stats/
|
||||
yt3.ggpht.com/a/default-user
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Facebook / Meta Tracking
|
||||
# ------------------------------------------------------------
|
||||
facebook.net
|
||||
connect.facebook.net
|
||||
pixel.facebook.com
|
||||
www.facebook.com/tr
|
||||
an.facebook.com
|
||||
staticxx.facebook.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Twitter / X Tracking
|
||||
# ------------------------------------------------------------
|
||||
analytics.twitter.com
|
||||
t.co
|
||||
ads-twitter.com
|
||||
ads-api.twitter.com
|
||||
static.ads-twitter.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Microsoft Tracking
|
||||
# ------------------------------------------------------------
|
||||
bat.bing.com
|
||||
clarity.ms
|
||||
c.bing.com
|
||||
c.msn.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Analytics & Session Recording
|
||||
# ------------------------------------------------------------
|
||||
hotjar.com
|
||||
mouseflow.com
|
||||
fullstory.com
|
||||
heapanalytics.com
|
||||
mixpanel.com
|
||||
segment.com
|
||||
segment.io
|
||||
amplitude.com
|
||||
cdn.amplitude.com
|
||||
api.amplitude.com
|
||||
inspectlet.com
|
||||
luckyorange.com
|
||||
crazyegg.com
|
||||
optimizely.com
|
||||
cdn.optimizely.com
|
||||
newrelic.com
|
||||
js-agent.newrelic.com
|
||||
bam.nr-data.net
|
||||
sentry.io
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# General Tracking & Fingerprinting
|
||||
# ------------------------------------------------------------
|
||||
liadm.com
|
||||
ipredictive.com
|
||||
bam-cell.nr-data.net
|
||||
cdn.ravenjs.com
|
||||
cdn.mxpnl.com
|
||||
cdn.heapanalytics.com
|
||||
static.hotjar.com
|
||||
script.hotjar.com
|
||||
vars.hotjar.com
|
||||
identify.hotjar.com
|
||||
surveys.hotjar.com
|
||||
in.hotjar.com
|
||||
sb.scorecardresearch.com
|
||||
imrworldwide.com
|
||||
sb.voicefive.com
|
||||
c.amazon-adsystem.com
|
||||
s.amazon-adsystem.com
|
||||
z-na.amazon-adsystem.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Ad-related CDN / Serving Domains
|
||||
# ------------------------------------------------------------
|
||||
cdn.doubleverify.com
|
||||
tps.doubleverify.com
|
||||
cdn.adsafeprotected.com
|
||||
fw.adsafeprotected.com
|
||||
static.adsafeprotected.com
|
||||
pixel.adsafeprotected.com
|
||||
dt.adsafeprotected.com
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Miscellaneous Ad / Tracking Domains
|
||||
# ------------------------------------------------------------
|
||||
adroll.com
|
||||
d.adroll.com
|
||||
s.adroll.com
|
||||
ib.adnxs.com
|
||||
secure.adnxs.com
|
||||
acdn.adnxs.com
|
||||
cdn.adnxs.com
|
||||
m.adnxs.com
|
||||
nym1-ib.adnxs.com
|
||||
bttrack.com
|
||||
clicktale.net
|
||||
zemanta.com
|
||||
teads.tv
|
||||
adskeeper.co.uk
|
||||
adf.ly
|
||||
sh.st
|
||||
linkbucks.com
|
||||
bc.vc
|
||||
ouo.io
|
||||
shorte.st
|
||||
adfoc.us
|
||||
coin-hive.com
|
||||
coinhive.com
|
||||
authedmine.com
|
||||
crypto-loot.com
|
||||
23
electron/forge.config.js
Normal file
23
electron/forge.config.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
packagerConfig: {
|
||||
name: 'Gaming Hub',
|
||||
executableName: 'gaming-hub',
|
||||
icon: path.join(__dirname, 'assets', 'icon'),
|
||||
asar: true,
|
||||
},
|
||||
makers: [
|
||||
{
|
||||
name: '@electron-forge/maker-squirrel',
|
||||
config: {
|
||||
name: 'gaming-hub-desktop',
|
||||
setupIcon: path.join(__dirname, 'assets', 'icon.ico'),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '@electron-forge/maker-zip',
|
||||
platforms: ['win32', 'linux', 'darwin'],
|
||||
},
|
||||
],
|
||||
};
|
||||
68
electron/main.js
Normal file
68
electron/main.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
const { app, BrowserWindow, session, shell } = require('electron');
|
||||
const path = require('path');
|
||||
const { setupAdBlocker } = require('./ad-blocker');
|
||||
|
||||
// Handle Squirrel events (Windows installer)
|
||||
try {
|
||||
if (require('electron-squirrel-startup')) app.quit();
|
||||
} catch {
|
||||
// electron-squirrel-startup not installed, skip
|
||||
}
|
||||
|
||||
const HUB_URL = process.env.GAMING_HUB_URL || 'https://hub.daddelolymp.de';
|
||||
|
||||
let mainWindow;
|
||||
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1400,
|
||||
height: 900,
|
||||
minWidth: 900,
|
||||
minHeight: 600,
|
||||
title: 'Gaming Hub',
|
||||
icon: path.join(__dirname, 'assets', 'icon.png'),
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
},
|
||||
backgroundColor: '#1a1b1e',
|
||||
autoHideMenuBar: true,
|
||||
});
|
||||
|
||||
// Setup ad blocker BEFORE loading URL
|
||||
setupAdBlocker(session.defaultSession);
|
||||
|
||||
// Custom User-Agent to identify Electron app
|
||||
const currentUA = mainWindow.webContents.getUserAgent();
|
||||
mainWindow.webContents.setUserAgent(currentUA + ' GamingHubDesktop/1.0.0');
|
||||
|
||||
mainWindow.loadURL(HUB_URL);
|
||||
|
||||
// Open external links in default browser
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (!url.startsWith(HUB_URL)) {
|
||||
shell.openExternal(url);
|
||||
return { action: 'deny' };
|
||||
}
|
||||
return { action: 'allow' };
|
||||
});
|
||||
|
||||
// Handle navigation to external URLs
|
||||
mainWindow.webContents.on('will-navigate', (event, url) => {
|
||||
if (!url.startsWith(HUB_URL)) {
|
||||
event.preventDefault();
|
||||
shell.openExternal(url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow);
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
});
|
||||
21
electron/package.json
Normal file
21
electron/package.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "gaming-hub-desktop",
|
||||
"productName": "Gaming Hub",
|
||||
"version": "1.0.0",
|
||||
"description": "Gaming Hub Desktop App mit Ad-Blocker",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
"dependencies": {
|
||||
"electron-squirrel-startup": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^33.0.0",
|
||||
"@electron-forge/cli": "^7.6.0",
|
||||
"@electron-forge/maker-squirrel": "^7.6.0",
|
||||
"@electron-forge/maker-zip": "^7.6.0"
|
||||
}
|
||||
}
|
||||
6
electron/preload.js
Normal file
6
electron/preload.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
const { contextBridge } = require('electron');
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
isElectron: true,
|
||||
version: '1.0.0',
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue