- // ==UserScript==
- // @name YouTube Enchantments
- // @namespace http://tampermonkey.net/
- // @version 0.8.2
- // @description Automatically likes videos of channels you're subscribed to, scrolls down on Youtube with a toggle button, and bypasses the AdBlock ban.
- // @author JJJ
- // @match https://www.youtube.com/*
- // @exclude https://www.youtube.com/*/community
- // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @run-at document-idle
- // @noframes
- // @license MIT
- // ==/UserScript==
-
- (() => {
- 'use strict';
-
- // Add logger configuration
- const Logger = {
- styles: {
- info: 'color: #2196F3; font-weight: bold',
- warning: 'color: #FFC107; font-weight: bold',
- success: 'color: #4CAF50; font-weight: bold',
- error: 'color: #F44336; font-weight: bold'
- },
- prefix: '[YouTubeEnchantments]',
- getTimestamp() {
- return new Date().toISOString().split('T')[1].slice(0, -1);
- },
- info(msg) {
- console.log(`%c${this.prefix} ${this.getTimestamp()} - ${msg}`, this.styles.info);
- },
- warning(msg) {
- console.warn(`%c${this.prefix} ${this.getTimestamp()} - ${msg}`, this.styles.warning);
- },
- success(msg) {
- console.log(`%c${this.prefix} ${this.getTimestamp()} - ${msg}`, this.styles.success);
- },
- error(msg) {
- console.error(`%c${this.prefix} ${this.getTimestamp()} - ${msg}`, this.styles.error);
- }
- };
-
- // Polyfill for Edge if necessary
- if (!window.Blob || !window.URL || !window.Worker) {
- Logger.warning('Browser compatibility features missing');
- return;
- }
-
- // Inject the YouTube IFrame API script with error handling
- function injectYouTubeAPI() {
- return new Promise((resolve, reject) => {
- const script = document.createElement('script');
- script.src = 'https://www.youtube.com/iframe_api';
- script.onload = resolve;
- script.onerror = reject;
- document.head.appendChild(script);
- });
- }
-
- // Updated constants
- const SELECTORS = {
- PLAYER: '#movie_player',
- SUBSCRIBE_BUTTON: '#subscribe-button > ytd-subscribe-button-renderer, ytd-reel-player-overlay-renderer #subscribe-button, tp-yt-paper-button[subscribed]',
- LIKE_BUTTON: 'ytd-menu-renderer button[aria-pressed][aria-label*="like"], like-button-view-model button[aria-pressed]',
- DISLIKE_BUTTON: 'ytd-menu-renderer button[aria-pressed][aria-label*="dislike"], dislike-button-view-model button[aria-pressed]',
- PLAYER_CONTAINER: '#player-container-outer',
- ERROR_SCREEN: '#error-screen',
- PLAYABILITY_ERROR: '.yt-playability-error-supported-renderers',
- LIVE_BADGE: '.ytp-live-badge',
- GAME_SECTION: 'ytd-rich-section-renderer, div#dismissible.style-scope.ytd-rich-shelf-renderer'
- };
-
- const CONSTANTS = {
- IFRAME_ID: 'adblock-bypass-player',
- STORAGE_KEY: 'youtubeEnchantmentsSettings',
- DELAY: 300, // Increased delay for Edge
- MAX_TRIES: 150, // Increased max tries
- DUPLICATE_CHECK_INTERVAL: 7000, // Increased interval
- GAME_CHECK_INTERVAL: 2000 // Interval to check for game sections
- };
-
- const defaultSettings = {
- autoLikeEnabled: true,
- autoLikeLiveStreams: false,
- likeIfNotSubscribed: false,
- watchThreshold: 0,
- checkFrequency: 5000,
- adBlockBypassEnabled: false,
- scrollSpeed: 50,
- removeGamesEnabled: true
- };
-
- let settings = loadSettings();
- const autoLikedVideoIds = new Set();
- let isScrolling = false;
- let scrollInterval;
- let currentPageUrl = window.location.href;
- let tries = 0;
-
- const worker = createWorker();
-
- const urlUtils = {
- extractParams(url) {
- try {
- const params = new URL(url).searchParams;
- return {
- videoId: params.get('v'),
- playlistId: params.get('list'),
- index: params.get('index')
- };
- } catch (e) {
- console.error('Failed to extract URL params:', e);
- return {};
- }
- },
-
- getTimestampFromUrl(url) {
- try {
- const timestamp = new URL(url).searchParams.get('t');
- if (timestamp) {
- const timeArray = timestamp.split(/h|m|s/).map(Number);
- const timeInSeconds = timeArray.reduce((acc, time, index) =>
- acc + time * Math.pow(60, 2 - index), 0);
- return `&start=${timeInSeconds}`;
- }
- } catch (e) {
- console.error('Failed to extract timestamp:', e);
- }
- return '';
- }
- };
-
- let player;
-
- // Updated PlayerManager
- const playerManager = {
- async initPlayer() {
- try {
- await injectYouTubeAPI();
- const iframe = document.getElementById(CONSTANTS.IFRAME_ID);
- if (iframe) {
- player = new YT.Player(CONSTANTS.IFRAME_ID, {
- events: {
- 'onReady': this.onPlayerReady.bind(this),
- 'onStateChange': this.onPlayerStateChange.bind(this),
- 'onError': (event) => {
- Logger.error(`Player error: ${event.data}`);
- }
- }
- });
- }
- } catch (error) {
- Logger.error(`Failed to initialize player: ${error}`);
- }
- },
-
- onPlayerReady(event) {
- Logger.info('Player is ready');
- },
-
- onPlayerStateChange(event) {
- if (event.data === YT.PlayerState.AD_STARTED) {
- Logger.info('Ad is playing, allowing ad to complete.');
- } else if (event.data === YT.PlayerState.ENDED || event.data === YT.PlayerState.PLAYING) {
- Logger.info('Video is playing, ensuring it is tracked in history.');
- }
- },
-
- createIframe(url) {
- try {
- const { videoId, playlistId, index } = urlUtils.extractParams(url);
- if (!videoId) return null;
-
- const iframe = document.createElement('iframe');
- const commonArgs = 'autoplay=1&modestbranding=1&enablejsapi=1&origin=' + encodeURIComponent(window.location.origin);
- const embedUrl = playlistId
- ? `https://www.youtube.com/embed/${videoId}?${commonArgs}&list=${playlistId}&index=${index}`
- : `https://www.youtube.com/embed/${videoId}?${commonArgs}${urlUtils.getTimestampFromUrl(url)}`;
-
- this.setIframeAttributes(iframe, embedUrl);
- return iframe;
- } catch (error) {
- Logger.error(`Failed to create iframe: ${error}`);
- return null;
- }
- },
-
- setIframeAttributes(iframe, url) {
- iframe.id = CONSTANTS.IFRAME_ID;
- iframe.src = url;
- iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share';
- iframe.allowFullscreen = true;
- iframe.style.cssText = 'height:100%; width:calc(100% - 240px); border:none; border-radius:12px; position:relative; left:240px;';
- },
-
- replacePlayer(url) {
- const playerContainer = document.querySelector(SELECTORS.ERROR_SCREEN);
- if (!playerContainer) return;
-
- let iframe = document.getElementById(CONSTANTS.IFRAME_ID);
- if (iframe) {
- this.setIframeAttributes(iframe, url);
- } else {
- iframe = this.createIframe(url);
- if (iframe) {
- playerContainer.appendChild(iframe);
- this.initPlayer();
- }
- }
- // Ensure the iframe is on top of the player container
- this.bringToFront(CONSTANTS.IFRAME_ID);
- this.addScrollListener();
- },
-
- bringToFront(elementId) {
- const element = document.getElementById(elementId);
- if (element) {
- const maxZIndex = Math.max(
- ...Array.from(document.querySelectorAll('*'))
- .map(e => parseInt(window.getComputedStyle(e).zIndex) || 0)
- );
- element.style.zIndex = maxZIndex + 1;
- }
- },
-
- removeDuplicates() {
- const iframes = document.querySelectorAll(`#${CONSTANTS.IFRAME_ID}`);
- if (iframes.length > 1) {
- Array.from(iframes).slice(1).forEach(iframe => iframe.remove());
- }
- },
-
- addScrollListener() {
- window.addEventListener('scroll', this.handleScroll);
- },
-
- handleScroll() {
- const iframe = document.getElementById(CONSTANTS.IFRAME_ID);
- if (!iframe) return;
-
- const playerContainer = document.querySelector(SELECTORS.ERROR_SCREEN);
- if (!playerContainer) return;
-
- const rect = playerContainer.getBoundingClientRect();
- if (rect.top < 0) {
- iframe.style.position = 'fixed';
- iframe.style.top = '0';
- iframe.style.left = '240px';
- iframe.style.width = 'calc(100% - 240px)';
- iframe.style.height = 'calc(100vh - 56px)'; // Adjust height as needed
- } else {
- iframe.style.position = 'relative';
- iframe.style.top = '0';
- iframe.style.left = '240px';
- iframe.style.width = 'calc(100% - 240px)';
- iframe.style.height = '100%';
- }
- }
- };
-
- // Updated worker with error handling
- function createWorker() {
- try {
- const workerBlob = new Blob([`
- let checkInterval;
- self.onmessage = function(e) {
- try {
- if (e.data.type === 'startCheck') {
- if (checkInterval) clearInterval(checkInterval);
- checkInterval = setInterval(() => {
- self.postMessage({ type: 'check' });
- }, e.data.checkFrequency);
- } else if (e.data.type === 'stopCheck') {
- clearInterval(checkInterval);
- }
- } catch (error) {
- self.postMessage({ type: 'error', error: error.message });
- }
- };
- `], { type: 'text/javascript' });
-
- const worker = new Worker(URL.createObjectURL(workerBlob));
- worker.onerror = function (error) {
- Logger.error(`Worker error: ${error}`);
- };
- return worker;
- } catch (error) {
- Logger.error(`Failed to create worker: ${error}`);
- return null;
- }
- }
-
- function loadSettings() {
- const savedSettings = GM_getValue(CONSTANTS.STORAGE_KEY, {});
- return Object.keys(defaultSettings).reduce((acc, key) => {
- acc[key] = key in savedSettings ? savedSettings[key] : defaultSettings[key];
- return acc;
- }, {});
- }
-
- function saveSettings() {
- GM_setValue(CONSTANTS.STORAGE_KEY, settings);
- }
-
- function createSettingsMenu() {
- GM_registerMenuCommand('YouTube Enchantments Settings', showSettingsDialog);
- }
-
- function showSettingsDialog() {
- let dialog = document.getElementById('youtube-enchantments-settings');
- if (!dialog) {
- dialog = createSettingsDialog();
- document.body.appendChild(dialog);
- }
- dialog.style.display = 'block';
- }
-
- function createSettingsDialog() {
- const dialog = document.createElement('div');
- dialog.id = 'youtube-enchantments-settings';
-
- const dialogHTML = `
- <div class="dpe-dialog">
- <h3>YouTube Enchantments</h3>
- ${createToggle('autoLikeEnabled', 'Auto Like', 'Automatically like videos of subscribed channels')}
- ${createToggle('autoLikeLiveStreams', 'Like Live Streams', 'Include live streams in auto-like feature')}
- ${createToggle('likeIfNotSubscribed', 'Like All Videos', 'Like videos even if not subscribed')}
- ${createToggle('adBlockBypassEnabled', 'AdBlock Bypass', 'Bypass AdBlock detection')}
- ${createToggle('removeGamesEnabled', 'Remove Games', 'Hide game sections from YouTube homepage')}
- <div class="dpe-slider-container" title="Percentage of video to watch before liking">
- <label for="watchThreshold">Watch Threshold</label>
- <input type="range" id="watchThreshold" min="0" max="100" step="10"
- value="${settings.watchThreshold}">
- <span id="watchThresholdValue">${settings.watchThreshold}%</span>
- </div>
- <div class="dpe-slider-container" title="Speed of auto-scroll (pixels per interval)">
- <label for="scrollSpeed">Scroll Speed</label>
- <input type="range" id="scrollSpeed" data-setting="scrollSpeed" min="10" max="100" step="5"
- value="${settings.scrollSpeed}">
- <span id="scrollSpeedValue">${settings.scrollSpeed}px</span>
- </div>
- <div class="dpe-button-container">
- <button id="saveSettingsButton" class="dpe-button dpe-button-save">Save</button>
- <button id="closeSettingsButton" class="dpe-button dpe-button-cancel">Cancel</button>
- </div>
- </div>
- `;
-
- const styleSheet = `
- <style>
- .dpe-dialog {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: #030d22;
- border: 1px solid #2a2945;
- border-radius: 12px;
- padding: 24px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
- z-index: 9999;
- color: #ffffff;
- width: 320px;
- font-family: 'Roboto', Arial, sans-serif;
- }
- .dpe-dialog h3 {
- margin-top: 0;
- font-size: 1.8em;
- text-align: center;
- margin-bottom: 24px;
- color: #ffffff;
- font-weight: 700;
- }
- .dpe-toggle-container {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- padding: 8px;
- border-radius: 8px;
- background: #15132a;
- transition: background-color 0.2s;
- }
- .dpe-toggle-container:hover {
- background: #1a1832;
- }
- .dpe-toggle-label {
- flex-grow: 1;
- color: #ffffff;
- font-size: 1.1em;
- font-weight: 600;
- margin-left: 12px;
- }
- .dpe-toggle {
- position: relative;
- display: inline-block;
- width: 46px;
- height: 24px;
- }
- .dpe-toggle input {
- position: absolute;
- width: 100%;
- height: 100%;
- opacity: 0;
- cursor: pointer;
- margin: 0;
- }
- .dpe-toggle-slider {
- position: absolute;
- cursor: pointer;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: #2a2945;
- transition: .3s;
- border-radius: 24px;
- }
- .dpe-toggle-slider:before {
- position: absolute;
- content: "";
- height: 18px;
- width: 18px;
- left: 3px;
- bottom: 3px;
- background-color: #ffffff;
- transition: .3s;
- border-radius: 50%;
- }
- .dpe-toggle input:checked + .dpe-toggle-slider {
- background-color: #cc0000;
- }
- .dpe-toggle input:checked + .dpe-toggle-slider:before {
- transform: translateX(22px);
- }
- .dpe-slider-container {
- margin: 24px 0;
- padding: 12px;
- background: #15132a;
- border-radius: 8px;
- }
- .dpe-slider-container label {
- display: block;
- margin-bottom: 8px;
- color: #ffffff;
- font-size: 1.1em;
- font-weight: 600;
- }
- .dpe-slider-container input[type="range"] {
- width: 100%;
- margin: 8px 0;
- height: 4px;
- background: #2a2945;
- border-radius: 2px;
- -webkit-appearance: none;
- }
- .dpe-slider-container input[type="range"]::-webkit-slider-thumb {
- -webkit-appearance: none;
- width: 16px;
- height: 16px;
- background: #cc0000;
- border-radius: 50%;
- cursor: pointer;
- transition: background-color 0.2s;
- }
- .dpe-slider-container input[type="range"]::-webkit-slider-thumb:hover {
- background: #990000;
- }
- .dpe-button-container {
- display: flex;
- justify-content: space-between;
- margin-top: 24px;
- gap: 12px;
- }
- .dpe-button {
- padding: 10px 20px;
- border: none;
- border-radius: 6px;
- cursor: pointer;
- font-size: 1.1em;
- font-weight: 600;
- transition: all 0.2s;
- flex: 1;
- }
- .dpe-button-save {
- background-color: #cc0000;
- color: white;
- }
- .dpe-button-save:hover {
- background-color: #990000;
- transform: translateY(-1px);
- }
- .dpe-button-cancel {
- background-color: #15132a;
- color: white;
- border: 1px solid #2a2945;
- }
- .dpe-button-cancel:hover {
- background-color: #1a1832;
- transform: translateY(-1px);
- }
- </style>
- `;
-
- dialog.innerHTML = styleSheet + dialogHTML;
-
- // Add event listeners
- dialog.querySelector('#saveSettingsButton').addEventListener('click', () => {
- saveSettings();
- hideSettingsDialog();
- });
-
- dialog.querySelector('#closeSettingsButton').addEventListener('click', hideSettingsDialog);
-
- dialog.querySelectorAll('.dpe-toggle input').forEach(toggle => {
- toggle.addEventListener('change', handleSettingChange);
- });
-
- dialog.querySelector('#watchThreshold').addEventListener('input', handleSliderInput);
- dialog.querySelector('#scrollSpeed').addEventListener('input', handleSliderInput);
-
- return dialog;
- }
-
- function createToggle(id, label, title) {
- return `
- <div class="dpe-toggle-container" title="${title}">
- <label class="dpe-toggle">
- <input type="checkbox" data-setting="${id}" ${settings[id] ? 'checked' : ''}>
- <span class="dpe-toggle-slider"></span>
- </label>
- <label class="dpe-toggle-label">${label}</label>
- </div>
- `;
- }
-
- function hideSettingsDialog() {
- const dialog = document.getElementById('youtube-enchantments-settings');
- if (dialog) {
- dialog.style.display = 'none';
- }
- }
-
- function formatSettingName(setting) {
- return setting.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
- }
-
- function handleSettingChange(e) {
- if (e.target.dataset.setting) {
- if (e.target.type === 'checkbox') {
- toggleSetting(e.target.dataset.setting);
- } else if (e.target.type === 'range') {
- updateNumericSetting(e.target.dataset.setting, e.target.value);
- }
-
- // Log the status of adBlockBypassEnabled if it is changed
- if (e.target.dataset.setting === 'adBlockBypassEnabled') {
- Logger.info(`AdBlock Ban Bypass is ${e.target.checked ? 'enabled' : 'disabled'}`);
- }
- }
- }
-
-
- function handleSliderInput(e) {
- if (e.target.type === 'range') {
- const value = e.target.value;
- if (e.target.id === 'watchThreshold') {
- document.getElementById('watchThresholdValue').textContent = `${value}%`;
- } else if (e.target.id === 'scrollSpeed') {
- document.getElementById('scrollSpeedValue').textContent = `${value}px`;
- }
- updateNumericSetting(e.target.dataset.setting, value);
- }
- }
-
- function toggleSetting(settingName) {
- settings[settingName] = !settings[settingName];
- saveSettings();
- }
-
- function updateNumericSetting(settingName, value) {
- settings[settingName] = parseInt(value, 10);
- saveSettings();
- }
-
- function startBackgroundCheck() {
- worker.postMessage({ type: 'startCheck', checkFrequency: settings.checkFrequency });
- }
-
- function checkAndLikeVideo() {
- Logger.info('Checking if video should be liked...');
- if (watchThresholdReached()) {
- Logger.info('Watch threshold reached.');
- if (settings.autoLikeEnabled) {
- Logger.info('Auto-like is enabled.');
- if (settings.likeIfNotSubscribed || isSubscribed()) {
- Logger.info('User is subscribed or likeIfNotSubscribed is enabled.');
- if (settings.autoLikeLiveStreams || !isLiveStream()) {
- Logger.info('Video is not a live stream or auto-like for live streams is enabled.');
- likeVideo();
- } else {
- Logger.info('Video is a live stream and auto-like for live streams is disabled.');
- }
- } else {
- Logger.info('User is not subscribed and likeIfNotSubscribed is disabled.');
- }
- } else {
- Logger.info('Auto-like is disabled.');
- }
- } else {
- Logger.info('Watch threshold not reached.');
- }
- }
-
- function watchThresholdReached() {
- const player = document.querySelector(SELECTORS.PLAYER);
- if (player) {
- const watched = player.getCurrentTime() / player.getDuration();
- const watchedTarget = settings.watchThreshold / 100;
- if (watched < watchedTarget) {
- Logger.info(`Waiting until watch threshold reached (${watched.toFixed(2)}/${watchedTarget})...`);
- return false;
- }
- }
- return true;
- }
-
- function isSubscribed() {
- const subscribeButton = document.querySelector(SELECTORS.SUBSCRIBE_BUTTON);
- return subscribeButton && (subscribeButton.hasAttribute('subscribe-button-invisible') || subscribeButton.hasAttribute('subscribed'));
- }
-
- function isLiveStream() {
- const liveBadge = document.querySelector(SELECTORS.LIVE_BADGE);
- return liveBadge && window.getComputedStyle(liveBadge).display !== 'none';
- }
-
- function likeVideo() {
- Logger.info('Attempting to like the video...');
- const likeButton = document.querySelector(SELECTORS.LIKE_BUTTON);
- const dislikeButton = document.querySelector(SELECTORS.DISLIKE_BUTTON);
- const videoId = getVideoId();
-
- if (!likeButton || !dislikeButton || !videoId) {
- Logger.info('Like button, dislike button, or video ID not found.');
- return;
- }
-
- if (!isButtonPressed(likeButton) && !isButtonPressed(dislikeButton) && !autoLikedVideoIds.has(videoId)) {
- Logger.info('Liking the video...');
- likeButton.click();
- if (isButtonPressed(likeButton)) {
- Logger.success('Video liked successfully.');
- autoLikedVideoIds.add(videoId);
- } else {
- Logger.warning('Failed to like the video.');
- }
- } else {
- Logger.info('Video already liked or disliked, or already auto-liked.');
- }
- }
-
- function isButtonPressed(button) {
- return button.classList.contains('style-default-active') || button.getAttribute('aria-pressed') === 'true';
- }
-
- function getVideoId() {
- const watchFlexyElem = document.querySelector('#page-manager > ytd-watch-flexy');
- if (watchFlexyElem && watchFlexyElem.hasAttribute('video-id')) {
- return watchFlexyElem.getAttribute('video-id');
- }
- const urlParams = new URLSearchParams(window.location.search);
- return urlParams.get('v');
- }
-
- function handleAdBlockError() {
- if (!settings.adBlockBypassEnabled) {
- Logger.info('AdBlock bypass is disabled.');
- return; // Do nothing if the AdBlock bypass is disabled
- }
-
- const playabilityError = document.querySelector(SELECTORS.PLAYABILITY_ERROR);
- if (playabilityError) {
- playabilityError.remove();
- playerManager.replacePlayer(window.location.href);
- } else if (tries < CONSTANTS.MAX_TRIES) {
- tries++;
- setTimeout(handleAdBlockError, CONSTANTS.DELAY);
- }
- }
-
-
- function handleKeyPress(event) {
- switch (event.key) {
- case 'F2':
- toggleSettingsDialog();
- break;
- case 'PageDown':
- toggleScrolling();
- break;
- case 'PageUp':
- handlePageUp();
- break;
- }
- }
-
- function toggleSettingsDialog() {
- const dialog = document.getElementById('youtube-enchantments-settings');
- if (dialog && dialog.style.display === 'block') {
- hideSettingsDialog();
- } else {
- showSettingsDialog();
- }
- }
-
- function toggleScrolling() {
- if (isScrolling) {
- clearInterval(scrollInterval);
- isScrolling = false;
- } else {
- isScrolling = true;
- scrollInterval = setInterval(() => window.scrollBy(0, settings.scrollSpeed), 20);
- }
- }
-
- function handlePageUp() {
- if (isScrolling) {
- clearInterval(scrollInterval);
- isScrolling = false;
- } else {
- window.scrollTo(0, 0);
- }
- }
-
- function setupEventListeners() {
- window.addEventListener('beforeunload', () => {
- currentPageUrl = window.location.href;
- });
-
- document.addEventListener('yt-navigate-finish', () => {
- Logger.info('yt-navigate-finish event triggered');
- const newUrl = window.location.href;
- if (newUrl !== currentPageUrl) {
- Logger.info(`URL changed: ${newUrl}`);
- if (newUrl.endsWith('.com/')) {
- const iframe = document.getElementById(CONSTANTS.IFRAME_ID);
- if (iframe) {
- Logger.info('Removing iframe');
- iframe.remove();
- }
- } else {
- Logger.info('Handling ad block error');
- handleAdBlockError();
- }
- currentPageUrl = newUrl;
- }
- });
-
- document.addEventListener('keydown', (event) => {
- Logger.info(`Key pressed: ${event.key}`);
- handleKeyPress(event);
- });
-
- const observer = new MutationObserver((mutations) => {
- for (const mutation of mutations) {
- if (mutation.type === 'childList') {
- for (const node of mutation.addedNodes) {
- if (node.nodeType === Node.ELEMENT_NODE &&
- node.matches(SELECTORS.PLAYABILITY_ERROR)) {
- Logger.info('Playability error detected');
- handleAdBlockError();
- return;
- }
- }
- }
- }
- });
- observer.observe(document.body, { childList: true, subtree: true });
-
- setInterval(() => {
- Logger.info('Checking for duplicate players');
- playerManager.removeDuplicates();
- }, CONSTANTS.DUPLICATE_CHECK_INTERVAL);
-
- // Add interval to check and hide game sections
- setInterval(hideGameSections, CONSTANTS.GAME_CHECK_INTERVAL);
- }
-
- function hideGameSections() {
- if (!settings.removeGamesEnabled) return;
-
- const allSections = document.querySelectorAll(SELECTORS.GAME_SECTION);
- if (allSections.length > 0) {
- allSections.forEach(section => {
- // Check if this is a game section using DOM traversal
- if (isGameSection(section)) {
- section.style.display = 'none';
- Logger.success('Game section hidden');
- }
- });
- }
- }
-
- function isGameSection(section) {
- // Check for dismissible rich shelf renderer elements
- const dismissibleElements = section.querySelectorAll('div#dismissible.style-scope.ytd-rich-shelf-renderer');
- if (dismissibleElements.length > 0) {
- return true;
- }
-
- // Check if this is a games/playables section using various indicators
-
- // Check for "Jugables de YouTube" in the title
- const titleElement = section.querySelector('#title-text span');
- if (titleElement && titleElement.textContent.includes('Jugables')) {
- return true;
- }
-
- // Check for playables links
- const playablesLinks = section.querySelectorAll('a[href="/playables"], a[href*="/playables"]');
- if (playablesLinks.length > 0) {
- return true;
- }
-
- // Check for gaming links
- const gamingLinks = section.querySelectorAll('a[href*="gaming"]');
- if (gamingLinks.length > 0) {
- return true;
- }
-
- // Check for game-related text in aria-labels
- const richShelfElements = section.querySelectorAll('ytd-rich-shelf-renderer');
- for (const element of richShelfElements) {
- const ariaLabel = element.getAttribute('aria-label');
- if (ariaLabel && (ariaLabel.toLowerCase().includes('game') || ariaLabel.toLowerCase().includes('juego'))) {
- return true;
- }
- }
-
- // Check for mini-game-card elements
- const miniGameCards = section.querySelectorAll('ytd-mini-game-card-view-model');
- if (miniGameCards.length > 0) {
- return true;
- }
-
- // Check for content with specific game-related patterns
- const gameGenres = ['Arcade', 'Carreras', 'Deportes', 'Acción', 'Puzles', 'Música'];
- const genreSpans = section.querySelectorAll('.yt-mini-game-card-view-model__genre');
- for (const span of genreSpans) {
- if (gameGenres.some(genre => span.textContent.includes(genre))) {
- return true;
- }
- }
-
- return false;
- }
-
- // Updated main initialization function
- async function initScript() {
- try {
- Logger.info('Initializing script for Edge compatibility');
- createSettingsMenu();
- setupEventListeners();
-
- const worker = createWorker();
- if (worker) {
- startBackgroundCheck(worker);
- } else {
- Logger.warning('Worker creation failed, falling back to interval');
- setInterval(checkAndLikeVideo, settings.checkFrequency);
- }
-
- // Initial check for game sections
- hideGameSections();
-
- // Check browser compatibility
- const userAgent = navigator.userAgent;
- if (userAgent.includes("Edg/")) {
- Logger.info('Edge detected, applying specific optimizations');
- CONSTANTS.DELAY = 300; // Specific adjustment for Edge
- CONSTANTS.MAX_TRIES = 150;
- }
-
- } catch (error) {
- Logger.error(`Script initialization failed: ${error}`);
- }
- }
-
- initScript();
- })();