YouTube Video Age and Category Filter

Filters old YouTube videos and hides videos in certain categories.

Installer dette script?
Skaberens foreslåede script

Du vil måske også kunne lide YouTube Volume and Time Mouse Controlled

Installer dette script
// ==UserScript==
// @name         YouTube Video Age and Category Filter
// @namespace    PoKeRGT
// @version      1.12
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @description  Filters old YouTube videos and hides videos in certain categories.
// @author       PoKeRGT
// @match        https://www.youtube.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @connect      www.youtube.com
// @run-at       document-start
// @homepageURL  https://github.com/PoKeRGT/userscripts
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';


  const MAX_VIDEO_AGE = GM_getValue('maxVideoAge', 15);
  const OPACITY = GM_getValue('opacity', 0.25);
  const CATEGORIES_TO_HIDE = GM_getValue('categoriesToHide', ['Music', 'Sports']);
  const NOT_SEEN_BORDER_COLOR = GM_getValue('notSeenBorderColor', '#00FF00');
  const SEEN_BORDER_COLOR = GM_getValue('seenBorderColor', '#FF0000');


  const processedVideos = new WeakSet();

  const observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      mutation.addedNodes.forEach(function (node) {
        if (node.nodeType === 1 && node.matches('ytd-rich-item-renderer')) {
          handleVideoItem(node);
        }
      });
    });
  });

  observer.observe(document.documentElement, { childList: true, subtree: true });

  function handleVideoItem(videoItem) {
    if (processedVideos.has(videoItem)) {
      return;
    }
    processedVideos.add(videoItem);

    const thumbnailElement = videoItem.querySelector('yt-thumbnail-view-model');
    if (!thumbnailElement) return;

    const progressBar = videoItem.querySelector('yt-thumbnail-overlay-progress-bar-view-model');
    if (progressBar) {
      changeElementStyle(thumbnailElement, 'seen');
      return;
    }

    const videoLink = videoItem.querySelector('a.yt-lockup-metadata-view-model-wiz__title');
    if (videoLink && videoLink.href) {
      const videoUrl = new URL(videoLink.href, document.baseURI).href;
      const videoTitle = videoLink.textContent.trim() || 'Untitled Video';
      fetchVideoDetails(videoUrl, videoTitle, thumbnailElement);
    }
  }

  function changeElementStyle(element, prop) {
    if (!element) return;
    element.style.transition = 'all 0.3s ease';
    element.style.overflow = 'hidden';

    switch (prop) {
      case 'opacity':
        element.style.opacity = OPACITY;
        break;
      case 'not_seen':
        element.style.border = `4px solid ${NOT_SEEN_BORDER_COLOR}`;
        element.style.boxSizing = 'border-box';
        break;
      case 'seen':
        element.style.border = `4px solid ${SEEN_BORDER_COLOR}`;
        element.style.boxSizing = 'border-box';
        break;
      default:
        break;
    }
  }

  function fetchVideoDetails(videoUrl, videoTitle, elementToChange) {
    GM_xmlhttpRequest({
      method: 'GET',
      url: videoUrl,
      fetch: true,
      onload: function (response) {
        if (response.status < 200 || response.status >= 300) {
          console.error(`Error fetching video details for "${videoTitle}". Status: ${response.status}`);
          return;
        }

        const metaTags = response.responseText.match(/<meta [^>]*>/g) || [];
        let hidden = false;

        const categoryElement = findMetaTagContent(metaTags, ['itemprop="genre"', 'itemprop="category"']);
        if (categoryElement && CATEGORIES_TO_HIDE.includes(categoryElement)) {
          hidden = true;
          changeElementStyle(elementToChange, 'opacity');
        }

        if (!hidden) {
          const dateElement = findMetaTagContent(metaTags, ['itemprop="datePublished"', 'itemprop="uploadDate"']);
          if (dateElement) {
            const uploadDate = new Date(dateElement);
            const today = new Date();
            const diffInDays = Math.ceil((today - uploadDate) / (1000 * 60 * 60 * 24));

            if (diffInDays > MAX_VIDEO_AGE) {
              changeElementStyle(elementToChange, 'opacity');
            } else {
              changeElementStyle(elementToChange, 'not_seen');
            }
          } else {
            changeElementStyle(elementToChange, 'not_seen');
          }
        }
      },
      onerror: function (error) {
        console.error(`Error de red al obtener detalles de "${videoTitle}":`, error);
      }
    });
  }

  function findMetaTagContent(metaTags, properties) {
    for (const prop of properties) {
      const tag = metaTags.find(t => t.includes(prop));
      if (tag) {
        const contentMatch = tag.match(/content="([^"]+)"/);
        if (contentMatch && contentMatch[1]) {
          return contentMatch[1];
        }
      }
    }
    return null;
  }
})();