您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hides watched videos from your YouTube subscriptions page.
当前为
// ==UserScript== // @name YouTube: Hide Watched Videos // @namespace http://www.globexdesigns.com/ // @version 0.6 // @description Hides watched videos from your YouTube subscriptions page. // @author Evgueni Naverniouk // @grant GM_addStyle // @include http://*.youtube.com/* // @include http://youtube.com/* // @include https://*.youtube.com/* // @include https://youtube.com/* // ==/UserScript== // To submit bugs or submit revisions please see visit the repository at: // https://github.com/globexdesigns/youtube-hide-watched // You can open new issues at: // https://github.com/globexdesigns/youtube-hide-watched/issues (function (undefined) { GM_addStyle("\ .GR-WATCHED {\ display: none;\ }\ .GR-BUTTON {\ cursor: pointer;\ position: absolute;\ right: 80px;\ top: 10px;\ }\ .GR-BUTTON-LABEL {\ pointer-events: none;\ }\ .GR-BUTTON-CHECKBOX {\ pointer-events: none;\ margin-right: 10px;\ vertical-align: -3px;\ }\ "); // =========================================================== var findWatchedElements = function () { return document.getElementsByClassName('watched'); }; // =========================================================== var findParentByClass = function(el, cls) { while ((el = el.parentElement) && !el.classList.contains(cls)); return el; }; // =========================================================== var findButtonTarget = function () { return document.getElementById('browse-items-primary'); }; // =========================================================== var isButtonAlreadyThere = function () { var button = document.getElementsByClassName('GR-BUTTON'); return button && button.length; }; // =========================================================== var addClassToWatchedRows = function () { var items = findWatchedElements() || []; for (var i = 0, l = items.length; i < l; i++) { var item = items[i]; // "Subscription" section needs us to hide the "feed-item-container", // but in the "Trending" section, that class will hide everything. // So there, we need to hide the "expanded-shelf-content-item-wrapper" var row; if (window.location.href.indexOf('/feed/subscriptions') > 0) { row = findParentByClass(item, 'feed-item-container'); } else { row = findParentByClass(item, 'expanded-shelf-content-item-wrapper'); } var gridItem = findParentByClass(item, 'yt-shelf-grid-item'); // If we're in grid view, we will hide the "grid" item, // otherwise we'll hide the item row var itemToHide = gridItem ? gridItem : row; if (localStorage.GRWATCHED === 'true') { itemToHide.classList.add('GR-WATCHED'); } else { itemToHide.classList.remove('GR-WATCHED'); } } }; // =========================================================== var addCheckboxButton = function () { if (isButtonAlreadyThere()) return; // Find button target var target = findButtonTarget(); if (!target) return; // Add label var label = document.createElement('label'); label.className = 'GR-BUTTON-LABEL'; // Add checkbox var checkbox = document.createElement('input'); checkbox.checked = localStorage.GRWATCHED === 'true' ? 'checked' : null; checkbox.className = 'GR-BUTTON-CHECKBOX'; checkbox.type = 'checkbox'; label.appendChild(checkbox); // Add label text var textnode = document.createTextNode("Hide Watched"); label.appendChild(textnode); // Create <button> var button = document.createElement('button'); button.className = 'yt-uix-button yt-uix-button-size-default yt-uix-button-default yt-uix-button-has-icon yt-uix-button-reverse inq-no-click GR-BUTTON'; button.appendChild(label); button.addEventListener('click', function (event) { var value = localStorage.GRWATCHED === 'true' ? 'false' : 'true'; localStorage.GRWATCHED = value; console.log(localStorage.GRWATCHED, Boolean(localStorage.GRWATCHED), value); checkbox.checked = value === 'true'; addClassToWatchedRows(); }); target.appendChild(button); }; var run = function () { addClassToWatchedRows(); addCheckboxButton(); }; // =========================================================== // Hijack all XHR calls var send = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function (data) { this.addEventListener("readystatechange", function () { if ( // Anytime more videos are fetched -- re-run script this.responseURL.indexOf('browse_ajax?action_continuation') > 0 ) { setTimeout(function () { run(); }, 0); } }, false); send.call(this, data); }; // =========================================================== var observeDOM = (function(){ var MutationObserver = window.MutationObserver || window.WebKitMutationObserver, eventListenerSupported = window.addEventListener; return function(obj, callback){ if( MutationObserver ){ // define a new observer var obs = new MutationObserver(function(mutations, observer){ if( mutations[0].addedNodes.length || mutations[0].removedNodes.length ) callback(); }); // have the observer observe foo for changes in children obs.observe( obj, { childList:true, subtree:true }); } else if( eventListenerSupported ){ obj.addEventListener('DOMNodeInserted', callback, false); obj.addEventListener('DOMNodeRemoved', callback, false); } }; })(); // YouTube does weird things during navigation. This seems to be the only reliable way to // check when user moves from one page to another. observeDOM(document.body, function () { run(); }); // =========================================================== run(); }());