Greasy Fork is available in English.
Search YouTube without interrupting the video, by loading the search r###lts in the related video bar
// ==UserScript==// @name Youtube - Search While Watching Video// @version 2.5.5// @description Search YouTube without interrupting the video, by loading the search r###lts in the related video bar// @author Cpt_mathix// @match https://www.youtube.com/*// @license GPL-2.0-or-later// @require https://cdn.jsdelivr.net/gh/culefa/JavaScript-autoComplete@19203f30f148e2d9d810ece292b987abb157bbe0/auto-complete.min.js// @namespace https://greasyfork.org/users/16080// @run-at document-start// @grant none// @noframes// ==/UserScript==/* jshint esversion: 11 */(function() {'use strict';// Handle Trusted Type Policy Violationsvar TTP = window.TTP = {createHTML: (string, sink) => string, createScript: (string, sink) => string, createScriptURL: (string, sink) => string};if(typeof window.isSecureContext !== 'undefined' && window.isSecureContext){if (window.trustedTypes && window.trustedTypes.createPolicy){if(window.trustedTypes.defaultPolicy) {TTP = window.TTP = window.trustedTypes.defaultPolicy;} else {TTP = window.TTP = window.trustedTypes.createPolicy("default", TTP);}}}function youtube_search_while_watching_video() {let script = {initialized: false,ytplayer: null,search_bar: null,search_autocomplete: null,search_suggestions: [],searched: false,debug: false};const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);document.addEventListener("DOMContentLoaded", initScript);// reload script on page change using youtube polymer fire eventswindow.addEventListener("yt-page-data-updated", function(event) {if (script.debug) { console.log("# page updated #"); }cleanupSearch();startScript(2);});function initScript() {if (script.debug) { console.log("### Youtube Search While Watching Video Initializing ###"); }initSearch();injectCSS();if (script.debug) { console.log("### Youtube Search While Watching Video Initialized ###"); }script.initialized = true;startScript(5);}function startScript(retry) {if (script.initialized && isPlayerAvailable()) {if (script.debug) { console.log("videoplayer is available"); }if (script.debug) { console.log("ytplayer: ", script.ytplayer); }if (script.ytplayer) {try {if (script.debug) { console.log("initializing search"); }loadSearch();} catch (error) {console.log("Failed to initialize search: ", (script.debug) ? error : error.message);}}} else if (retry > 0) { // fix conflict with Youtube+ scriptsetTimeout( function() {startScript(--retry);}, 1000);} else {if (script.debug) { console.log("videoplayer is unavailable"); }}}// *** VIDEOPLAYER *** //function getVideoPlayer() {return insp(document.getElementById('movie_player'));}function isPlayerAvailable() {script.ytplayer = getVideoPlayer();return script.ytplayer !== null && script.ytplayer.getVideoData?.().video_id;}// *** SEARCH *** //function initSearch() {// callback function for search suggestion r###ltswindow.suggestions_callback = suggestionsCallback;}function loadSearch() {// prevent double searchbarlet playlistOrLiveSearchBar = document.querySelector('#suggestions-search.playlist-or-live');if (playlistOrLiveSearchBar) { playlistOrLiveSearchBar.remove(); }let searchbar = document.getElementById('suggestions-search');if (!searchbar) {createSearchBar();} else {searchbar.value = "";}script.searched = false;cleanupSuggestionRequests();}function cleanupSearch() {if (script.search_autocomplete) {script.search_autocomplete.destroy();}}function createSearchBar() {let anchor, html;anchor = document.querySelector('ytd-compact-autoplay-renderer > #contents');if (anchor) {html = "<input id=\"suggestions-search\" type=\"search\" placeholder=\"Search\">";anchor.insertAdjacentHTML("afterend", html);} else { // playlist, live video or experimental youtube layout (where autoplay is not a separate renderer anymore)anchor = document.querySelector('#related > ytd-watch-next-secondary-r###lts-renderer');if (anchor) {html = "<input id=\"suggestions-search\" class=\"playlist-or-live\" type=\"search\" placeholder=\"Search\">";anchor.insertAdjacentHTML("beforebegin", html);}}let searchBar = document.getElementById('suggestions-search');if (searchBar) {script.search_bar = searchBar;script.search_autocomplete = new window.autoComplete({selector: '#suggestions-search',minChars: 1,delay: 100,source: function(term, suggest) {script.search_suggestions = {query: term,suggest: suggest};searchSuggestions(term);},onSelect: function(event, term, item) {prepareNewSearchRequest(term);}});script.search_bar.addEventListener("keyup", function(event) {if (this.value === "") {resetSuggestions();}});// seperate keydown listener because the search listener blocks keyup..?script.search_bar.addEventListener("keydown", function(event) {const ENTER = 13;if (this.value.trim() !== "" && (event.key == "Enter" || event.keyCode === ENTER)) {prepareNewSearchRequest(this.value.trim());}});script.search_bar.addEventListener("search", function(event) {if(this.value === "") {script.search_bar.blur(); // close search suggestions dropdownscript.search_suggestions = []; // clearing the search suggestionsresetSuggestions();}});script.search_bar.addEventListener("focus", function(event) {this.select();});}}// callback from search suggestions attached to windowfunction suggestionsCallback(data) {if (script.debug) { console.log(data); }let query = data[0];if (query !== script.search_suggestions.query) {return;}let raw = data[1]; // extract relevant data from jsonlet suggestions = raw.map(function(array) {return array[0]; // change 2D array to 1D array with only suggestions});script.search_suggestions.suggest(suggestions);}function searchSuggestions(query) {// youtube search parametersconst GeoLocation = window.yt.config_.INNERTUBE_CONTEXT_GL;const HostLanguage = window.yt.config_.INNERTUBE_CONTEXT_HL;if (script.debug) { console.log("suggestion request send", query); }let scriptElement = document.createElement("script");scriptElement.type = "text/javascript";scriptElement.className = "suggestion-request";scriptElement.src = "https://clients1.google.com/complete/search?client=youtube&hl=" + HostLanguage + "&gl=" + GeoLocation + "&gs_ri=youtube&ds=yt&q=" + encodeURIComponent(query) + "&callback=suggestions_callback";(document.body || document.head || document.documentElement).appendChild(scriptElement);}function cleanupSuggestionRequests() {let requests = document.getElementsByClassName('suggestion-request');forEachReverse(requests, function(request) {request.remove();});}// send new search request (with the search bar)function prepareNewSearchRequest(value) {if (script.debug) { console.log("searching for " + value); }script.search_bar.blur(); // close search suggestions dropdownscript.search_suggestions = []; // clearing the search suggestionscleanupSuggestionRequests();sendSearchRequest("https://www.youtube.com/r###lts?pbj=1&search_query=" + encodeURIComponent(value));}// given the url, retrieve the search r###ltsfunction sendSearchRequest(url) {let xmlHttp = new XMLHttpRequest();xmlHttp.onreadystatechange = function() {if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {processSearch(xmlHttp.responseText);}};xmlHttp.open("GET", url, true);xmlHttp.setRequestHeader("x-youtube-client-name", window.yt.config_.INNERTUBE_CONTEXT_CLIENT_NAME);xmlHttp.setRequestHeader("x-youtube-client-version", window.yt.config_.INNERTUBE_CONTEXT_CLIENT_VERSION);xmlHttp.setRequestHeader("x-youtube-client-utc-offset", new Date().getTimezoneOffset() * -1);if (window.yt.config_.ID_TOKEN) { // null if not logged inxmlHttp.setRequestHeader("x-youtube-identity-token", window.yt.config_.ID_TOKEN);}xmlHttp.send(null);}// process search requestfunction processSearch(responseText) {try {let data = JSON.parse(responseText);let found = searchJson(data, (key, value) => {if (key === "itemSectionRenderer") {if (script.debug) { console.log(value.contents); }let succeeded = creat###ggestions(value.contents);return succeeded;}return false;});if (!found) {alert("The search request was succesful but the script was unable to parse the r###lts");}} catch (error) {alert("Failed to retrieve search data, sorry!\nError message: " + error.message + "\nSearch response: " + responseText);}}function searchJson(json, func) {let found = false;for (let item in json) {found = func(item, json[item]);if (found) { break; }if (json[item] !== null && typeof(json[item]) == "object") {found = searchJson(json[item], func);if (found) { break; }}}return found;}// *** HTML & CSS *** //function creat###ggestions(data) {// filter out promotional stuffif (data.length < 10) {return false;}// remove current suggestionslet hidden_continuation_item_renderer;let watchRelated = document.querySelector('#related ytd-watch-next-secondary-r###lts-renderer #items ytd-item-section-renderer #contents') || document.querySelector('#related ytd-watch-next-secondary-r###lts-renderer #items');forEachReverse(watchRelated.children, function(item) {if (item.tagName === "YTD-CONTINUATION-ITEM-RENDERER") {item.setAttribute("hidden", "");hidden_continuation_item_renderer = item;} else if (item.tagName !== "YTD-COMPACT-AUTOPLAY-RENDERER") {item.remove();}});// create suggestionsforEach(data, function(videoData) {if (videoData.videoRenderer || videoData.compactVideoRenderer) {window.Polymer.dom(watchRelated).appendChild(videoQueuePolymer(videoData.videoRenderer || videoData.compactVideoRenderer, "ytd-compact-video-renderer"));} else if (videoData.radioRenderer || videoData.compactRadioRenderer) {window.Polymer.dom(watchRelated).appendChild(videoQueuePolymer(videoData.radioRenderer || videoData.compactRadioRenderer, "ytd-compact-radio-renderer"));} else if (videoData.playlistRenderer || videoData.compactPlaylistRenderer) {window.Polymer.dom(watchRelated).appendChild(videoQueuePolymer(videoData.playlistRenderer || videoData.compactPlaylistRenderer, "ytd-compact-playlist-renderer"));}});if (hidden_continuation_item_renderer) {watchRelated.appendChild(hidden_continuation_item_renderer);}script.searched = true;return true;}function resetSuggestions() {if (script.searched) {let itemSectionRenderer = document.querySelector('#related ytd-watch-next-secondary-r###lts-renderer #items ytd-item-section-renderer') || document.querySelector("#related ytd-watch-next-secondary-r###lts-renderer");let data = insp(itemSectionRenderer).__data.data;creat###ggestions(data.contents || data.r###lts);// restore continuation rendererlet continuation = itemSectionRenderer.querySelector('ytd-continuation-item-renderer[hidden]');if (continuation) {continuation.removeAttribute("hidden");}}script.searched = false;}function videoQueuePolymer(videoData, type) {let node = document.createElement(type);node.classList.add("style-scope", "ytd-watch-next-secondary-r###lts-renderer", "yt-search-generated");node.data = videoData;return node;}function injectCSS() {let css = `.autocomplete-suggestions {text-align: left; cursor: default; border: 1px solid var(--ytd-searchbox-legacy-border-color); border-top: 0; background: var(--ytd-searchbox-background);position: absolute; /*display: none; z-index: 9999;*/ max-height: 254px; overflow: hidden; overflow-y: auto; box-sizing: border-box; box-shadow: -1px 1px 3px rgba(0,0,0,.1);left: auto; top: auto; width: 100%; margin: 0; contain: content; /* 1.2.0 */}.autocomplete-suggestion { position: relative; padding: 0 .6em; line-height: 23px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 1.22em; color: var(--ytd-searchbox-text-color); }.autocomplete-suggestion b { font-weight: normal; color: #b31217; }.autocomplete-suggestion.selected { background: #ddd; }[dark] .autocomplete-suggestion.selected { background: #333; }autocomplete-holder {overflow: visible; position: absolute; left: auto; top: auto; width: 100%; height: 0; z-index: 9999; box-sizing: border-box; margin:0; padding:0; border:0; contain: size layout;}ytd-compact-autoplay-renderer { padding-bottom: 0px; }#suggestions-search {outline: none; width: 100%; padding: 6px 5px; margin-bottom: 16px;border: 1px solid var(--ytd-searchbox-legacy-border-color); border-radius: 2px 0 0 2px;box-shadow: inset 0 1px 2px var(--ytd-searchbox-legacy-border-shadow-color);color: var(--ytd-searchbox-text-color); background-color: var(--ytd-searchbox-background);}`;let style = document.createElement("style");style.type = "text/css";if (style.styleSheet){style.styleSheet.cssText = css;} else {style.appendChild(document.createTextNode(css));}(document.body || document.head || document.documentElement).appendChild(style);}// *** FUNCTIONALITY *** //function forEach(array, callback, scope) {for (let i = 0; i < array.length; i++) {callback.call(scope, array[i], i);}}// When you want to remove elementsfunction forEachReverse(array, callback, scope) {for (let i = array.length - 1; i >= 0; i--) {callback.call(scope, array[i], i);}}}// ================================================================================= //// =============================== INJECTING SCRIPTS =============================== //// ================================================================================= //document.documentElement.setAttribute("youtube-search-while-watching-video", "");if (!document.getElementById("autocomplete_script")) {let autoCompleteScript = document.createElement('script');autoCompleteScript.id = "autocomplete_script";autoCompleteScript.type = 'text/javascript';autoCompleteScript.textContent = 'window.autoComplete = ' + autoComplete + ';';(document.body || document.head || document.documentElement).appendChild(autoCompleteScript);}if (!document.getElementById("search_while_watching_video")) {let searchWhileWatchingVideoScript = document.createElement('script');searchWhileWatchingVideoScript.id = "search_while_watching_video";searchWhileWatchingVideoScript.type = 'text/javascript';searchWhileWatchingVideoScript.textContent = '('+ youtube_search_while_watching_video +')();';(document.body || document.head || document.documentElement).appendChild(searchWhileWatchingVideoScript);}})();