您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Don't like the youtube autoplay suggestion? This script can create a queue with videos you want to play after your current video has finished!
当前为
// ==UserScript== // @name Youtube Play Next Queue // @version 1.2.5 // @description Don't like the youtube autoplay suggestion? This script can create a queue with videos you want to play after your current video has finished! // @author Cpt_mathix // @match https://www.youtube.com // @include https://www.youtube.com/* // @license GPL version 2 or any later version; http://www.gnu.org/licenses/gpl-2.0.txt // @require https://cdnjs.cloudflare.com/ajax/libs/JavaScript-autoComplete/1.0.4/auto-complete.min.js // @namespace https://greatest.deepsurf.us/users/16080 // @grant none // @noframes // ==/UserScript== (function() { var script = { ytplayer: null, playnext: true, instantplay: true, queue: new Queue(), suggestion: "", version: "1.2.0", search_timeout: null, search_suggestions: [], debug: false }; // callback function for search results window.search_callback = search_callback; // youtube search parameters const GeoLocation = window.yt.config_.INNERTUBE_CONTEXT_GL; const HostLanguage = window.yt.config_.INNERTUBE_CONTEXT_HL; // reload script on page change using youtube spf events (http://youtube.github.io/js/documentation/events/) window.addEventListener("spfdone", function(e) { if (script.debug) { console.log("new page loaded"); } clearSearchRequests(); if (isPlayerAvailable()) { startScript(2); } }); main(); function main() { initGlobalScrollListener(); initButtonGenerators(); injectCSS(); if (isPlayerAvailable()) { if (script.debug) { console.log("player available"); } startScript(5); } else { if (script.debug) { console.log("player unavailable"); } } } function startScript(retry) { script.ytplayer = getVideoPlayer(); if (script.debug) { console.log("ytplayer: ", script.ytplayer); } if (script.ytplayer && !isPlaylistOrLivePlayer()) { if (getVideoInfoFromUrl(document.location.href, "t") == "0s") { script.ytplayer.seekTo(0); } if (script.debug) { console.log("initializing queue"); } initQueue(); if (script.debug) { console.log("initializing search"); } initSearch(); if (script.debug) { console.log("initializing video statelistener"); } initVideoStateListener(); if (script.debug) { console.log("initializing queue buttons"); } initQueueButtons(); } else if (script.ytplayer && isPlaylistOrLivePlayer()) { if (script.debug) { console.log("initializing search"); } initSearch(); } else if (retry > 0) { // fix conflict with Youtube+ script setTimeout( function() { startScript(--retry); }.bind(retry), 1000); } } // *** LISTENERS *** // function initVideoStateListener() { if (!script.ytplayer.classList.contains('initialized-listeners')) { script.ytplayer.classList.add('initialized-listeners'); // play next video in queue if current video has finished playing (state equal to 0) script.ytplayer.addEventListener("onStateChange", function(videoState) { if (script.debug) { console.log("state changed: ", videoState); } if (script.debug) { console.log("playnext: ", script.playnext); } if (script.debug) { console.log("instantplay: ", script.instantplay); } if (script.debug) { console.log("queue empty: ", script.queue.isEmpty()); } const FINISHED_STATE = 0; if (videoState === FINISHED_STATE && script.playnext === true && script.instantplay === true && !script.queue.isEmpty()) { script.queue.playNow(); } else if (videoState !== FINISHED_STATE) { script.playnext = true; } }); } else { if (script.debug) { console.log("statelistener already initialized"); } } } // Did new content load? Triggered everytime you scroll function initGlobalScrollListener() { document.addEventListener("scroll", function scroll(event) { // temporarily remove scroll listener to prevent multiple events event.currentTarget.removeEventListener(event.type, scroll); if (script.debug) { console.log("scroll"); } if (isPlayerAvailable()) { if (script.ytplayer === null) { startScript(0); } else if (!isPlaylistOrLivePlayer()) { initQueueButtons(); } } setTimeout( function() { initGlobalScrollListener(); }, 1000); }); } // *** OBJECTS *** // // video object function ytVideo(title, id, html, anchor, author, time, stats, thumb) { this.title = title; this.id = id; this.html = html; this.buttonAnchor = anchor; this.author = author; this.time = time; this.length_seconds = hmsToSecondsOnly(time); this.stats = stats; this.iurlhq = thumb; this.iurlmq = thumb; } // hh:mm:ss => only seconds function hmsToSecondsOnly(str) { var p = str.split(":"), s = 0, m = 1; while (p.length > 0) { s += m * parseInt(p.pop(), 10); m *= 60; } return s; } // Queue object function Queue() { var queue = []; this.get = function() { return queue; }; this.set = function(newQueue) { queue = newQueue; setCache("queue", this.get()); }; this.isEmpty = function() { return 0 === queue.length; }; this.reset = function() { queue = []; this.update(0); this.show(0); }; this.peek = function() { return queue[0]; }; this.enqueue = function(item) { queue.push(item); this.update(); this.show(500); }; this.dequeue = function() { var item = queue.shift(); this.update(); if (script.debug) { console.log("dequeued: ", item); } return item; }; this.remove = function(index) { queue.splice(index, 1); this.update(); this.show(250); }; this.playNext = function(index) { var video = queue.splice(index, 1); queue.unshift(video[0]); this.update(); this.show(0); }; this.playNow = function() { script.playnext = false; var video = this.dequeue(); playNextVideo(video.id); }; this.html = function() { var html = ""; queue.forEach( function(item) { html += item.html; }); return html; }; this.update = function() { setCache("queue", this.get()); if (script.debug) { console.log("updated queue: ", this.get().slice()); } }; this.show = function(delay) { setTimeout(function() { displayQueue(); }, delay); }; } // *** VIDEO & PLAYER *** // function getVideoPlayer() { return document.getElementById('movie_player'); } function isPlayerAvailable() { // available on video pages without playlist or live chat return (/https:\/\/www\.youtube\.com\/watch\?v=.*/.test(document.location.href)); } function isPlaylistOrLivePlayer() { return (getVideoInfoFromUrl(document.location.href, "list")) || (document.getElementById('live-chat-iframe') !== null); } function isPlayerFullscreen() { return (script.ytplayer.classList.contains('ytp-fullscreen')); } // play next video behavior depending on if you're watching fullscreen function playNextVideo(nextVideoId) { if (script.debug) { console.log("playing next song"); } if (isPlayerFullscreen()) { script.ytplayer.loadVideoById(nextVideoId, 0); } else { window.spf.navigate("https://www.youtube.com/watch?v=" + nextVideoId + "&t=0s"); } } // reconfigure the next video button (video player) function changeNextVideo(video) { if (script.debug) { console.log("changing next video button"); } // next video autoplay settings var related_vid_config = window.yt.config_.RELATED_PLAYER_ARGS; var related_vids_params = related_vid_config.rvs.split(","); var first_vid_params = related_vids_params[0]; var other_vid_params = related_vids_params.slice(1).join(","); // changing next video with first from queue var params = ["author", "id", "title", "iurlhq", "iurlmq", "length_seconds", "short_view_count_text"]; for (var i = 0; i < params.length; i++) { var re = new RegExp("(" + params[i] + ")=(.[^&]+)", "g"); first_vid_params = first_vid_params.replace(re, function($0, param, value) { return param + "=" + encodeURIComponent(video[param] || ""); }); } script.ytplayer.updateVideoData(JSON.parse('{"rvs":"' + first_vid_params + ',' + other_vid_params + '"}')); } function getPlayType() { return (script.instantplay) ? "Instantplay" : "Autoplay"; } function getVideoInfoFromUrl(url, info) { if (url.indexOf("?") === -1) { return null; } var urlVariables = url.split("?")[1].split("&"), varName; for (var i = 0; i < urlVariables.length; i++) { varName = urlVariables[i].split("="); if (varName[0] === info) { return varName[1] === undefined ? null : varName[1]; } } } // extracting video information and creating a video object (that can be added to the queue) function findVideoInformation(video, selector) { var anchor = video.querySelector(selector + ' .yt-uix-sessionlink:not(.related-playlist)'); if (anchor) { var title = video.querySelector('span.title').textContent.trim(); var author = video.querySelector('span.author') ? video.querySelector('span.author').textContent.trim() : video.querySelector('span.attribution').textContent.trim(); var time = video.querySelector('span.video-time') ? video.querySelector('span.video-time').textContent.trim() : "0"; var thumb = video.querySelector('span.yt-uix-simple-thumb-related > img').dataset.thumb || video.querySelector('span.yt-uix-simple-thumb-related > img').src; var id = getVideoInfoFromUrl(video.querySelector('a.yt-uix-sessionlink').href, "v"); var newVidObject = new ytVideo(title, id, video.outerHTML, anchor, author, time, null, thumb); return newVidObject; } return null; } // *** QUEUE *** // function initQueue() { var cachedQueue = getCache("queue"); if (cachedQueue) { script.queue.set(cachedQueue); } else { setCache("queue", script.queue.get()); } // instantplay settings script.instantplay = getCache("instantplay") || script.instantplay; // prepare html for queue var queue = document.getElementsByClassName('autoplay-bar')[0]; queue.classList.add('video-list'); queue.id = 'watch-queue'; // add class to suggestion video so it doesn't get queue related buttons var suggestion = queue.getElementsByClassName('related-list-item')[0]; suggestion.classList.add('suggestion'); script.suggestion = suggestion.outerHTML; // show the queue if not empty if (!script.queue.isEmpty()) { // dequeue video from the queue if it is playing if (script.ytplayer.getVideoData().video_id === script.queue.peek().id) { script.queue.dequeue(); script.ytplayer.seekTo(0); } displayQueue(); } } function displayQueue() { if (script.debug) { console.log("showing queue: ", script.queue.get()); } var html = script.queue.html(); var queue = document.querySelector('.autoplay-bar'); var anchor = document.querySelector('.watch-sidebar-head'); var suggestion; var suggestion_anchor = document.querySelector('.watch-sidebar-body > .video-list'); // cleanup current queue var li = document.querySelectorAll('.autoplay-bar > li.video-list-item'); if (li) { for (var i = li.length - 1; i >= 0; i--) { li[i].remove(); } } // display new queue if (html !== null && !script.queue.isEmpty() && queue !== null && anchor !== null) { // insert new queue anchor.insertAdjacentHTML("afterend", html); // button generators var playNextButtonGenerator = new PlayNextButtonGenerator(); var playNowButtonGenerator = new PlayNowButtonGenerator(); var removeButtonGenerator = new RemoveButtonGenerator(); var suggestionAddButtonGenerator = new SuggestionAddButtonGenerator(); // add remove buttons var items = queue.querySelectorAll('.related-list-item:not(.suggestion)'); for (var z = 0; z < items.length; z++) { var video = findVideoInformation(items[z], '#watch-queue'); // remove addbutton if there is one var addedButton = items[z].querySelector('.queue-add, .queue-add-suggestion'); if (addedButton) { addedButton.remove(); } if (video) { if (z > 0) { playNextButtonGenerator.build(video, z); } else { playNowButtonGenerator.build(video); } removeButtonGenerator.build(video, z); } } // replace autoplay options with remove queue button var autoplay = queue.querySelector('.checkbox-on-off'); if (autoplay) { removeQueueButton(autoplay); // changePlayTypeButton(autoplay); } // add queue button to suggestion video suggestion = queue.querySelector('.suggestion:not(.processed)'); if (suggestion) { var suggestionVideo = findVideoInformation(suggestion, '#watch-queue'); suggestion.classList.add('processed'); suggestionAddButtonGenerator.build(suggestionVideo); } // triggering lazyload window.scrollTo(window.scrollX, window.scrollY + 1); window.scrollTo(window.scrollX, window.scrollY - 1); // remove not interested menu var menu = queue.getElementsByClassName('yt-uix-menu-trigger'); for (var j = menu.length - 1; j >= 0; j--) { menu[j].remove(); } // change next video button of the youtube player setTimeout( function() { var autoplay = script.queue.peek(); if (autoplay) { changeNextVideo(autoplay); } }, 1000); } else if (suggestion_anchor.children.length === 0) { suggestion_anchor.insertAdjacentHTML("afterbegin", script.suggestion); // triggering lazyload window.scrollTo(window.scrollX, window.scrollY + 1); window.scrollTo(window.scrollX, window.scrollY - 1); // change next video button of the youtube player changeNextVideo(findVideoInformation(suggestion_anchor.firstChild, '#watch-queue')); } else { suggestion = document.querySelector('.suggestion'); if (suggestion.querySelector('.queue-add-suggestion')) { suggestion.classList.remove('processed', 'processed-buttons'); suggestion.querySelector('.queue-add-suggestion').remove(); } // change next video button of the youtube player changeNextVideo(findVideoInformation(suggestion, '#watch-queue')); } } // *** BUTTONS *** // // initialize Button Generators (Template design) function initButtonGenerators() { AddButtonGenerator.prototype = new ButtonGenerator(); SuggestionAddButtonGenerator.prototype = new ButtonGenerator(); RemoveButtonGenerator.prototype = new ButtonGenerator(); PlayNextButtonGenerator.prototype = new ButtonGenerator(); PlayNowButtonGenerator.prototype = new ButtonGenerator(); } // finding video's and adding the queue buttons function initQueueButtons() { var addButtonGenerator = new AddButtonGenerator(); var videos = document.querySelectorAll('.related-list-item:not(.processed-buttons)'); for (var j = 0; j < videos.length; j++) { try { var video = findVideoInformation(videos[j], '#watch-related'); videos[j].classList.add('processed-buttons'); if (video) { addButtonGenerator.build(video); } } catch(error) { console.error("Couldn't initialize \"Add to queue\" buttons for a video \n" + error.message); } } } // Button template function ButtonGenerator() { this.build = function(video, index) { var anchor = video.buttonAnchor; var html = "<div class=\"queue-button " + this.type + " yt-uix-button yt-uix-button-default yt-uix-button-size-default\"><button class=\"yt-uix-button-content\">" + this.text + "</button></div>"; anchor.insertAdjacentHTML("beforeend", html); var button = this; anchor.getElementsByClassName(this.type)[0].addEventListener("click", function handler(e) { e.preventDefault(); button.clickBehavior(this, video, index); e.currentTarget.removeEventListener(e.type, handler); if (button.type !== "queue-add-suggestion") { this.addEventListener("click", function(e) { e.preventDefault(); }); } }); }; } function AddButtonGenerator() { this.type = "queue-add"; this.text = "Add to queue"; this.clickBehavior = function(element, video, index) { element.textContent = "Queued!"; script.queue.enqueue(video); }; } function SuggestionAddButtonGenerator() { this.type = "queue-add-suggestion"; this.text = "Add to queue"; this.clickBehavior = function(element, video, index) { element.textContent = "Queued!"; var suggestion = document.getElementsByClassName('suggestion')[0]; suggestion.classList.remove('suggestion'); video.html = suggestion.outerHTML; script.queue.enqueue(video); suggestion.remove(); }; } function RemoveButtonGenerator() { this.type = "queue-remove"; this.text = "Remove"; this.clickBehavior = function(element, video, index) { element.textContent = "Removed!"; script.queue.remove(index); restoreAddButton(video.id); }; } function PlayNextButtonGenerator() { this.type = "queue-next"; this.text = "Play Next"; this.clickBehavior = function(element, video, index) { this.textContent = "To the top!"; script.queue.playNext(index); }; } function PlayNowButtonGenerator() { this.type = "queue-now"; this.text = "Play Now"; this.clickBehavior = function(element, video, index) { this.textContent = "Playing!"; script.queue.playNow(); }; } // The "remove queue and all its videos" button function removeQueueButton(anchor) { var html = "<div class=\"queue-button remove-queue yt-uix-button yt-uix-button-default yt-uix-button-size-default\"><button class=\"yt-uix-button-content\">Remove Queue</button></div>"; anchor.innerHTML = html; anchor.getElementsByClassName('remove-queue')[0].addEventListener("click", function handler(e) { e.preventDefault(); this.textContent = "Removed!"; script.queue.reset(); restoreAddButton("*"); // restore all e.currentTarget.removeEventListener(e.type, handler); this.addEventListener("click", function (e) { e.preventDefault(); }); }); } function changePlayTypeButton(anchor) { var html = "<div class=\"queue-button toggle-play-type yt-uix-button yt-uix-button-default yt-uix-button-size-default\"><button class=\"yt-uix-button-content\">" + getPlayType() + "</button></div>"; var button = anchor.getElementsByClassName('toggle-play-type')[0]; if (button) { button.outerHTML = html; } else { anchor.insertAdjacentHTML("afterbegin", html); } anchor.getElementsByClassName('toggle-play-type')[0].addEventListener("click", function handler(e) { e.preventDefault(); script.instantplay = !script.instantplay; setCache("instantplay", script.instantplay); e.currentTarget.removeEventListener(e.type, handler); changePlayTypeButton(anchor); }); } function restoreAddButton(id) { var addButtonGenerator = new AddButtonGenerator(); var videos = document.querySelectorAll('.related-list-item'); for (var j = 0; j < videos.length; j++) { if (id === "*" || id === getVideoInfoFromUrl(videos[j].querySelector('a.yt-uix-sessionlink').href, "v")) { // remove current addbutton if there is one var addedButton = videos[j].querySelector('.queue-add'); if (addedButton) { addedButton.remove(); } // make new addbutton var video = findVideoInformation(videos[j], '#watch-related'); if (video) { addButtonGenerator.build(video); } } } } // *** SEARCH *** // // initialize search function initSearch() { if (!document.getElementById('masthead-queue-search')) { var anchor, html; if (isPlaylistOrLivePlayer()) { anchor = document.querySelector('#watch7-sidebar-modules'); html = "<input id=\"masthead-queue-search\" class=\"search-term yt-uix-form-input-bidi playlist-or-live\" type=\"text\" placeholder=\"Search\">"; } else { anchor = document.querySelector('#watch7-sidebar-modules > div:nth-child(2)'); html = "<input id=\"masthead-queue-search\" class=\"search-term yt-uix-form-input-bidi\" type=\"text\" placeholder=\"Search\">"; } anchor.insertAdjacentHTML("afterbegin", html); var input = document.getElementById('masthead-queue-search'); // suggestion dropdown init new autoComplete({ selector: '#masthead-queue-search', minChars: 1, delay: 250, source: function(term, suggest) { suggest(script.search_suggestions); }, onSelect: function(event, term, item) { prepareNewSearchRequest(term); } }); input.addEventListener("keydown", function(event) { const ENTER = 13; const BACKSPACE = 8; if (this.value !== "" && event.keyCode === ENTER) { prepareNewSearchRequest(this.value); } else if (this.value !== "" && event.keyCode === BACKSPACE) { searchSuggestions(this.value); } else { searchSuggestions(this.value + event.key); } }); input.addEventListener("focus", function(event) { this.select(); }); } } // callback from search suggestions attached to window function search_callback(data) { var raw = data[1]; // extract relevant data from json script.search_suggestions = raw.map(function(array) { return array[0]; // change 2D array to 1D array with only suggestions }); } // get search suggestions function searchSuggestions(value) { if (script.search_timeout !== null) { clearTimeout(script.search_timeout); } // only allow 1 search request every 100 milliseconds script.search_timeout = setTimeout( function() { if (script.debug) { console.log("search request send"); } var scriptElement = document.createElement("script"); scriptElement.type = "text/javascript"; scriptElement.className = "search-request"; scriptElement.src = "https://clients1.google.com/complete/search?client=youtube&hl=" + HostLanguage + "&gl=" + GeoLocation + "&gs_ri=youtube&ds=yt&q=" + encodeURIComponent(value) + "&callback=search_callback"; document.head.appendChild(scriptElement); }.bind(value), 100); } // send new search request (with the search bar) function prepareNewSearchRequest(value) { if (script.debug) { console.log("searching for " + value); } document.getElementById('masthead-queue-search').blur(); // close search suggestions dropdown var nextPage = document.getElementById('watch-more-related-button'); if (nextPage !== null) { nextPage.remove(); } // removing the "More Suggestions" link script.search_suggestions = []; // clearing the search suggestions sendSearchRequest("https://www.youtube.com/results?q=" + encodeURIComponent(value)); } // given the url, retrieve the search results function sendSearchRequest(url) { var xmlHttp = new XMLHttpRequest(); xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { var container = document.implementation.createHTMLDocument().documentElement; container.innerHTML = xmlHttp.responseText; processSearch(container); } }; xmlHttp.open("GET", url, true); // true for asynchronous xmlHttp.send(null); } function clearSearchRequests() { var requests = document.getElementsByClassName('search-request'); if (requests) { for (var i = requests.length - 1; i >= 0; i--) { requests[i].remove(); } } } // process search request function processSearch(container) { var videoList = container.getElementsByClassName('item-section')[0]; // remove current videos (and replace with searched videos later) var ul = document.getElementById('watch-related'); var li = ul.querySelectorAll('li.video-list-item'); if (li) { for (var i = li.length - 1; i >= 0; i--) { li[i].remove(); } } // insert searched videos var videos = videoList.querySelectorAll('.yt-lockup-video'); for (var j = videos.length - 1; j >= 0; j--) { var video = videos[j]; if (video.querySelector('.yt-badge-live') === null) { try { var videoId = video.dataset.contextItemId; var videoTitle = video.querySelector('.yt-lockup-title > a').title; var videoStats = video.querySelector('.yt-lockup-meta').innerHTML; var videoTime = video.querySelector('.video-time') ? video.querySelector('.video-time').textContent : "0"; var author = video.querySelector('.yt-lockup-byline') ? video.querySelector('.yt-lockup-byline').textContent : ""; var videoThumb = video.querySelector('div.yt-lockup-thumbnail img').dataset.thumb || video.querySelector('div.yt-lockup-thumbnail img').src; var videoObject = new ytVideo(videoTitle, videoId, null, null, author, videoTime, videoStats, videoThumb); if (script.debug) { console.log(videoObject); } ul.insertAdjacentHTML("afterbegin", videoQueueHTML(videoObject).html); } catch (error) { console.error("failed to process video " + error.message, video); } } } // insert navigation buttons var navigation = container.getElementsByClassName('search-pager')[0]; var buttons = navigation.getElementsByTagName('a'); for (var k = 0; k < buttons.length; k++) { buttons[k].addEventListener("click", function handler(e) { e.preventDefault(); document.getElementById('masthead-queue-search').scrollIntoView(); window.scrollBy(0, -1 * document.getElementById('yt-masthead-container').clientHeight); sendSearchRequest(this.href); }); } var currNavigation = ul.parentNode.getElementsByClassName('search-pager')[0]; if (currNavigation) { currNavigation.remove(); } // remove old navigation ul.parentNode.appendChild(navigation); // append new navigation // insert separation line between videos and navigation if (! ul.parentNode.getElementsByClassName('watch-sidebar-separation-line')[0]) { ul.insertAdjacentHTML("afterend", "<hr class=\"watch-sidebar-separation-line\">"); } // only add queue buttons with normal video player if (!isPlaylistOrLivePlayer()) { initQueueButtons(); } } // *** LOCALSTORAGE *** // function getCache(key) { return JSON.parse(localStorage.getItem("YTQUEUE#" + script.version + "#" + key)); } function deleteCache(key) { localStorage.removeItem("YTQUEUE#" + script.version + "#" + key); } function setCache(key, value) { localStorage.setItem("YTQUEUE#" + script.version + "#" + key, JSON.stringify(value)); } // *** HTML & CSS *** // function videoQueueHTML(video) { var strVar=""; strVar += "<li class=\"video-list-item related-list-item show-video-time related-list-item-compact-video\">"; strVar += " <div class=\"related-item-dismissable\">"; strVar += " <div class=\"content-wrapper\">"; strVar += " <a href=\"\/watch?v=" + video.id + "\" class=\"yt-uix-sessionlink content-link spf-link spf-link\" rel=\"spf-prefetch\" title=\"" + video.title + "\">"; strVar += " <span dir=\"ltr\" class=\"title\">" + video.title + "<\/span>"; strVar += " <span class=\"stat author\">" + video.author + "<\/span>"; strVar += " <div class=\"yt-lockup-meta stat\">" + video.stats + "<\/div>"; strVar += " <\/a>"; strVar += " <\/div>"; strVar += " <div class=\"thumb-wrapper\">"; strVar += " <a href=\"\/watch?v=" + video.id + "\" class=\"yt-uix-sessionlink thumb-link spf-link spf-link\" rel=\"spf-prefetch\" tabindex=\"-1\" aria-hidden=\"true\">"; strVar += " <span class=\"yt-uix-simple-thumb-wrap yt-uix-simple-thumb-related\" tabindex=\"0\" data-vid=\"" + video.id + "\">"; strVar += " <img aria-hidden=\"true\" alt=\"\" src=\"" + video.iurlhq + "\">"; strVar += " <\/span>"; strVar += " <\/a>"; strVar += " <span class=\"video-time\">"+ video.time +"<\/span>"; strVar += " <button class=\"yt-uix-button yt-uix-button-size-small yt-uix-button-default yt-uix-button-empty yt-uix-button-has-icon no-icon-markup addto-button video-actions spf-nolink hide-until-delayloaded addto-watch-later-button yt-uix-tooltip\" type=\"button\" onclick=\";return false;\" title=\"Watch Later\" role=\"button\" data-video-ids=\"" + video.id + "\" data-tooltip-text=\"Watch Later\"><\/button>"; strVar += " <\/div>"; strVar += " <\/div>"; strVar += "<\/li>"; video.html = strVar; return video; } // injecting css function injectCSS() { var css = ` .autocomplete-suggestions { text-align: left; cursor: default; border: 1px solid #ccc; border-top: 0; background: #fff; box-shadow: -1px 1px 3px rgba(0,0,0,.1); position: absolute; display: none; z-index: 9999; max-height: 254px; overflow: hidden; overflow-y: auto; box-sizing: border-box; } .autocomplete-suggestion { position: relative; padding: 0 .6em; line-height: 23px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 1.02em; color: #333; } .autocomplete-suggestion b { font-weight: normal; color: #b31217; } .autocomplete-suggestion.selected { background: #f0f0f0; } .yt-uix-simple-thumb-wrap > img { top: 0px; width: 168px; height: 94px; } .watch-sidebar-body > div.search-pager { width: 97.5%; padding: 5px 5px; display: flex; justify-content: center; } .watch-sidebar-body > div.search-pager > .yt-uix-button { margin: 0 1px; } #masthead-queue-search { outline: none; width: 95%; padding: 5px 5px; margin: 0 4px; } #masthead-queue-search.playlist-or-live { width: 93%; margin: 0 10px 10px 10px; } #watch-queue { list-style: none; } #watch-related .queue-add { display: none; } #watch-related .processed-buttons:hover .queue-add { display: inline-block; } .related-list-item span.title { max-height: 2.4em; } .queue-button { height: 15px; padding: 0.2em 0.4em 0.2em 0.4em; margin: 2px 0; } .queue-remove { margin-left: 4px; } .remove-queue { margin-top: -3px; } .toggle-play-type { margin-right: 4px; margin-top: -3px; } `; var style = document.createElement("style"); style.type = "text/css"; if (style.styleSheet){ style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } document.documentElement.appendChild(style); } })();