Return YouTube Grid Layout

Force YouTube grid layout to show 1~6 videos per row responsively, and scale up thumbnails on wide screens

目前为 2025-04-20 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Return YouTube Grid Layout
  3. // @namespace Return YouTube Grid Layout
  4. // @version 1.1
  5. // @description Force YouTube grid layout to show 1~6 videos per row responsively, and scale up thumbnails on wide screens
  6. // @author DOGJIP
  7. // @match https://www.youtube.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14.  
  15. const STYLE_ID = 'custom-grid-style';
  16.  
  17. function getItemsPerRow(width) {
  18. if (width >= 2000) return 6;
  19. if (width >= 1700) return 5;
  20. if (width >= 1400) return 4;
  21. if (width >= 1100) return 3;
  22. if (width >= 800) return 2;
  23. return 1;
  24. }
  25.  
  26. function getItemWidth(width, itemsPerRow) {
  27. const containerWidth = width - 96;
  28. const totalMargin = 16 * (itemsPerRow - 1);
  29. const itemWidth = Math.floor((containerWidth - totalMargin) / itemsPerRow);
  30.  
  31. const maxDefault = 300;
  32. const minDefault = 220;
  33.  
  34. const maxW = Math.min(Math.max(itemWidth, maxDefault), 400);
  35. const minW = Math.min(Math.max(itemWidth - 20, minDefault), maxW - 10);
  36.  
  37. return { maxW, minW };
  38. }
  39.  
  40. function generateStyle(width) {
  41. const n = getItemsPerRow(width);
  42. const { maxW, minW } = getItemWidth(width, n);
  43.  
  44. return `
  45. ytd-rich-grid-renderer {
  46. --ytd-rich-grid-item-max-width: ${maxW}px !important;
  47. --ytd-rich-grid-item-min-width: ${minW}px !important;
  48. --ytd-rich-grid-row-margin: 32px !important;
  49. --ytd-rich-grid-items-per-row: ${n} !important;
  50. --ytd-rich-grid-item-margin: 16px !important;
  51. --ytd-rich-grid-posts-per-row: 3 !important;
  52. --ytd-rich-grid-slim-items-per-row: ${n} !important;
  53. --ytd-rich-grid-game-cards-per-row: ${n} !important;
  54. --ytd-rich-grid-mini-game-cards-per-row: ${n} !important;
  55. --ytd-rich-grid-content-offset-top: 56px !important;
  56. }
  57. `;
  58. }
  59.  
  60. function isExcludedPage(path) {
  61. return /^\/@[^\/]+\/(?:videos|streams)\/?$/.test(path);
  62. }
  63.  
  64. function applyStyle() {
  65. if (isExcludedPage(location.pathname)) {
  66. const old = document.getElementById(STYLE_ID);
  67. if (old) old.remove();
  68. return;
  69. }
  70.  
  71. const old = document.getElementById(STYLE_ID);
  72. if (old) old.remove();
  73.  
  74. const styleEl = document.createElement('style');
  75. styleEl.id = STYLE_ID;
  76. styleEl.textContent = generateStyle(window.innerWidth);
  77. document.head.appendChild(styleEl);
  78. }
  79.  
  80. window.addEventListener('load', () => setTimeout(applyStyle, 500));
  81. window.addEventListener('resize', () => setTimeout(applyStyle, 200));
  82.  
  83. const observer = new MutationObserver(() => {
  84. applyStyle();
  85. });
  86. observer.observe(document.body, { childList: true, subtree: true });
  87. })();