YT LIVE CHAT NEW TAB BUTTON

Adds a live chat button that opens chat in new window

  1. // ==UserScript==
  2. // @name YT LIVE CHAT NEW TAB BUTTON
  3. // @icon https://static-00.iconduck.com/assets.00/youtube-chat-icon-468x512-k45kpail.png
  4. // @name:pl Przycisk Live Chat YouTube
  5. // @namespace https://tampermonkey.net/
  6. // @version 1.1
  7. // @license MIT
  8. // @description Adds a live chat button that opens chat in new window
  9. // @description:pl Dodaje przycisk czatu na żywo otwierający okno czatu w nowym oknie przeglądarki
  10. // @author 「❗■ ͜ʖ■ ꍏռꪮռʏꪑꪮꪊsɨꀘꍟའའꪮ 」
  11. // @match https://www.youtube.com/*
  12. // @match https://m.youtube.com/*
  13. // @match https://youtu.be/*
  14. // @grant none
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19. const translations = {
  20. 'pl': {
  21. buttonText: '💭 Czat na żywo',
  22. windowTitle: 'CHAT NA ŻYWO'
  23. },
  24. 'en': {
  25. buttonText: '💭 Live Chat',
  26. windowTitle: 'LIVE CHAT'
  27. }
  28. };
  29.  
  30. function getLanguage() {
  31. const htmlLang = document.documentElement.lang;
  32. if (htmlLang && htmlLang.startsWith('pl')) return 'pl';
  33. const browserLang = navigator.language || navigator.userLanguage;
  34. if (browserLang && browserLang.startsWith('pl')) return 'pl';
  35. return 'en';
  36. }
  37.  
  38. function getText(key) {
  39. const lang = getLanguage();
  40. return translations[lang]?.[key] || translations['en'][key];
  41. }
  42.  
  43. function getVideoId() {
  44. const url = new URL(window.location.href);
  45. if (url.hostname.includes('youtube.com')) {
  46. return url.searchParams.get('v') || url.pathname.split('/').pop();
  47. }
  48. if (url.hostname === 'youtu.be') {
  49. return url.pathname.substring(1);
  50. }
  51. return null;
  52. }
  53.  
  54. function addLiveChatButton() {
  55. // Checking if we are on the right page
  56. if (window.location.hostname === 'youtu.be' &&
  57. (!window.location.pathname || window.location.pathname === '/')) return;
  58. if (window.location.hostname.includes('youtube.com') &&
  59. !window.location.pathname.includes('/watch')) return;
  60. // Prevent button from being added multiple times
  61. if (document.getElementById('ferroLiveChatBtn')) return;
  62.  
  63. const liveChatBtn = document.createElement('button');
  64. liveChatBtn.id = 'ferroLiveChatBtn';
  65. liveChatBtn.innerHTML = getText('buttonText');
  66. liveChatBtn.style.cssText = `
  67. background-color: #cc0000;
  68. color: white;
  69. border: none;
  70. border-radius: 2px;
  71. padding: 8px 16px;
  72. margin: 8px;
  73. cursor: pointer;
  74. font-family: Roboto, Arial, sans-serif;
  75. font-size: 14px;
  76. font-weight: 500;
  77. display: flex;
  78. align-items: center;
  79. gap: 6px;
  80. z-index: 1000;
  81. `;
  82.  
  83. liveChatBtn.onmouseover = function() {
  84. this.style.backgroundColor = '#990000';
  85. };
  86. liveChatBtn.onmouseout = function() {
  87. this.style.backgroundColor = '#cc0000';
  88. };
  89. liveChatBtn.onclick = function() {
  90. const videoId = getVideoId();
  91. if (videoId) {
  92. const chatUrl = `https://www.youtube.com/live_chat?v=${videoId}`;
  93. window.open(chatUrl, getText('windowTitle'), 'width=400,height=600,resizable=yes,scrollbars=yes');
  94. }
  95. };
  96.  
  97. // Multiple attempts to find a container for a button
  98. const possibleContainers = [
  99. document.querySelector('#top-level-buttons-computed'),
  100. document.querySelector('.slim-video-action-bar-actions'),
  101. document.querySelector('#actions.ytd-video-primary-info-renderer'),
  102. document.querySelector('ytd-menu-renderer.ytd-video-primary-info-renderer')
  103. ];
  104.  
  105. const actionButtons = possibleContainers.find(container => container);
  106. if (actionButtons) {
  107. actionButtons.appendChild(liveChatBtn);
  108. }
  109. }
  110.  
  111. // Listening for page change events
  112. window.addEventListener('load', addLiveChatButton);
  113. window.addEventListener('yt-navigate-finish', addLiveChatButton);
  114.  
  115. // Emergency interval
  116. const checkInterval = setInterval(() => {
  117. const possibleContainers = [
  118. document.querySelector('#top-level-buttons-computed'),
  119. document.querySelector('.slim-video-action-bar-actions'),
  120. document.querySelector('#actions.ytd-video-primary-info-renderer'),
  121. document.querySelector('ytd-menu-renderer.ytd-video-primary-info-renderer')
  122. ];
  123.  
  124. const actionButtons = possibleContainers.find(container => container);
  125. if (actionButtons) {
  126. addLiveChatButton();
  127. clearInterval(checkInterval);
  128. }
  129. }, 1000);
  130.  
  131. // Interval time limit
  132. setTimeout(() => clearInterval(checkInterval), 10000);
  133. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址