Last active
January 22, 2025 04:36
-
-
Save abstraction/ae389154ba2952fbe7b3d635ce9e037c to your computer and use it in GitHub Desktop.
Revisions
-
abstraction revised this gist
Jan 22, 2025 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,6 +11,7 @@ /** * This script modifies YouTube videos' visibility based on percentage rating or view count. * Companion: https://microsoftedge.microsoft.com/addons/detail/thumbnail-rating-bar-for-/mglepphnjnfcljjafdgafoipiakakbin * If `shouldRemove` is true, it completely removes videos, otherwise, it lowers their opacity. */ -
abstraction revised this gist
Jan 22, 2025 . 1 changed file with 89 additions and 83 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,124 +9,130 @@ // @grant none // ==/UserScript== /** * This script modifies YouTube videos' visibility based on percentage rating or view count. * If `shouldRemove` is true, it completely removes videos, otherwise, it lowers their opacity. */ // Flag to control whether to remove videos or just lower their opacity let shouldRemove = true; // Set this to `true` to remove the videos, `false` to lower opacity /** * Process all videos by checking their percentage ratings and view counts. * Videos with low ratings or views are either removed or have reduced opacity. */ function processVideos() { try { // Determine if we are on the main video page or the recommendation page const isWatchPage = window.location.pathname.includes('/watch'); // Select the appropriate video item container based on the page const videoItemSelector = isWatchPage ? 'ytd-compact-video-renderer.ytd-item-section-renderer' // For recommendation page : 'ytd-rich-item-renderer.ytd-rich-grid-renderer'; // For main grid page // Get all elements with the 'ytrb-tooltip' containing the percentage const percentageElements = document.querySelectorAll('ytrb-tooltip'); if (!percentageElements.length) return; // Early exit if no percentage elements are found percentageElements.forEach(percentageElement => { // Extract percentage value from tooltip content const percentageText = percentageElement.querySelector('div')?.textContent.trim(); const percentageMatch = percentageText?.match(/(\d+\.?\d*)%/); if (!percentageMatch) return; const percentage = parseFloat(percentageMatch[1]); // Process video if percentage is below 99 if (percentage < 99) { const videoGridItem = percentageElement.closest(videoItemSelector); if (videoGridItem) { if (shouldRemove) { videoGridItem.remove(); } else { videoGridItem.style.opacity = 0.05; } } } // Check if the video has fewer than 1000 views or is a live stream const metadataLine = percentageElement.closest(videoItemSelector)?.querySelector('#metadata-line'); if (metadataLine) { const viewText = metadataLine.textContent.trim(); // If the metadata line does not contain the word 'views', it's likely a live video if (!viewText.includes('views')) { const videoGridItem = percentageElement.closest(videoItemSelector); if (videoGridItem) { if (shouldRemove) { videoGridItem.remove(); } else { videoGridItem.style.opacity = 0.05; } } } else { // Extract and convert view count to numeric value const viewMatch = viewText.match(/(\d+\.?\d*)\s*(k|m|b)?\s*views/i); if (viewMatch) { let viewCount = parseFloat(viewMatch[1]); const multiplier = { k: 1000, m: 1_000_000, b: 1_000_000_000 }; const suffix = viewMatch[2]?.toLowerCase(); if (multiplier[suffix]) { viewCount *= multiplier[suffix]; } // If the video has fewer than 1000 views, apply the toggle logic if (viewCount < 1000) { const videoGridItem = percentageElement.closest(videoItemSelector); if (videoGridItem) { if (shouldRemove) { videoGridItem.remove(); } else { videoGridItem.style.opacity = 0.05; } } } } } } }); } catch (error) { console.error('Error processing videos:', error); } } /** * Initialize the MutationObserver to monitor DOM changes (e.g., infinite scroll). */ const observer = new MutationObserver(debounce(processVideosTwice, 500)); // Debouncing to reduce the frequency of calls // Configure the observer to track added nodes in the DOM observer.observe(document.body, { childList: true, subtree: true }); /** * Debounce function to limit the rate at which a function is invoked. * @param {Function} func - The function to debounce * @param {number} wait - Time in milliseconds to wait before invoking the function * @returns {Function} - A debounced version of the provided function */ function debounce(func, wait) { let timeout; return function() { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, arguments), wait); }; } function processVideosTwice (){ // Initial processing of videos on page load processVideos(); // Do it one again setTimeout(processVideos, 1000); } processVideosTwice(); -
abstraction created this gist
Jan 22, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,132 @@ // ==UserScript== // @name YTCreme // @namespace http://tampermonkey.net/ // @version 2025-01-22 // @description YouTube better, like an elite. // @author abstraction // @match https://www.youtube.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @grant none // ==/UserScript== // Companion to: https://microsoftedge.microsoft.com/addons/detail/thumbnail-rating-bar-for-/mglepphnjnfcljjafdgafoipiakakbin // Flag to control whether to remove videos or just lower their opacity let shouldRemove = true; // Set this to `true` to remove the videos, `false` to lower opacity // Function to process videos and apply opacity or remove them function processVideos() { // Determine if we are on the main video page or the recommendation page const isWatchPage = window.location.pathname.includes('/watch'); // Select the appropriate video item container based on the page const videoItemSelector = isWatchPage ? 'ytd-compact-video-renderer.ytd-item-section-renderer' // For recommendation page : 'ytd-rich-item-renderer.ytd-rich-grid-renderer'; // For main grid page // Get all the elements with the class 'ytrb-percentage' (less accurate, sometimes not present) // const percentageElements = document.querySelectorAll('.ytrb-percentage'); // Get all the elements with the 'ytrb-tooltip' containing the percentage (more accurate) const percentageElements = document.querySelectorAll('ytrb-tooltip'); percentageElements.forEach(percentageElement => { // Get the percentage value from the text content (to be used with less accurate ytrb-percentage) // const percentage = parseFloat(percentageElement.textContent); // Extract the percentage value from the tooltip content (to be used with more accurate ytrb-tooltop) const percentageText = percentageElement.querySelector('div').textContent.trim(); const percentageMatch = percentageText.match(/(\d+\.?\d*)%/); if (!percentageMatch) return; // (to be used with more accurate ytrb-tooltop) const percentage = parseFloat(percentageMatch[1]); // (to be used with more accurate ytrb-tooltop) // If the percentage is less than 99, modify the parent grid item if (percentage < 99) { // Find the video grid item by bubbling up const videoGridItem = percentageElement.closest(videoItemSelector); // Dynamically selected based on page type if (videoGridItem) { if (shouldRemove) { // Remove the video item from DOM completely videoGridItem.remove(); } else { // Apply opacity to the entire video grid item videoGridItem.style.opacity = 0.05; // Full opacity effect applied to the entire item } } } // Check if the view count in #metadata-line is less than 1000 views const metadataLine = percentageElement.closest(videoItemSelector).querySelector('#metadata-line'); if (metadataLine) { const viewText = metadataLine.textContent.trim(); // If the metadata line does not contain the word 'views', it's likely a live video if (!viewText.includes('views')) { const videoGridItem = percentageElement.closest(videoItemSelector); if (videoGridItem) { if (shouldRemove) { // Remove the live video item from DOM completely videoGridItem.remove(); } else { // Reduce opacity for live videos videoGridItem.style.opacity = 0.05; } } } else { // Extract the view count using a regular expression const viewMatch = viewText.match(/(\d+\.?\d*)\s*(k|m|b)?\s*views/i); if (viewMatch) { let viewCount = parseFloat(viewMatch[1]); // Get the numeric part of the view count const isK = viewMatch[2] && viewMatch[2].toLowerCase() === 'k'; // Check if it's in "k" format const isM = viewMatch[2] && viewMatch[2].toLowerCase() === 'm'; // Check if it's in "m" format const isB = viewMatch[2] && viewMatch[2].toLowerCase() === 'b'; // Check if it's in "b" format (billions) // Convert based on the "k" (thousands), "m" (millions), or "b" (billions) if (isK) { viewCount *= 1000; // Multiply by 1000 for "k" } else if (isM) { viewCount *= 1000000; // Multiply by 1 million for "m" } else if (isB) { viewCount *= 1000000000; // Multiply by 1 billion for "b" } // If the video has less than 1000 views, apply the toggle logic if (viewCount < 1000) { const videoGridItem = percentageElement.closest(videoItemSelector); if (videoGridItem) { if (shouldRemove) { // Remove the low-view video item from DOM completely videoGridItem.remove(); } else { // Reduce opacity for low-view videos videoGridItem.style.opacity = 0.05; } } } } } } }); } // Initialize the MutationObserver to monitor DOM changes (infinite scroll) const observer = new MutationObserver(() => { processVideos(); // Run the video processing function on every DOM mutation }); // Configure the observer to track added nodes in the DOM observer.observe(document.body, { childList: true, subtree: true }); // Initial processing of videos on page load processVideos();