Restores native context menu, cleanly removes ads (invasive only), and eliminates heavy CSS/GPU bottlenecks on PMVHaven.
// ==UserScript==
// @name PMVHaven
// @namespace https://pmvhaven.com/
// @version 1.0.0
// @description Restores native context menu, cleanly removes ads (invasive only), and eliminates heavy CSS/GPU bottlenecks on PMVHaven.
// @match pmvcat
// @match https://*.pmvhaven.com/*
// @run-at document-start
// @author Cat-Ling
// @license MIT
// @grant none
// ==/UserScript==
(function () {
'use strict';
// 1. Restore Native Browser Context Menu
const restoreNativeContextMenu = () => {
const handleContextMenu = (e) => {
e.stopImmediatePropagation();
};
window.addEventListener('contextmenu', handleContextMenu, true);
document.addEventListener('contextmenu', handleContextMenu, true);
const preventSiteOverrides = (obj) => {
try {
Object.defineProperty(obj, '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);
}
};
// 2. High-Performance Declarative Styles (Adblock, Grid Unification, GPU/CPU Optimizations)
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-lab"]',
'[data-reka-context-menu-content]',
'[data-radix-context-menu-content]'
];
const css = `
/* === 1. Clean Ad Removal === */
${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;
}
/* === 2. Unified Grid: Fix Separate Chunk Divs & Horizontal Ad Gaps === */
/* Promote the parent wrapper of chunked video grids to the master responsive grid */
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;
}
}
/* Make chunk grid wrappers transparent so child cards flow into the parent grid */
div:has(> .grid[class*="cols-4-1500"]) > .grid,
div:has(> .grid[class*="cols-3-1200"]) > .grid {
display: contents !important;
contain: none !important;
}
/* Eliminate horizontal ad spacer divs between chunks */
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;
}
/* === 3. GPU & Compositing Layer Optimization === */
/* Remove forced translateZ and layer creation on every card */
.videos-grid-tailwind > *,
.grid > a,
.grid > * {
transform: none !important;
will-change: auto !important;
backface-visibility: visible !important;
}
/* Remove expensive backdrop-filter passes from small badge overlays */
[class*="backdrop-blur"],
.backdrop-blur-sm,
.backdrop-blur-md,
.backdrop-blur {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
/* Stop universal transition recalculations on body.loaded */
body.loaded * {
transition-property: none !important;
}
/* Re-enable scoped transitions for interactive elements */
a[data-video-id],
button,
input,
.transition-colors {
transition-property: color, background-color, border-color !important;
transition-duration: 0.15s !important;
}
/* === 4. Halt Infinite Background CPU/GPU Animations === */
.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 = () => {
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 });
}
};
// 3. Fallback Click Interceptor for Outbound Ad Links
const interceptAdClicks = () => {
const adTargetSelector = 'a.native-ad-card, a.inline-scroll-banner, a.ad-link, [class*="native-ad"], [class*="inline-scroll-banner"]';
window.addEventListener(
'click',
(e) => {
const target = e.target;
if (!(target instanceof Element)) return;
const matched = target.closest(adTargetSelector);
if (matched && !matched.hasAttribute('data-video-id')) {
e.preventDefault();
e.stopImmediatePropagation();
}
},
true
);
};
restoreNativeContextMenu();
injectOptimizations();
interceptAdClicks();
})();