- // ==UserScript==
- // @run-at document-start
- // @name MissAV去广告、影院模式
- // @description missav 广告拦截与界面优化
- // @icon https://static.missav.com/img/favicon.png
- // @namespace loadingi.local
- // @version 3.1.1
- // @author ch
- // @match https://missav.ai/*
- // @match https://missav.ws/*
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant unsafeWindow
- // @grant GM_xmlhttpRequest
- // @compatible chrome
- // @compatible firefox
- // @compatible edge
- // @license GPL-3.0-only
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- // 统一管理所有选择器
- const SELECTORS = {
- // 样式相关选择器
- STYLES: {
- PROGRESS_BUTTONS: '.isolate.inline-flex.rounded-md.shadow-sm',
- PROGRESS_CONTROL: '.sm\\:hidden',
- LOOP_BUTTON: '.sm\\:ml-6 button',
- // INFO_TEXT: '.mb-1.text-secondary.break-all.line-clamp-2',
- // ASPECT_RATIO: '.aspect-w-16.aspect-h-9',
- PLAYER_CONTAINER: 'div.relative.-mx-4.sm\\:m-0.-mt-6',
- // VIDEO_WRAPPER: '.aspect-w-16.aspect-h-9.relative'
- },
- // 广告相关选择器
- ADS: {
- SCRIPTS: [
- "script[src*='app.1aad5686.js']",
- "script[src*='inpage.push.js']",
- "script[src*='hartattenuate.com']",
- "script[src*='ads']",
- "script[src*='pop']",
- "script[src*='banner']"
- ],
- ELEMENTS: [
- 'div.sm\\:container.mx-auto.mb-5.px-4',
- 'ul.mb-4.list-none.text-nord14.grid.grid-cols-2.gap-2',
- // class="relative ml-4" 无聊的东西 myavlive 之类的
- 'div.relative.ml-4',
- 'div.root--ujvuu', // 隐藏底部右下角浮窗广告
- 'div.under_player',
- 'div.space-y-5.mb-5',
- 'div[class^="rootContent--"]',
- 'div[class^="fixed right-2 bottom-2"]',
- 'div[class^="space-y-6 mb-6"]',
- 'div.space-y-2.mb-4.ml-4.list-disc.text-nord14',
- 'div[id*="ads"]',
- 'div[id*="banner"]',
- 'div[class*="ads"]',
- 'div[class*="banner"]',
- '.ad-container',
- '#ad-container'
- ],
- SCRIPT_PATTERNS: [
- 'htmlAds',
- 'popAds',
- 'bannerAds',
- 'adsConfig'
- ]
- },
- THEATER: {
- PLAYER_CONTAINER: 'body > div:nth-child(3) > div.sm\\:container.mx-auto.px-4.content-without-search.pb-12 > div > div.flex-1.order-first > div:nth-child(2) > div.relative.-mx-4.sm\\:m-0.-mt-6',
- PLAYER_WRAPPER: '.aspect-w-16.aspect-h-9',
- VIDEO_ELEMENT: 'video#player',
- PROGRESS: 'div.sm\\:hidden.flex.justify-between.-mx-4.px-4.pt-3.pb-1.bg-black',
- AB_LOOP: 'div.flex.items-center.flex-nowrap.leading-5',
- AB_LOOP_CONTROLS: '.theater-controls-abloop'
- }
- };
-
- // 添加统一的按钮样式常量
- const BUTTON_STYLES = {
- BASE: {
- backgroundColor: '#222',
- borderRadius: '15px',
- borderColor: 'black',
- borderWidth: '1px',
- color: 'burlywood',
- cursor: 'pointer',
- transition: 'all 0.3s ease',
- outline: 'none',
- minWidth: '80px',
- padding: '2px 4px',
- marginBottom: '10px',
-
- },
- HOVER: {
- backgroundColor: '#333'
- }
- };
-
- // 创建统一的按钮工厂函数
- function createStyledButton(text, onClick) {
- const button = document.createElement('button');
- Object.assign(button.style, BUTTON_STYLES.BASE);
- button.innerText = text;
- button.addEventListener('mouseover', () => Object.assign(button.style, BUTTON_STYLES.HOVER));
- button.addEventListener('mouseout', () => Object.assign(button.style, { backgroundColor: BUTTON_STYLES.BASE.backgroundColor }));
- button.addEventListener('click', onClick);
- return button;
- }
-
- // 统一的样式更新函数
- function updateStyles() {
- // 使用更高效的选择器
- const styleUpdates = [
- {
- selector: SELECTORS.STYLES.PROGRESS_BUTTONS,
- styles: {
- background: 'rgba(85, 35, 49, 0.37)'
- }
- },
- {
- selector: SELECTORS.STYLES.PROGRESS_CONTROL,
- styles: {
- display: 'flex',
- visibility: 'visible',
- opacity: '1'
- }
- },
- {
- selector: SELECTORS.STYLES.LOOP_BUTTON,
- styles: { borderWidth: '0px' }
- }
- ];
-
- styleUpdates.forEach(({selector, styles}) => {
- document.querySelectorAll(selector).forEach(el => {
- Object.assign(el.style, styles);
- });
- });
-
- // 设置背景
- document.body.style.backgroundColor = 'black';
- }
-
- // 优化的广告拦截函数
- function blockAds() {
- // 合并所有选择器为一个字符串
- const allSelectors = [
- ...SELECTORS.ADS.SCRIPTS,
- ...SELECTORS.ADS.ELEMENTS
- ].join(',');
-
- // 一次性查询所有需要删除的元素
- document.querySelectorAll(allSelectors).forEach(el => el?.remove());
-
- // 优化 iframe 移除
- const iframes = document.getElementsByTagName('iframe');
- Array.from(iframes).forEach(iframe => iframe.remove());
-
- // 优化脚本检查
- const scriptPattern = new RegExp(SELECTORS.ADS.SCRIPT_PATTERNS.join('|'));
- document.querySelectorAll('script').forEach(script => {
- if (scriptPattern.test(script.innerText)) {
- script.remove();
- }
- });
- }
-
- // 优化的播放器设置函数
- function setupPlayer() {
- // 移除所有带有 @click="pop()" 的元素的点击事件
- document.querySelectorAll('[\\@click="pop()"]').forEach(element => {
- element.removeAttribute('@click');
- });
-
- // 移除窗口失焦暂停
- const aspectElements = document.getElementsByClassName('aspect-w-16 aspect-h-9');
- if(aspectElements[11]) {
- aspectElements[11].removeAttribute('@click');
- aspectElements[11].removeAttribute('@keyup.space.window');
- }
- }
-
- // 更新影院模式样式
- function addTheaterModeStyles() {
- const style = document.createElement('style');
- style.textContent = `
- .theater-overlay {
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- background: rgba(0, 0, 0, 0.95);
- z-index: 9998;
- display: none;
- }
-
- /* 修改播放器容器样式 */
- .theater-mode-container {
- position: fixed !important;
- top: 0 !important;
- left: 0 !important;
- width: 100vw !important;
- height: 100vh !important;
- transform: none !important;
- z-index: 9999 !important;
- margin: 0 !important;
- padding: 0 !important;
- display: flex !important;
- align-items: center !important;
- justify-content: center !important;
- background: transparent !important;
- pointer-events: auto !important;
- }
-
-
- /* 修改视频包装器样式 */
- .theater-mode-container .aspect-w-16.aspect-h-9 {
- position: relative !important;
- width: 100vw !important;
- max-width: none !important;
- height: 100vh !important;
- margin: 0 auto !important;
- pointer-events: auto !important;
- }
-
- /* 修改视频元素样式 */
- .theater-mode-container video {
- position: absolute !important;
- top: 0 !important;
- left: 0 !important;
- width: 100% !important;
- height: 100% !important;
- object-fit: contain !important;
- pointer-events: auto !important;
- }
-
- /* 确保所有父容器不限制尺寸和层级 */
- .theater-mode-container * {
- max-width: none !important;
- max-height: none !important;
- pointer-events: auto !important;
- }
-
- /* 修改播放器控制栏样式 */
- .theater-mode-container .plyr__controls {
- position: fixed !important;
- bottom: 0 !important;
- left: 0 !important;
- width: 100% !important;
- z-index: 10000 !important;
- // background: rgba(254, 98, 142, 0.27) !important;
- padding: 10px !important;
- opacity: 1 !important;
- visibility: visible !important;
- display: flex !important;
- }
- /* 降低导航栏层级*/
- .fixed.z-max.w-full.bg-gradient-to-b.from-darkest {
- z-index: 1 !important;
- }
- /* 影院模式下不显示导航栏*/
- .theater-mode-container .fixed.z-max.w-full.bg-gradient-to-b.from-darkest {
- display: none !important;
- }
-
- /* 确保时间显示可见 */
- .theater-mode-container .plyr__time {
- display: inline-block !important;
- color: white !important;
- opacity: 1 !important;
- visibility: visible !important;
- }
-
- /* 控制条样式 */
- .theater-controls-progress {
- position: fixed !important;
- bottom: 104px !important;
- z-index: 10000 !important;
- // background: rgba(254, 98, 142, 0.27) !important;
- background: transparent !important;
- padding: 10px !important;
- width: 100% !important;
- max-width: none !important;
- pointer-events: auto !important;
- }
-
- .theater-controls-abloop {
- position: fixed !important;
- bottom: 52px !important;
- left: 0px !important;
- width: 100% !important;
- z-index: 10000 !important;
- // background: rgba(254, 98, 142, 0.27) !important;
- padding: 10px !important;
- pointer-events: auto !important;
- }
-
- /* 添加音量控制器宽度设置 */
- .theater-mode-container .plyr__controls__item.plyr__volume {
- width: 40px !important;
- }
-
- /* 隐藏指定的控制按钮 */
- .theater-mode-container .plyr__controls__item[data-plyr="rewind"],
- .theater-mode-container .plyr__controls__item[data-plyr="fast-forward"],
- .theater-mode-container .plyr__control[data-plyr="settings"],
- .theater-mode-container .plyr__controls__item[data-plyr="pip"],
- .theater-mode-container .plyr__controls__item[data-plyr="fullscreen"] {
- display: none !important;
- }
- `;
- document.head.appendChild(style);
- }
-
- // 更新 toggleTheaterMode 函数
- function toggleTheaterMode() {
- const playerContainer = document.querySelector(SELECTORS.THEATER.PLAYER_CONTAINER);
- const progress = document.querySelector(SELECTORS.THEATER.PROGRESS);
- const abLoop = document.querySelector(SELECTORS.THEATER.AB_LOOP);
-
- // 获取或创建遮罩层
- let overlay = document.querySelector('.theater-overlay');
- if (!overlay) {
- overlay = document.createElement('div');
- overlay.className = 'theater-overlay';
- document.body.appendChild(overlay);
- }
-
- const isTheaterMode = overlay.style.display === 'none' || overlay.style.display === '';
-
- // 获取按钮并更新文本
- const theaterButton = document.querySelector('.theater-mode-button');
- const abLoopButton = document.querySelector('.ab-loop-button');
-
- if (theaterButton) {
- theaterButton.innerText = isTheaterMode ? '关闭影院' : '影院模式';
- }
-
- // 控制 AB 循环按钮的显示/隐藏
- if (abLoopButton) {
- abLoopButton.style.display = isTheaterMode ? 'block' : 'none';
- }
-
- if (isTheaterMode) {
- // 进入影院模式
- overlay.style.display = 'block';
-
- if (playerContainer) {
- playerContainer.classList.add('theater-mode-container');
- // 确保所有父容器都不限制尺寸和层级
- let parent = playerContainer.parentElement;
- while (parent && parent !== document.body) {
- parent.style.setProperty('max-width', 'none', 'important');
- parent.style.setProperty('max-height', 'none', 'important');
- parent.style.setProperty('overflow', 'visible', 'important');
- parent.style.setProperty('z-index', 'auto', 'important');
- parent = parent.parentElement;
- }
- }
-
- if (progress) {
- progress.classList.add('theater-controls-progress');
- }
-
- if (abLoop) {
- abLoop.classList.add('theater-controls-abloop');
- // 默认隐藏 AB 循环控制栏
- abLoop.style.display = 'none';
- }
-
- document.addEventListener('keydown', handleEscKey);
- } else {
- // 退出影院模式
- overlay.style.display = 'none';
-
- if (playerContainer) {
- playerContainer.classList.remove('theater-mode-container');
- // 恢复父容器的原始样式
- let parent = playerContainer.parentElement;
- while (parent && parent !== document.body) {
- parent.style.removeProperty('max-width');
- parent.style.removeProperty('max-height');
- parent.style.removeProperty('overflow');
- parent.style.removeProperty('z-index');
- parent = parent.parentElement;
- }
- }
-
- if (progress) {
- progress.classList.remove('theater-controls-progress');
- }
-
- if (abLoop) {
- abLoop.classList.remove('theater-controls-abloop');
- }
-
- document.removeEventListener('keydown', handleEscKey);
- }
- }
-
- // ESC键处理函数
- function handleEscKey(e) {
- if (e.key === 'Escape') {
- toggleTheaterMode();
- }
- }
-
- // 更新浮动按钮创建函数
- function createFloatingButtons() {
- const buttonContainer = document.createElement('div');
- Object.assign(buttonContainer.style, {
- position: 'fixed',
- top: '14px',
- right: '98px',
- zIndex: '10001',
- display: 'flex',
- flexDirection: 'row', // 改为水平排列
- gap: '10px'
- });
-
- // 创建影院模式按钮
- const theaterButton = createStyledButton('影院模式', toggleTheaterMode);
- theaterButton.className = 'theater-mode-button';
- buttonContainer.appendChild(theaterButton);
-
- // 创建 AB 循环按钮(初始文本为"显示AB循环")
- const abLoopButton = createStyledButton('A/B', toggleABLoopControls);
- abLoopButton.className = 'ab-loop-button';
- abLoopButton.style.display = 'none'; // 初始隐藏
- buttonContainer.appendChild(abLoopButton);
-
- document.body.appendChild(buttonContainer);
- }
-
- // 添加防抖函数
- function debounce(func, wait) {
- let timeout;
- return function executedFunction(...args) {
- const later = () => {
- clearTimeout(timeout);
- func(...args);
- };
- clearTimeout(timeout);
- timeout = setTimeout(later, wait);
- };
- }
-
- // 优化观察者
- function initObserver() {
- const debouncedUpdate = debounce(() => {
- blockAds();
- updateStyles();
- setupPlayer();
- }, 100);
-
- const observer = new MutationObserver(debouncedUpdate);
-
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
- }
-
- // 简化清理函数
- function cleanup() {
- document.removeEventListener('keydown', handleEscKey);
- }
-
- // 添加 AB 循环控制函数
- function toggleABLoopControls() {
- const abLoopControls = document.querySelector(SELECTORS.THEATER.AB_LOOP_CONTROLS);
- const abLoopButton = document.querySelector('.ab-loop-button');
-
- if (abLoopControls) {
- const isVisible = abLoopControls.style.display !== 'none';
- abLoopControls.style.display = isVisible ? 'none' : 'flex';
-
- // 更新按钮文本,默认显示"显示AB循环"
- if (abLoopButton) {
- abLoopButton.innerText = isVisible ? 'A/B' : 'no A/B';
- }
- }
- }
-
- // 主函数
- function init() {
- updateStyles();
- blockAds();
- setupPlayer();
- addTheaterModeStyles(); // 添加影院模式样式
- createFloatingButtons();
- initObserver();
-
- }
-
- // 当 DOM 加载完成后执行初始化
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', init);
- } else {
- init();
- }
- })();