YouTube: Search results in Grid view

See more results in one go, without irrelevant results, such as 'People also watched' and 'For you', in the way.

// ==UserScript==
// @name              YouTube: Search results in Grid view
// @namespace         https://greasyfork.org/users/1166888-pedro
// @match             https://www.youtube.com/*
// @version           2024.8.14
// @author            Pedro
// @icon              https://i.imgur.com/DWVSLcD.png
// @description       See more results in one go, without irrelevant results, such as 'People also watched' and 'For you', in the way.
// @contributionURL   https://www.paypal.com/donate/?hosted_button_id=AF464CBPNVYB8
// @grant             GM_registerMenuCommand
// @grant             GM_setValue
// @grant             GM_getValue
// @compatible        Chrome
// @compatible        Safari
// @compatible        Firefox
// @license           MIT
// ==/UserScript==
GM_registerMenuCommand('Settings', settingsMenu);

function settingsMenu() {
    try { trustedTypes.createPolicy('default', {createHTML: (string, sink) => string}); }
    catch {}

    const menu = document.createElement('settings-menu');
    document.documentElement.appendChild(menu);
    menu.insertAdjacentHTML('afterbegin', `
    <div>
      <header>
        <span>Settings</span>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm4.3 14.3c-.39.39-1.02.39-1.41 0L12 13.41 9.11 16.3c-.39.39-1.02.39-1.41 0-.39-.39-.39-1.02 0-1.41L10.59 12 7.7 9.11c-.39-.39-.39-1.02 0-1.41.39-.39 1.02-.39 1.41 0L12 10.59l2.89-2.89c.39-.39 1.02-.39 1.41 0 .39.39.39 1.02 0 1.41L13.41 12l2.89 2.89c.38.38.38 1.02 0 1.41z"></path>
        </svg>
      </header>
      <label>
        <span>Maximum number of columns </span>
        <input type="number" id="maxNumOfColumns" value="${maxNumOfColumns}">
      </label>
      <label>
        <span>Minimum column width (px)</span>
        <input type="number" id="columnMinWidth" value="${columnMinWidth}">
      </label>
      <label>
        <span>Hide right sidebar</span>
        <input type="checkbox" id="hideRightSidebar" ${GM_getValue('hideRightSidebar') ? 'checked' : ''}>
      </label>
      <style>
        settings-menu svg {
          color: var(--background-3);
          width: 24px;
          height: 24px;
          transition: 0.4s;
          color: var(--text);
          opacity: .7;
        }

        settings-menu svg:hover {
          transform: rotate(-90deg);
          opacity: 1;
        }

        settings-menu svg:active {
          transform: scale(1.5);
        }

        settings-menu div {
          margin: 10px;
        }

        settings-menu {
          width: 310px;
          position: fixed;
          background: var(--background);
          top: 20px;
          right: 20px;
          z-index: 9999;
          color: var(--text);
          font-size: 1.4rem;
          border-radius: 20px;
          box-shadow: 0 4px 32px 0 rgba(0, 0, 0, 0.3);
          font-weight: 400;
          border: 1px solid var(--border);
        }

        settings-menu header {
          font-size: 1.7rem;
          font-weight: 500;
        }

        settings-menu header,
        settings-menu label {
          padding: 6px;
          display: flex;
          align-items: center;
        }

        settings-menu svg,
        settings-menu label {
          cursor: pointer;
        }

        settings-menu span {
          flex-grow: 1;
        }

        settings-menu [type="number"] {
          font-family: "Roboto";
          font-size: inherit;
          box-sizing: border-box;
          border: none;
          width: 60px;
          height: 30px;
          background: var(--background-2);
          color: inherit;
          outline: none;
          border-radius: 6px;
          padding: 0 3px;
        }

        settings-menu [type="number"]::-webkit-inner-spin-button {
          height: 30px;
        }

        settings-menu [type="checkbox"] {
          appearance: none;
          -webkit-tap-highlight-color: transparent;
          position: relative;
          border: 0;
          outline: 0;
          width: 37.5px;
          height: 24px;
          cursor: pointer;
        }

        settings-menu [type="checkbox"]:after {
          content: "";
          width: 100%;
          height: 100%;
          display: inline-block;
          border-radius: 100px;
          clear: both;
          background: var(--background-2);
          transition: background-color linear 0.08s;
        }

        settings-menu [type="checkbox"]:checked:after {
          background: #1db954;
        }

        settings-menu [type="checkbox"]:before {
          content: "";
          height: 19.5px;
          width: 19.5px;
          display: block;
          position: absolute;
          left: 0;
          top: 2px;
          border-radius: 50%;
          background: #fff;
          box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 2px 3px 0 rgba(0, 0, 0, 0.2);
          transform: translateX(2px);
          transition: transform linear 0.1s, background-color linear 0.08s;
        }

        settings-menu [type="checkbox"]:checked:before {
          transform: translateX(80%);
          transition: transform linear 0.1s, background-color linear 0.08s;
        }

        @media (prefers-color-scheme: dark) {
          :root {
            color-scheme: dark;
            --text: #f1f1f1;
            --background: #000;
            --background-2: rgba(255, 255, 255, .1);
            --border: rgba(255, 255, 255, .2);
          }
        }

        @media (prefers-color-scheme: light) {
          :root {
            --text: #030303;
            --background: #fff;
            --background-2: rgba(0, 0, 0, .1);
          }
        }
      </style>
    </div>`);

    menu.addEventListener('change', function(e) {
        if (e.target.type === 'number') {
            GM_setValue(e.target.id, e.target.value);
            if (e.target.id == 'maxNumOfColumns') maxNumOfColumns = GM_getValue('maxNumOfColumns');
            else columnMinWidth = GM_getValue('columnMinWidth');
        } else {
            GM_setValue(e.target.id, e.target.checked);
        }

        handleResize();
    });

    menu.querySelector('svg').addEventListener('click', function() {
        menu.remove();
    });
}

let maxNumOfColumns = GM_getValue('maxNumOfColumns') || 6;
let columnMinWidth = GM_getValue('columnMinWidth') || 326;
const div = document.createElement('div');
div.style = 'position: absolute; width: calc(100% - 32px - var(--sidebarWidth, 0px))';

document.addEventListener('yt-navigate-finish', function() {
    const pm = document.getElementById('page-manager');
    pm.style.position = 'relative';
    pm.appendChild(div);

    new ResizeObserver(function() {
        handleResize();
    }).observe(div);
}, {once: true});

document.addEventListener('yt-navigate-finish', function() {
    if (/(@|\/c\/).*search/.test(window.location.href)) {
        document.documentElement.classList.add('channelSearch');
    } else {
        document.documentElement.classList.remove('channelSearch');
    }
});

function handleResize() {
    let hasRun;

    for (let i = maxNumOfColumns; i > 0; i--) {
        if (div.clientWidth / i >= columnMinWidth) {
            document.documentElement.style.setProperty('--numOfColumns', i);
            hasRun = 1;
            break;
        }
    }

    if (!hasRun) document.documentElement.style.setProperty('--numOfColumns', 1);
}

const sheet = document.createElement('style');
document.documentElement.appendChild(sheet);
sheet.textContent = `
ytd-search {
  padding-left: 16px !important;
  padding-right: 16px !important;
}
ytd-search ytd-search-pyv-renderer,
ytd-search ytd-ad-slot-renderer,
ytd-search .metadata-snippet-container-one-line.ytd-video-renderer,
ytd-search .metadata-snippet-container.ytd-video-renderer,
ytd-search #description-text.ytd-video-renderer,
ytd-search #description.ytd-channel-renderer,
ytd-search #list,
ytd-search #expandable-metadata.ytd-video-renderer:not(:empty),
ytd-search ytd-exploratory-results-renderer.ytd-item-section-renderer,
ytd-search ytd-horizontal-card-list-renderer.ytd-item-section-renderer:not(:first-child),
ytd-search ytd-reel-shelf-renderer.ytd-item-section-renderer,
ytd-search ytd-shelf-renderer.ytd-item-section-renderer,
ytd-search #channel-name.ytd-video-renderer,
ytd-search #separator.ytd-video-meta-block {
  display: none !important;
}
ytd-search #view-more.ytd-playlist-renderer,
ytd-search #metadata.ytd-video-meta-block,
ytd-search #byline-container[hidden] {
  display: block !important;
}
ytd-search #container.ytd-search {
  max-width: calc(var(--numOfColumns) * (var(--ytd-rich-grid-item-max-width) + var(--ytd-rich-grid-item-margin)) + var(--sidebarWidth, 0px));
  min-width: calc(var(--sidebarWidth) + var(--ytd-rich-grid-item-max-width));
}
ytd-search #header.ytd-search,
ytd-search ytd-two-column-search-results-renderer,
ytd-search #primary.ytd-two-column-search-results-renderer {
  max-width: 100% !important;
}
ytd-search #contents > ytd-item-section-renderer,
ytd-search #contents > ytd-item-section-renderer > #contents {
  display: contents;
}
ytd-search ytd-item-section-renderer[can-show-more]:after {
  /* Fix for elements appearing in wrong spots */
  content: "";
  width: 100%;
  min-height: 7000px;
}
ytd-search #contents.ytd-section-list-renderer {
  display: flex;
  flex-wrap: wrap;
}
ytd-search #contents > .ytd-item-section-renderer {
  margin-left: calc(var(--ytd-rich-grid-item-margin)/2);
  margin-right: calc(var(--ytd-rich-grid-item-margin)/2);
  width: calc(100%/var(--numOfColumns) - var(--ytd-rich-grid-item-margin) - 0.01px);
  margin-bottom: 24px;
}
ytd-search ytd-movie-renderer {
  width: calc(200%/var(--numOfColumns) - var(--ytd-rich-grid-item-margin) - 0.01px) !important;
}
ytd-search yt-did-you-mean-renderer,
ytd-search yt-showing-results-for-renderer,
ytd-search ytd-thumbnail.ytd-video-renderer,
ytd-search ytd-playlist-thumbnail.ytd-radio-renderer,
ytd-search ytd-playlist-thumbnail.ytd-playlist-renderer,
ytd-search ytd-playlist-thumbnail.ytd-show-renderer {
  min-width: 100% !important;
}
ytd-search ytd-playlist-thumbnail.ytd-show-renderer {
  flex: 0 !important;
}
ytd-search ytd-playlist-thumbnail.ytd-playlist-renderer {
  margin: 0 !important;
}
ytd-search .thumbnail-container.ytd-movie-renderer {
  min-width: 0 !important;
}
ytd-search ytd-item-section-renderer[top-spacing-zero]:first-child #contents.ytd-item-section-renderer .ytd-item-section-renderer:first-child:not(yt-did-you-mean-renderer):not(yt-showing-results-for-renderer) {
  margin-top: 16px;
}
ytd-search #dismissible.ytd-video-renderer,
ytd-search ytd-radio-renderer,
ytd-search ytd-playlist-renderer,
ytd-search #content-section.ytd-channel-renderer,
ytd-search #info-section.ytd-channel-renderer,
ytd-search ytd-show-renderer {
  flex-direction: column;
}
ytd-search #video-title {
  font-size: 1.6rem !important;
  line-height: 2.2rem !important;
  font-weight: 500 !important;
}
ytd-search h3:not(.ytd-movie-renderer) {
  margin: 12px 0 4px 0 !important;
}
ytd-search #channel-title.ytd-channel-renderer {
  font-size: 1.6rem;
  line-height: 2.2rem;
  font-weight: 500;
  margin: 12px 0 4px 0;
  align-self: center;
}
ytd-search ytd-video-meta-block:not([rich-meta]) .ytd-video-meta-block:is(#metadata-line, #byline-container),
ytd-search #metadata.ytd-channel-renderer {
  font-size: 1.4rem;
  line-height: 2rem;
  max-height: 3.6rem;
}
ytd-search #content.ytd-playlist-renderer,
ytd-search #content.ytd-radio-renderer,
ytd-search #info-section.ytd-channel-renderer {
  flex-basis: 100%;
}
ytd-search #info.ytd-channel-renderer {
  padding: 0 0px 16px 0;
  text-align: center;
}
ytd-search .ytd-channel-renderer yt-formatted-string {
  text-align: center !important;
}
ytd-search #avatar-section.ytd-channel-renderer {
  min-width: 100% !important;
}
ytd-search .ytd-channel-renderer:is(#buttons, #purchase-button, #subscribe-button) {
  padding: 0 !important;
  align-self: center;
}
ytd-search #badges.ytd-video-renderer {
  margin: 4px 0 0 0;
}
ytd-search .text-wrapper.ytd-video-renderer {
  position: relative;
  width: 100%;
}
ytd-search #channel-thumbnail.ytd-video-renderer {
  position: absolute;
  top: 12px;
}
ytd-search yt-img-shadow.ytd-video-renderer img.yt-img-shadow {
  width: 36px;
  height: 36px;
}
ytd-search ytd-video-renderer[use-search-ui] #channel-info.ytd-video-renderer {
  padding: 0;
}
body[dir="ltr"] ytd-search ytd-menu-renderer.ytd-video-renderer {
  position: absolute;
  right: -12px;
  margin: 4px 0 0 0;
}
body[dir="ltr"] ytd-search #title-wrapper.ytd-video-renderer {
  padding-right: 24px;
}
body[dir="ltr"] ytd-search .ytd-video-renderer:is(#title-wrapper, #channel-name, #badges, #buttons),
body[dir="ltr"] ytd-search ytd-video-meta-block.ytd-video-renderer {
  padding-left: 48px;
}
body[dir="rtl"] ytd-search ytd-menu-renderer.ytd-video-renderer {
  position: absolute;
  left: -12px;
  margin: 4px 0 0 0;
}
body[dir="rtl"] ytd-search #title-wrapper.ytd-video-renderer {
  padding-left: 24px;
}
body[dir="rtl"] ytd-search .ytd-video-renderer:is(#title-wrapper, #channel-name, #badges, #buttons),
body[dir="rtl"] ytd-search ytd-video-meta-block.ytd-video-renderer {
  padding-right: 48px;
}
.channelSearch #description-text.ytd-video-renderer,
.channelSearch #list.ytd-playlist-renderer {
  display: none;
}
.channelSearch #metadata.ytd-video-meta-block,
.channelSearch #view-more.ytd-playlist-renderer {
  display: block;
}
.channelSearch ytd-browse[page-subtype=channels] ytd-two-column-browse-results-renderer {
  width: calc(100% - 32px) !important;
  max-width: calc(var(--numOfColumns) * (var(--ytd-rich-grid-item-max-width) + var(--ytd-rich-grid-item-margin))) !important;
}
.channelSearch #contents.ytd-item-section-renderer,
.channelSearch ytd-item-section-renderer.ytd-section-list-renderer {
  display: contents;
}
.channelSearch #contents.ytd-section-list-renderer {
  display: flex;
  flex-wrap: wrap;
}
.channelSearch ytd-video-renderer,
.channelSearch ytd-playlist-renderer,
.channelSearch ytd-show-renderer {
  width: calc(100% / var(--numOfColumns) - var(--ytd-rich-grid-item-margin) - 0.01px);
  margin-left: calc(var(--ytd-rich-grid-item-margin) / 2);
  margin-right: calc(var(--ytd-rich-grid-item-margin) / 2);
  margin-bottom: 24px;
}
.channelSearch ytd-thumbnail.ytd-video-renderer,
.channelSearch ytd-playlist-thumbnail.ytd-playlist-renderer,
.channelSearch ytd-playlist-thumbnail.ytd-show-renderer {
  width: 100% !important;
  height: 100% !important;
  flex: 0 !important;
}
.channelSearch ytd-thumbnail.ytd-video-renderer:before,
.channelSearch ytd-playlist-thumbnail.ytd-playlist-renderer:before,
.channelSearch ytd-playlist-thumbnail.ytd-show-renderer:before {
  display: block;
  content: "";
  padding-top: 56.11%;
}
.channelSearch #dismissible.ytd-video-renderer,
.channelSearch ytd-playlist-renderer,
.channelSearch ytd-show-renderer {
  flex-direction: column;
}
.channelSearch #video-title {
  font-size: 1.6rem !important;
  line-height: 2.2rem !important;
  font-weight: 500 !important;
}
.channelSearch ytd-video-meta-block:not([rich-meta]) .ytd-video-meta-block:is(#byline-container, #metadata-line) {
  font-size: 1.4rem;
  line-height: 2rem;
  max-height: 3.6rem;
}
.channelSearch .title-and-badge.ytd-video-renderer,
.channelSearch h3:is(.ytd-playlist-renderer, .ytd-show-renderer) {
  margin: 12px 0 4px 0;
}
.channelSearch #badges.ytd-video-renderer {
  margin: 4px 0 0 0;
}
.channelSearch #content.ytd-playlist-renderer {
  flex-basis: 100%;
}
.channelSearch .text-wrapper.ytd-video-renderer {
  max-width: 100%;
}
.channelSearch body[dir="ltr"] ytd-menu-renderer.ytd-video-renderer {
  position: absolute;
  right: -12px;
  margin-top: 4px;
}
.channelSearch body[dir="ltr"] #meta.ytd-video-renderer {
  padding-right: 24px;
}
.channelSearch body[dir="rtl"] ytd-menu-renderer.ytd-video-renderer {
  position: absolute;
  left: -12px;
  margin-top: 4px;
}
.channelSearch body[dir="rtl"] #meta.ytd-video-renderer {
  padding-left: 24px;
}

${GM_getValue('hideRightSidebar') ? `
ytd-secondary-search-container-renderer {
  display: none !important;
}
`:`
@media (min-width: 1091px) {
  #page-manager:has(ytd-search[role][has-secondary-content]) {
    --sidebarWidth: 425px;
  }
}
`}
`;