Removes invasive ads, blocks popunders/popups, restores the native context menu, and reduces unnecessary CSS/GPU work.
// ==UserScript==
// @name PMVHaven
// @namespace https://pmvhaven.com/
// @version 1.2.0
// @description Removes invasive ads, blocks popunders/popups, restores the native context menu, and reduces unnecessary CSS/GPU work.
// @match https://pmvhaven.com/*
// @match https://*.pmvhaven.com/*
// @run-at document-start
// @author Cat-Ling
// @license MIT
// @grant none
// ==/UserScript==
(function () {
'use strict';
const AD_HOST_PATTERNS = [
/(?:^|\.)s\.eunow4u\.com$/i,
/(?:^|\.)eunow4u\.com$/i,
/(?:^|\.)rndomnm\.com$/i,
/(?:^|\.)fluxion-lab88\.com$/i,
/(?:^|\.)sadbaguette\.com$/i,
/(?:^|\.)clearsky-rhythm\.com$/i,
/(?:^|\.)exacdn\.com$/i,
/(?:^|\.)happyleafmotion\.com$/i,
/(?:^|\.)realxxx\.com$/i,
/(?:^|\.)ab1n\.net$/i
];
const AD_URL_PATTERNS = [
/popunder1000\.js(?:[?#]|$)/i
];
const AD_CLASS_PATTERNS = [
/(?:^|\s)ad-link(?:\s|$)/i,
/(?:^|\s)native-ad-card(?:\s|$)/i,
/(?:^|\s)inline-scroll-banner(?:\s|$)/i,
/(?:^|\s)ad-banner(?:\s|$)/i,
/(?:^|\s)undress-ai-animated-btn(?:\s|$)/i,
/(?:^|\s)mobile-undress-ad-banner(?:\s|$)/i,
/(?:^|\s)mobile-undress-ad-container(?:\s|$)/i,
/(?:^|\s)ads-container(?:\s|$)/i,
/(?:^|\s)video-player-banner(?:\s|$)/i,
/(?:^|\s)sidebar-ad-container(?:\s|$)/i,
/(?:^|\s)sidebar-ad-wrapper(?:\s|$)/i,
/(?:^|\s)sidebar-ad-iframe(?:\s|$)/i,
/(?:^|\s)ad-content-mobile(?:\s|$)/i,
/(?:^|\s)ad-content(?:\s|$)/i
];
const getURL = (value) => {
if (!value) {
return null;
}
try {
return new URL(String(value), location.href);
} catch {
return null;
}
};
const isAdURL = (value) => {
const url = getURL(value);
if (!url) {
return false;
}
if (
AD_HOST_PATTERNS.some((pattern) =>
pattern.test(url.hostname)
)
) {
return true;
}
return AD_URL_PATTERNS.some((pattern) =>
pattern.test(url.href)
);
};
const classLooksAdRelated = (element) => {
if (!(element instanceof Element)) {
return false;
}
const className =
typeof element.className === 'string'
? element.className
: '';
return AD_CLASS_PATTERNS.some((pattern) =>
pattern.test(className)
);
};
const elementHasAdURL = (element) => {
if (!(element instanceof Element)) {
return false;
}
if (element instanceof HTMLAnchorElement) {
return isAdURL(element.href);
}
if (element instanceof HTMLIFrameElement) {
return isAdURL(element.src);
}
if (element instanceof HTMLScriptElement) {
return isAdURL(element.src);
}
return false;
};
const isAdElement = (element) => {
if (!(element instanceof Element)) {
return false;
}
if (elementHasAdURL(element)) {
return true;
}
if (classLooksAdRelated(element)) {
return true;
}
if (
element.matches(
'a[rel~="sponsored"], [data-ad], [data-advertisement]'
)
) {
return true;
}
if (
element.closest(
'.ads-container, .native-ad-card, .inline-scroll-banner, .ad-link, .ad-banner, ' +
'.undress-ai-animated-btn, .mobile-undress-ad-banner, .mobile-undress-ad-container, ' +
'.video-player-banner, .sidebar-ad-container, .sidebar-ad-wrapper, .sidebar-ad-iframe'
)
) {
return true;
}
return false;
};
const blockWindowOpen = () => {
const blockedOpen = function () {
return null;
};
try {
Object.defineProperty(blockedOpen, 'name', {
value: 'open',
configurable: true
});
} catch {}
const targets = [];
if (
typeof Window !== 'undefined' &&
Window.prototype
) {
targets.push({
object: Window.prototype,
property: 'open'
});
}
if (typeof window !== 'undefined') {
targets.push({
object: window,
property: 'open'
});
}
for (const target of targets) {
const object = target.object;
const property = target.property;
try {
const descriptor =
Object.getOwnPropertyDescriptor(
object,
property
);
if (
descriptor &&
descriptor.writable === false &&
descriptor.configurable === false
) {
continue;
}
Object.defineProperty(
object,
property,
{
value: blockedOpen,
writable: true,
configurable: true,
enumerable: descriptor
? descriptor.enumerable
: false
}
);
} catch {
try {
object[property] = blockedOpen;
} catch {}
}
}
};
const installInteractionBlocker = () => {
const eventTypes = [
'pointerdown',
'pointerup',
'pointercancel',
'touchstart',
'touchend',
'touchcancel',
'mousedown',
'mouseup',
'click',
'auxclick'
];
const block = (event) => {
const target = event.target;
if (!(target instanceof Element)) {
return;
}
const adTarget = target.closest(
'a.ad-link, a.native-ad-card, a.inline-scroll-banner, a.ad-banner, ' +
'a.undress-ai-animated-btn, a.mobile-undress-ad-banner, ' +
'iframe[src], [data-ad], [data-advertisement]'
);
if (
adTarget &&
isAdElement(adTarget)
) {
event.preventDefault();
event.stopImmediatePropagation();
event.stopPropagation();
}
};
for (const type of eventTypes) {
window.addEventListener(
type,
block,
{
capture: true,
passive: false
}
);
document.addEventListener(
type,
block,
{
capture: true,
passive: false
}
);
}
};
const patchAnchorClick = () => {
if (
typeof HTMLAnchorElement === 'undefined'
) {
return;
}
const proto = HTMLAnchorElement.prototype;
const originalClick = proto.click;
if (
typeof originalClick !== 'function' ||
originalClick.__pmvhavenPatched
) {
return;
}
const patchedClick = function (...args) {
if (isAdElement(this)) {
return undefined;
}
return originalClick.apply(this, args);
};
try {
Object.defineProperty(
patchedClick,
'__pmvhavenPatched',
{
value: true,
configurable: false
}
);
Object.defineProperty(
proto,
'click',
{
value: patchedClick,
writable: true,
configurable: true
}
);
} catch {}
};
const blockInjectedNodes = () => {
if (
typeof Node === 'undefined' ||
!Node.prototype
) {
return;
}
const methods = [
'appendChild',
'insertBefore',
'replaceChild'
];
for (const methodName of methods) {
const original =
Node.prototype[methodName];
if (
typeof original !== 'function' ||
original.__pmvhavenPatched
) {
continue;
}
const patched = function (node, ...args) {
if (node instanceof Element) {
if (
node instanceof HTMLScriptElement &&
isAdURL(node.src)
) {
try {
node.remove();
} catch {}
return node;
}
if (
node instanceof HTMLIFrameElement &&
isAdURL(node.src)
) {
try {
node.remove();
} catch {}
return node;
}
}
return original.call(
this,
node,
...args
);
};
try {
Object.defineProperty(
patched,
'__pmvhavenPatched',
{
value: true,
configurable: false
}
);
Object.defineProperty(
Node.prototype,
methodName,
{
value: patched,
writable: true,
configurable: true
}
);
} catch {}
}
};
const patchAttributeSetter = () => {
if (
typeof Element === 'undefined' ||
!Element.prototype
) {
return;
}
const originalSetAttribute =
Element.prototype.setAttribute;
if (
typeof originalSetAttribute !== 'function' ||
originalSetAttribute.__pmvhavenPatched
) {
return;
}
const patchedSetAttribute = function (
name,
value
) {
const attr =
String(name).toLowerCase();
if (
(
this instanceof HTMLScriptElement ||
this instanceof HTMLIFrameElement
) &&
attr === 'src' &&
isAdURL(value)
) {
return originalSetAttribute.call(
this,
'src',
'about:blank'
);
}
if (
this instanceof HTMLAnchorElement &&
attr === 'href' &&
isAdURL(value)
) {
originalSetAttribute.call(
this,
'href',
'#'
);
originalSetAttribute.call(
this,
'data-pmvhaven-blocked-ad',
'1'
);
return undefined;
}
return originalSetAttribute.call(
this,
name,
value
);
};
try {
Object.defineProperty(
patchedSetAttribute,
'__pmvhavenPatched',
{
value: true,
configurable: false
}
);
Object.defineProperty(
Element.prototype,
'setAttribute',
{
value: patchedSetAttribute,
writable: true,
configurable: true
}
);
} catch {}
};
const neutralizeAdElement = (element) => {
if (!(element instanceof Element)) {
return;
}
if (
element instanceof HTMLAnchorElement &&
element.hasAttribute('data-video-id') &&
!classLooksAdRelated(element)
) {
return;
}
if (!isAdElement(element)) {
return;
}
if (element instanceof HTMLAnchorElement) {
element.removeAttribute('href');
element.removeAttribute('target');
element.setAttribute(
'aria-hidden',
'true'
);
element.setAttribute(
'data-pmvhaven-blocked-ad',
'1'
);
}
if (
element instanceof HTMLIFrameElement
) {
element.removeAttribute('src');
element.setAttribute(
'sandbox',
''
);
element.setAttribute(
'data-pmvhaven-blocked-ad',
'1'
);
}
if (
element instanceof HTMLScriptElement
) {
element.remove();
return;
}
try {
element.remove();
} catch {}
};
const purgeAds = (root = document) => {
if (
!root ||
!root.querySelectorAll
) {
return;
}
const selectors = [
'script#popmagicldr',
'script[src*="popunder1000.js"]',
'script[src*="exacdn.com"]',
'script[src*="eunow4u.com"]',
'script[src*="rndomnm.com"]',
'script[src*="sadbaguette.com"]',
'script[src*="clearsky-rhythm.com"]',
'script[src*="happyleafmotion.com"]',
'iframe[src*="sadbaguette.com"]',
'iframe[src*="clearsky-rhythm.com"]',
'iframe[src*="exacdn.com"]',
'iframe[src*="happyleafmotion.com"]',
'iframe[src*="fluxion-lab88.com"]',
'a[href*="s.eunow4u.com"]',
'a[href*="eunow4u.com"]',
'a[href*="rr.rndomnm.com"]',
'a[href*="fluxion-lab88.com"]',
'a[href*="v6.realxxx.com"]',
'.ads-container',
'a.ad-link',
'a.native-ad-card',
'a.inline-scroll-banner',
'a.ad-banner',
'a.undress-ai-animated-btn',
'a.mobile-undress-ad-banner',
'.mobile-undress-ad-container',
'.video-player-banner',
'.sidebar-ad-container',
'.sidebar-ad-wrapper',
'.sidebar-ad-iframe'
];
for (
const element of root.querySelectorAll(
selectors.join(',')
)
) {
neutralizeAdElement(element);
}
};
const installDOMObserver = () => {
const observer =
new MutationObserver(
(mutations) => {
for (
const mutation of mutations
) {
if (
mutation.type ===
'attributes'
) {
const target =
mutation.target;
if (
target instanceof Element
) {
if (
target instanceof
HTMLAnchorElement
) {
const href =
target.getAttribute(
'href'
);
if (
isAdURL(href) ||
classLooksAdRelated(
target
)
) {
neutralizeAdElement(
target
);
}
} else if (
target instanceof
HTMLIFrameElement ||
target instanceof
HTMLScriptElement
) {
if (
isAdURL(
target.getAttribute(
'src'
)
)
) {
neutralizeAdElement(
target
);
}
}
}
continue;
}
for (
const node of
mutation.addedNodes
) {
if (
!(node instanceof Element)
) {
continue;
}
neutralizeAdElement(node);
if (
node.querySelectorAll
) {
purgeAds(node);
}
}
}
}
);
observer.observe(
document,
{
childList: true,
subtree: true,
attributes: true,
attributeFilter: [
'href',
'src',
'target',
'class',
'id'
]
}
);
};
const restoreNativeContextMenu = () => {
const handleContextMenu = (event) => {
event.stopImmediatePropagation();
};
window.addEventListener(
'contextmenu',
handleContextMenu,
true
);
document.addEventListener(
'contextmenu',
handleContextMenu,
true
);
const preventSiteOverrides = (object) => {
try {
Object.defineProperty(
object,
'oncontextmenu',
{
get: () => null,
set: () => true,
configurable: true,
enumerable: true
}
);
} catch {}
};
preventSiteOverrides(window);
preventSiteOverrides(document);
if (
typeof Document !== 'undefined' &&
Document.prototype
) {
preventSiteOverrides(
Document.prototype
);
}
if (
typeof HTMLElement !== 'undefined' &&
HTMLElement.prototype
) {
preventSiteOverrides(
HTMLElement.prototype
);
}
};
const injectOptimizations = () => {
const adSelectors = [
'a.native-ad-card:not([data-video-id])',
'a.ad-link:not([data-video-id]):not([href^="/video/"])',
'a[rel*="sponsored"]:not([data-video-id]):not([href^="/video/"])',
'a.inline-scroll-banner',
'a.undress-ai-animated-btn',
'.mobile-undress-ad-container',
'.mobile-undress-ad-banner',
'.mobile-header-ad',
'.ads-container',
'.video-player-banner',
'.sidebar-ad-container',
'.sidebar-ad-wrapper',
'.sidebar-ad-iframe',
'.ad-banner',
'.ad-content-mobile',
'iframe[src*="sadbaguette.com"]',
'iframe[src*="clearsky-rhythm.com"]',
'iframe[src*="exacdn.com"]',
'iframe[src*="happyleafmotion.com"]',
'iframe[src*="fluxion-lab88.com"]',
'[data-reka-context-menu-content]',
'[data-radix-context-menu-content]'
];
const css = `
${adSelectors.join(',\\n')} {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
pointer-events: none !important;
user-select: none !important;
}
div:has(> .grid[class*="cols-4-1500"]),
div:has(> .grid[class*="cols-3-1200"]) {
display: grid !important;
grid-template-columns:
repeat(1, minmax(0, 1fr)) !important;
gap: 1rem !important;
}
@media (min-width: 640px) {
div:has(> .grid[class*="cols-4-1500"]),
div:has(> .grid[class*="cols-3-1200"]) {
grid-template-columns:
repeat(2, minmax(0, 1fr)) !important;
}
}
@media (min-width: 1200px) and (max-width: 1499.98px) {
div:has(> .grid[class*="cols-4-1500"]),
div:has(> .grid[class*="cols-3-1200"]) {
grid-template-columns:
repeat(3, minmax(0, 1fr)) !important;
}
}
@media (min-width: 1500px) {
div:has(> .grid[class*="cols-4-1500"]),
div:has(> .grid[class*="cols-3-1200"]) {
grid-template-columns:
repeat(4, minmax(0, 1fr)) !important;
}
}
div:has(> .grid[class*="cols-4-1500"]) > .grid,
div:has(> .grid[class*="cols-3-1200"]) > .grid {
display: contents !important;
contain: none !important;
}
div:has(> .grid[class*="cols-4-1500"]) > div.my-6,
div:has(> .grid[class*="cols-3-1200"]) > div.my-6,
div.my-6:not(:has([data-video-id])) {
display: none !important;
margin: 0 !important;
height: 0 !important;
}
.videos-grid-tailwind > *,
.grid > a,
.grid > * {
transform: none !important;
will-change: auto !important;
backface-visibility: visible !important;
}
[class*="backdrop-blur"],
.backdrop-blur-sm,
.backdrop-blur-md,
.backdrop-blur {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
body.loaded * {
transition-property: none !important;
}
a[data-video-id],
button,
input,
.transition-colors {
transition-property:
color,
background-color,
border-color !important;
transition-duration: 0.15s !important;
}
.route-loading-bar,
.ssr-loading-bar,
.loading-bar,
[class*="loading-bar"] {
display: none !important;
animation: none !important;
}
.ongoing-event-banner__icon {
animation: none !important;
}
`;
const inject = () => {
if (
document.getElementById(
'pmvhaven-optimizer-styles'
)
) {
return;
}
const style =
document.createElement(
'style'
);
style.id =
'pmvhaven-optimizer-styles';
style.textContent = css;
(
document.head ||
document.documentElement
).appendChild(style);
};
if (
document.head ||
document.documentElement
) {
inject();
} else {
document.addEventListener(
'DOMContentLoaded',
inject,
{ once: true }
);
}
};
blockWindowOpen();
blockInjectedNodes();
patchAttributeSetter();
patchAnchorClick();
restoreNativeContextMenu();
installInteractionBlocker();
injectOptimizations();
installDOMObserver();
purgeAds();
document.addEventListener(
'DOMContentLoaded',
() => {
purgeAds();
injectOptimizations();
},
{ once: true }
);
})();