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.

  1. // ==UserScript==
  2. // @name YouTube: Search results in Grid view
  3. // @namespace https://greasyfork.org/users/1166888-pedro
  4. // @match https://www.youtube.com/*
  5. // @version 2024.11.8
  6. // @author Pedro
  7. // @icon https://i.imgur.com/DWVSLcD.png
  8. // @description See more results in one go, without irrelevant results, such as 'People also watched' and 'For you', in the way.
  9. // @contributionURL https://www.paypal.com/donate/?hosted_button_id=AF464CBPNVYB8
  10. // @grant GM_registerMenuCommand
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @compatible Chrome
  14. // @compatible Safari
  15. // @compatible Firefox
  16. // @license MIT
  17. // ==/UserScript==
  18. GM_registerMenuCommand('Settings', settingsMenu);
  19.  
  20. function settingsMenu() {
  21. try { trustedTypes.createPolicy('default', {createHTML: (string, sink) => string}); }
  22. catch {}
  23.  
  24. const menu = document.createElement('settings-menu');
  25. document.documentElement.appendChild(menu);
  26. menu.insertAdjacentHTML('afterbegin', `
  27. <div>
  28. <header>
  29. <span>Settings</span>
  30. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
  31. <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>
  32. </svg>
  33. </header>
  34. <label>
  35. <span>Maximum number of columns </span>
  36. <input type="number" id="maxNumOfColumns" value="${maxNumOfColumns}">
  37. </label>
  38. <label>
  39. <span>Minimum column width (px)</span>
  40. <input type="number" id="columnMinWidth" value="${columnMinWidth}">
  41. </label>
  42. <label>
  43. <span>Hide right sidebar</span>
  44. <input type="checkbox" id="hideRightSidebar" ${GM_getValue('hideRightSidebar') ? 'checked' : ''}>
  45. </label>
  46. <style>
  47. settings-menu svg {
  48. color: var(--background-3);
  49. width: 24px;
  50. height: 24px;
  51. transition: 0.4s;
  52. color: var(--text);
  53. opacity: .7;
  54. }
  55.  
  56. settings-menu svg:hover {
  57. transform: rotate(-90deg);
  58. opacity: 1;
  59. }
  60.  
  61. settings-menu svg:active {
  62. transform: scale(1.5);
  63. }
  64.  
  65. settings-menu div {
  66. margin: 10px;
  67. }
  68.  
  69. settings-menu {
  70. width: 310px;
  71. position: fixed;
  72. background: var(--background);
  73. top: 20px;
  74. right: 20px;
  75. z-index: 9999;
  76. color: var(--text);
  77. font-size: 1.4rem;
  78. border-radius: 20px;
  79. box-shadow: 0 4px 32px 0 rgba(0, 0, 0, 0.3);
  80. font-weight: 400;
  81. border: 1px solid var(--border);
  82. }
  83.  
  84. settings-menu header {
  85. font-size: 1.7rem;
  86. font-weight: 500;
  87. }
  88.  
  89. settings-menu header,
  90. settings-menu label {
  91. padding: 6px;
  92. display: flex;
  93. align-items: center;
  94. }
  95.  
  96. settings-menu svg,
  97. settings-menu label {
  98. cursor: pointer;
  99. }
  100.  
  101. settings-menu span {
  102. flex-grow: 1;
  103. }
  104.  
  105. settings-menu [type="number"] {
  106. font-family: "Roboto";
  107. font-size: inherit;
  108. box-sizing: border-box;
  109. border: none;
  110. width: 60px;
  111. height: 30px;
  112. background: var(--background-2);
  113. color: inherit;
  114. outline: none;
  115. border-radius: 6px;
  116. padding: 0 3px;
  117. }
  118.  
  119. settings-menu [type="number"]::-webkit-inner-spin-button {
  120. height: 30px;
  121. }
  122.  
  123. settings-menu [type="checkbox"] {
  124. appearance: none;
  125. -webkit-tap-highlight-color: transparent;
  126. position: relative;
  127. border: 0;
  128. outline: 0;
  129. width: 37.5px;
  130. height: 24px;
  131. cursor: pointer;
  132. }
  133.  
  134. settings-menu [type="checkbox"]:after {
  135. content: "";
  136. width: 100%;
  137. height: 100%;
  138. display: inline-block;
  139. border-radius: 100px;
  140. clear: both;
  141. background: var(--background-2);
  142. transition: background-color linear 0.08s;
  143. }
  144.  
  145. settings-menu [type="checkbox"]:checked:after {
  146. background: #1db954;
  147. }
  148.  
  149. settings-menu [type="checkbox"]:before {
  150. content: "";
  151. height: 19.5px;
  152. width: 19.5px;
  153. display: block;
  154. position: absolute;
  155. left: 0;
  156. top: 2px;
  157. border-radius: 50%;
  158. background: #fff;
  159. box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 2px 3px 0 rgba(0, 0, 0, 0.2);
  160. transform: translateX(2px);
  161. transition: transform linear 0.1s, background-color linear 0.08s;
  162. }
  163.  
  164. settings-menu [type="checkbox"]:checked:before {
  165. transform: translateX(80%);
  166. transition: transform linear 0.1s, background-color linear 0.08s;
  167. }
  168.  
  169. @media (prefers-color-scheme: dark) {
  170. :root {
  171. color-scheme: dark;
  172. --text: #f1f1f1;
  173. --background: #000;
  174. --background-2: rgba(255, 255, 255, .1);
  175. --border: rgba(255, 255, 255, .2);
  176. }
  177. }
  178.  
  179. @media (prefers-color-scheme: light) {
  180. :root {
  181. --text: #030303;
  182. --background: #fff;
  183. --background-2: rgba(0, 0, 0, .1);
  184. }
  185. }
  186. </style>
  187. </div>`);
  188.  
  189. menu.addEventListener('change', function(e) {
  190. if (e.target.type === 'number') {
  191. GM_setValue(e.target.id, e.target.value);
  192. if (e.target.id == 'maxNumOfColumns') maxNumOfColumns = GM_getValue('maxNumOfColumns');
  193. else columnMinWidth = GM_getValue('columnMinWidth');
  194. document.documentElement.style.setProperty('--numOfColumns', calcNumOfColumns() || 1);
  195. } else {
  196. GM_setValue(e.target.id, e.target.checked);
  197. }
  198. });
  199.  
  200. menu.querySelector('svg').addEventListener('click', function() {
  201. menu.remove();
  202. });
  203. }
  204.  
  205. let maxNumOfColumns = GM_getValue('maxNumOfColumns') || 6;
  206. let columnMinWidth = GM_getValue('columnMinWidth') || 326;
  207. const div = document.createElement('div');
  208. div.style = 'position: absolute; width: calc(100% - 32px - var(--sidebarWidth, 0px))';
  209.  
  210. document.addEventListener('yt-navigate-finish', function() {
  211. const pm = document.getElementById('page-manager');
  212. pm.style.position = 'relative';
  213. pm.appendChild(div);
  214.  
  215. new ResizeObserver(function() {
  216. document.documentElement.style.setProperty('--numOfColumns', calcNumOfColumns() || 1);
  217. }).observe(div);
  218. }, {once: true});
  219.  
  220. document.addEventListener('yt-navigate-finish', function() {
  221. if (/(@|\/c\/).*search/.test(window.location.href)) {
  222. document.documentElement.classList.add('channelSearch');
  223. } else {
  224. document.documentElement.classList.remove('channelSearch');
  225. }
  226. });
  227.  
  228. function calcNumOfColumns() {
  229. for (let i = maxNumOfColumns; i > 0; i--) {
  230. if (div.clientWidth / i >= columnMinWidth) return i;
  231. }
  232. }
  233.  
  234. const sheet = document.createElement('style');
  235. document.documentElement.appendChild(sheet);
  236. sheet.textContent = `
  237. ytd-search {
  238. padding-left: 16px !important;
  239. padding-right: 16px !important;
  240. }
  241. ytd-search ytd-search-pyv-renderer,
  242. ytd-search ytd-ad-slot-renderer,
  243. ytd-search .metadata-snippet-container-one-line.ytd-video-renderer,
  244. ytd-search .metadata-snippet-container.ytd-video-renderer,
  245. ytd-search #description-text.ytd-video-renderer,
  246. ytd-search #description.ytd-channel-renderer,
  247. ytd-search #list,
  248. ytd-search #expandable-metadata.ytd-video-renderer:not(:empty),
  249. ytd-search ytd-exploratory-results-renderer.ytd-item-section-renderer,
  250. ytd-search ytd-horizontal-card-list-renderer.ytd-item-section-renderer:not(:first-child),
  251. ytd-search ytd-reel-shelf-renderer.ytd-item-section-renderer,
  252. ytd-search ytd-shelf-renderer.ytd-item-section-renderer,
  253. ytd-search #channel-name.ytd-video-renderer,
  254. ytd-search #separator.ytd-video-meta-block {
  255. display: none !important;
  256. }
  257. ytd-search #metadata.ytd-video-meta-block,
  258. ytd-search #byline-container[hidden] {
  259. display: block !important;
  260. }
  261. ytd-search #container.ytd-search {
  262. max-width: calc(var(--numOfColumns) * (var(--ytd-rich-grid-item-max-width) + var(--ytd-rich-grid-item-margin)) + var(--sidebarWidth, 0px));
  263. min-width: calc(var(--sidebarWidth) + var(--ytd-rich-grid-item-max-width));
  264. }
  265. ytd-search #header.ytd-search,
  266. ytd-search ytd-two-column-search-results-renderer,
  267. ytd-search #primary.ytd-two-column-search-results-renderer {
  268. max-width: 100% !important;
  269. }
  270. ytd-search #contents > ytd-item-section-renderer,
  271. ytd-search #contents > ytd-item-section-renderer > #contents {
  272. display: contents;
  273. }
  274. ytd-search ytd-item-section-renderer[can-show-more]:after {
  275. /* Fix for elements appearing in wrong spots */
  276. content: "";
  277. width: 100%;
  278. min-height: 7000px;
  279. }
  280. ytd-search #contents.ytd-section-list-renderer {
  281. display: flex;
  282. flex-wrap: wrap;
  283. }
  284. ytd-search #contents > .ytd-item-section-renderer {
  285. margin-left: calc(var(--ytd-rich-grid-item-margin)/2);
  286. margin-right: calc(var(--ytd-rich-grid-item-margin)/2);
  287. width: calc(100%/var(--numOfColumns) - var(--ytd-rich-grid-item-margin) - 0.01px);
  288. margin-bottom: 24px;
  289. }
  290. ytd-search ytd-movie-renderer {
  291. width: calc(200%/var(--numOfColumns) - var(--ytd-rich-grid-item-margin) - 0.01px) !important;
  292. }
  293. ytd-search yt-did-you-mean-renderer,
  294. ytd-search yt-showing-results-for-renderer,
  295. ytd-search ytd-thumbnail.ytd-video-renderer {
  296. min-width: 100% !important;
  297. }
  298. ytd-search .yt-lockup-view-model-wiz__content-image {
  299. width: 100% !important;
  300. }
  301. ytd-search .thumbnail-container.ytd-movie-renderer {
  302. min-width: 0 !important;
  303. }
  304. 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) {
  305. margin-top: 16px;
  306. }
  307. ytd-search #dismissible.ytd-video-renderer,
  308. ytd-search .yt-lockup-view-model-wiz--horizontal,
  309. ytd-search #content-section.ytd-channel-renderer,
  310. ytd-search #info-section.ytd-channel-renderer,
  311. ytd-search ytd-show-renderer {
  312. flex-direction: column;
  313. }
  314. ytd-search #video-title,
  315. ytd-search .yt-lockup-metadata-view-model-wiz__title {
  316. font-size: 1.6rem !important;
  317. line-height: 2.2rem !important;
  318. font-weight: 500 !important;
  319. }
  320. ytd-search h3:not(.ytd-movie-renderer) {
  321. margin: 12px 0 4px 0 !important;
  322. }
  323. ytd-search #channel-title.ytd-channel-renderer {
  324. font-size: 1.6rem;
  325. line-height: 2.2rem;
  326. font-weight: 500;
  327. margin: 12px 0 4px 0;
  328. align-self: center;
  329. }
  330. ytd-search :is(#metadata-line, #byline-container),
  331. ytd-search .yt-content-metadata-view-model-wiz__metadata-text,
  332. ytd-search #metadata.ytd-channel-renderer {
  333. font-size: 1.4rem !important;
  334. line-height: 2rem !important;
  335. max-height: 3.6rem !important;
  336. }
  337. ytd-search #info.ytd-channel-renderer {
  338. padding: 0 0px 16px 0;
  339. text-align: center;
  340. }
  341. ytd-search .ytd-channel-renderer yt-formatted-string {
  342. text-align: center !important;
  343. }
  344. ytd-search #avatar-section.ytd-channel-renderer {
  345. min-width: 100% !important;
  346. }
  347. ytd-search .ytd-channel-renderer:is(#buttons, #purchase-button, #subscribe-button) {
  348. padding: 0 !important;
  349. align-self: center;
  350. }
  351. ytd-search #badges.ytd-video-renderer {
  352. margin: 4px 0 0 0;
  353. }
  354. ytd-search .text-wrapper.ytd-video-renderer {
  355. position: relative;
  356. width: 100%;
  357. }
  358. ytd-search #channel-thumbnail.ytd-video-renderer {
  359. position: absolute;
  360. top: 12px;
  361. }
  362. ytd-search yt-img-shadow.ytd-video-renderer img.yt-img-shadow {
  363. width: 36px;
  364. height: 36px;
  365. }
  366. ytd-search ytd-video-renderer[use-search-ui] #channel-info.ytd-video-renderer {
  367. padding: 0;
  368. }
  369. body[dir="ltr"] ytd-search ytd-menu-renderer.ytd-video-renderer {
  370. position: absolute;
  371. right: -12px;
  372. margin: 4px 0 0 0;
  373. }
  374. body[dir="ltr"] ytd-search #title-wrapper.ytd-video-renderer {
  375. padding-right: 24px;
  376. }
  377. body[dir="ltr"] ytd-search .ytd-video-renderer:is(#title-wrapper, #channel-name, #badges, #buttons),
  378. body[dir="ltr"] ytd-search ytd-video-meta-block.ytd-video-renderer {
  379. padding-left: 48px;
  380. }
  381. body[dir="rtl"] ytd-search ytd-menu-renderer.ytd-video-renderer {
  382. position: absolute;
  383. left: -12px;
  384. margin: 4px 0 0 0;
  385. }
  386. body[dir="rtl"] ytd-search #title-wrapper.ytd-video-renderer {
  387. padding-left: 24px;
  388. }
  389. body[dir="rtl"] ytd-search .ytd-video-renderer:is(#title-wrapper, #channel-name, #badges, #buttons),
  390. body[dir="rtl"] ytd-search ytd-video-meta-block.ytd-video-renderer {
  391. padding-right: 48px;
  392. }
  393. .channelSearch #description-text.ytd-video-renderer {
  394. display: none;
  395. }
  396. .channelSearch #metadata.ytd-video-meta-block,
  397. .channelSearch #view-more.ytd-playlist-renderer {
  398. display: block;
  399. }
  400. .channelSearch ytd-browse[page-subtype=channels] ytd-two-column-browse-results-renderer {
  401. width: calc(100% - 32px) !important;
  402. max-width: calc(var(--numOfColumns) * (var(--ytd-rich-grid-item-max-width) + var(--ytd-rich-grid-item-margin))) !important;
  403. }
  404. .channelSearch #contents.ytd-item-section-renderer,
  405. .channelSearch ytd-item-section-renderer.ytd-section-list-renderer {
  406. display: contents;
  407. }
  408. .channelSearch #contents.ytd-section-list-renderer {
  409. display: flex;
  410. flex-wrap: wrap;
  411. }
  412. .channelSearch ytd-video-renderer,
  413. .channelSearch ytd-playlist-renderer,
  414. .channelSearch ytd-show-renderer {
  415. width: calc(100% / var(--numOfColumns) - var(--ytd-rich-grid-item-margin) - 0.01px);
  416. margin-left: calc(var(--ytd-rich-grid-item-margin) / 2);
  417. margin-right: calc(var(--ytd-rich-grid-item-margin) / 2);
  418. margin-bottom: 24px;
  419. }
  420. .channelSearch ytd-thumbnail.ytd-video-renderer,
  421. .channelSearch ytd-playlist-thumbnail.ytd-playlist-renderer,
  422. .channelSearch ytd-playlist-thumbnail.ytd-show-renderer {
  423. width: 100% !important;
  424. height: 100% !important;
  425. flex: 0 !important;
  426. }
  427. .channelSearch ytd-thumbnail.ytd-video-renderer:before,
  428. .channelSearch ytd-playlist-thumbnail.ytd-playlist-renderer:before,
  429. .channelSearch ytd-playlist-thumbnail.ytd-show-renderer:before {
  430. display: block;
  431. content: "";
  432. padding-top: 56.11%;
  433. }
  434. .channelSearch #dismissible.ytd-video-renderer,
  435. .channelSearch ytd-playlist-renderer,
  436. .channelSearch ytd-show-renderer {
  437. flex-direction: column;
  438. }
  439. .channelSearch #video-title:not(.ytd-child-video-renderer) {
  440. font-size: 1.6rem !important;
  441. line-height: 2.2rem !important;
  442. font-weight: 500 !important;
  443. }
  444. .channelSearch :is(#byline-container, #metadata-line) {
  445. font-size: 1.4rem !important;
  446. line-height: 2rem !important;
  447. max-height: 3.6rem !important;
  448. }
  449. .channelSearch .title-and-badge.ytd-video-renderer,
  450. .channelSearch h3:is(.ytd-playlist-renderer, .ytd-show-renderer) {
  451. margin: 12px 0 4px 0;
  452. }
  453. .channelSearch #badges.ytd-video-renderer {
  454. margin: 4px 0 0 0;
  455. }
  456. .channelSearch #content.ytd-playlist-renderer {
  457. flex-basis: 100%;
  458. }
  459. .channelSearch .text-wrapper.ytd-video-renderer {
  460. max-width: 100%;
  461. }
  462. .channelSearch body[dir="ltr"] ytd-menu-renderer.ytd-video-renderer {
  463. position: absolute;
  464. right: -12px;
  465. margin-top: 4px;
  466. }
  467. .channelSearch body[dir="ltr"] #meta.ytd-video-renderer {
  468. padding-right: 24px;
  469. }
  470. .channelSearch body[dir="rtl"] ytd-menu-renderer.ytd-video-renderer {
  471. position: absolute;
  472. left: -12px;
  473. margin-top: 4px;
  474. }
  475. .channelSearch body[dir="rtl"] #meta.ytd-video-renderer {
  476. padding-left: 24px;
  477. }
  478.  
  479. ${GM_getValue('hideRightSidebar') ? `
  480. ytd-secondary-search-container-renderer {
  481. display: none !important;
  482. }
  483. `:`
  484. @media (min-width: 1091px) {
  485. #page-manager:has(ytd-search[role][has-secondary-content]) {
  486. --sidebarWidth: 425px;
  487. }
  488. }
  489. `}
  490. `;