Youtube play all from channel

add button to play all videos from channel

  1. // ==UserScript==
  2. // @name Youtube play all from channel
  3. // @namespace https://greasyfork.org/users/821661
  4. // @match https://www.youtube.com/*
  5. // @grant none
  6. // @version 1.2
  7. // @author hdyzen
  8. // @description add button to play all videos from channel
  9. // @license MIT
  10. // ==/UserScript==
  11. 'use strict';
  12.  
  13. // Get channel id
  14. async function getChannelId() {
  15. try {
  16. const response = await fetch(window.location.href);
  17.  
  18. if (!response.ok) {
  19. throw new Error('Error loading data');
  20. }
  21.  
  22. const data = await response.text();
  23. const result = /(?<="channelId":)"(.*?)"/.exec(data);
  24.  
  25. return `UU${result[1].substring(2)}`;
  26. } catch (error) {
  27. console.error('Error:', error);
  28. }
  29. }
  30.  
  31. // Add param to url
  32. function addParam(url, key = 'list', value) {
  33. const urlObj = new URL(url);
  34. urlObj.searchParams.set(key, value);
  35. return urlObj.toString();
  36. }
  37.  
  38. // Add play all button style
  39. (function addBtnStyle() {
  40. const btnStyle = document.createElement('style');
  41.  
  42. btnStyle.textContent = `
  43. #playAll {
  44. background-color: var(--yt-spec-badge-chip-background);
  45. color: var(--yt-spec-text-primary);
  46. transition: background-color .5s cubic-bezier(.05,0,0,1);
  47. height: 32px;
  48. min-width: 12px;
  49. padding: 0 10px;
  50. border-radius: 8px;
  51. box-sizing: border-box;
  52. outline: none;
  53. overflow: hidden;
  54. cursor: pointer;
  55. user-select: none;
  56. position: relative;
  57. font-family: "Roboto","Arial",sans-serif;
  58. font-size: 1.4rem;
  59. line-height: 2rem;
  60. font-weight: 500;
  61. -moz-box-orient: horizontal;
  62. -moz-box-direction: normal;
  63. flex-direction: row;
  64. -moz-box-align: center;
  65. align-items: center;
  66. display: inline-flex;
  67. text-wrap: nowrap;
  68. text-decoration: none;
  69. }
  70. #playAll:hover {
  71. background-color: var(--yt-spec-button-chip-background-hover);
  72. }
  73. iron-selector#chips yt-chip-cloud-chip-renderer + #playAll {
  74. margin-left: 12px;
  75. }
  76. #owner #playAll {
  77. padding: 0 16px;
  78. height: 36px;
  79. font-size: 14px;
  80. line-height: 36px;
  81. border-radius: 18px;
  82. margin-left: 8px;
  83. }
  84. #header.ytd-rich-grid-renderer:has(> #playAll) {
  85. margin-top: 16px;
  86. margin-bottom: -8px;
  87. display: unset !important;
  88. }
  89. `;
  90.  
  91. document.head.appendChild(btnStyle);
  92. })();
  93.  
  94. // Create/Update play all button
  95. document.addEventListener('yt-page-data-updated', async e => {
  96. if (!/\/videos$|^\/watch/.test(window.location.pathname)) return;
  97.  
  98. const playAllButton = document.querySelector(':is(ytd-watch-flexy, ytd-browse[page-subtype="channels"]):not([hidden]) #playAll');
  99. const channelId = await getChannelId();
  100. const toAppend = document.querySelector(':is(ytd-browse[page-subtype="channels"], ytd-watch-flexy):not([hidden]) :is(iron-selector#chips, #owner.ytd-watch-metadata), #header.ytd-rich-grid-renderer[hidden]:empty');
  101. const getFistVideo = document.getElementById('video-title-link');
  102.  
  103. if (!playAllButton && channelId && toAppend) {
  104. const aEl = document.createElement('a');
  105. aEl.textContent = 'Play All';
  106. aEl.id = 'playAll';
  107. aEl.href = window.location.pathname === '/watch' ? addParam(document.URL, 'list', channelId) : addParam(getFistVideo.href, 'list', channelId);
  108. toAppend.appendChild(aEl);
  109. }
  110.  
  111. if (playAllButton) {
  112. playAllButton.href = window.location.pathname === '/watch' ? addParam(document.URL, 'list', channelId) : addParam(getFistVideo.href, 'list', channelId);
  113. }
  114. });