Advertisement
Guest User

Youtube Special Comment Sticker Tapermonkey

a guest
Sep 5th, 2020
528
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Youtube Special Comment Sticker
  3. // @namespace    http://tampermonkey.net/
  4. // @version      0.1
  5. // @description  try to take over the world!
  6. // @author       You
  7. // @include https://www.youtube.com/live_chat*
  8. // @grant        none
  9. // ==/UserScript==
  10.  
  11. (() => {
  12.     let IS_DARK = document.querySelector('html').hasAttribute('dark');
  13.  
  14.     let canScroll = true;
  15.     let chat;
  16.     let itemScroller;
  17.     let scrollButton;
  18.     let sticky;
  19.     let stickyItems;
  20.     let stickyItemsContainer;
  21.     let toggleSticky;
  22.     let toggleStickyText;
  23.  
  24.     let scrollSticky = () => {
  25.         if (canScroll) {
  26.             stickyItems.scrollTop = stickyItems.scrollHeight;
  27.         }
  28.     }
  29.  
  30.     let isSpecial = (authorElement) => {
  31.         return authorElement.classList.contains('moderator') || authorElement.classList.contains('owner');
  32.     };
  33.  
  34.     let stickItem = (node) => {
  35.         let authorElement = node.querySelector('#author-name');
  36.         if (authorElement && isSpecial(authorElement)) {
  37.             let stickyItem = document.createElement('div');
  38.             let authorPhoto = document.createElement('div');
  39.             let content = document.createElement('div');
  40.             let timestamp = document.createElement('span');
  41.             let author = document.createElement('div');
  42.             let authorName = document.createElement('span');
  43.             content.id = 'content';
  44.             stickyItem.classList.add('sticky-item');
  45.             content.classList.add('style-scope', 'yt-live-chat-text-message-renderer');
  46.             timestamp.classList.add('timestamp');
  47.             author.classList.add('author');
  48.             authorName.classList.add('author-name');
  49.             authorElement.classList.contains('owner') ? authorName.classList.add('owner') : null;
  50.             authorPhoto.innerHTML = node.querySelector('#author-photo').outerHTML.replace(/(\<|\/)(yt\-img\-shadow)/g, '$1div');
  51.             timestamp.innerText = node.querySelector('#timestamp').innerText;
  52.             authorName.innerText = authorElement.innerText;
  53.             author.append(authorName);
  54.             content.append(timestamp);
  55.             content.append(author);
  56.             content.append(node.querySelector('#message').cloneNode(true));
  57.             stickyItem.append(authorPhoto.firstChild);
  58.             stickyItem.append(content);
  59.             stickyItems.append(stickyItem);
  60.  
  61.             if (sticky.style.display === 'none') {
  62.                 chat = document.querySelector('#chat');
  63.                 itemScroller = chat.querySelector('#item-scroller');
  64.                 sticky.style.display = 'inherit';
  65.                 chat.setAttribute('style', `max-height: ${chat.offsetHeight - sticky.offsetHeight}px;`);
  66.                 itemScroller.scrollTop = itemScroller.scrollHeight;
  67.             }
  68.  
  69.             scrollSticky();
  70.         }
  71.     };
  72.  
  73.     let monitor = () => {
  74.         let chatItems = document.querySelector('#items.style-scope.yt-live-chat-item-list-renderer');
  75.         let observer = new MutationObserver((mutations) => {
  76.             mutations.forEach((mutation) => {
  77.                 mutation.addedNodes.forEach(stickItem);
  78.             });
  79.         });
  80.         chatItems.querySelectorAll('yt-live-chat-text-message-renderer').forEach(stickItem);
  81.         observer.observe(chatItems, { childList: true });
  82.     };
  83.  
  84.     let setUpCss = () => {
  85.         let style = document.createElement('style');
  86.         document.head.appendChild(style);
  87.         style.sheet.insertRule('#sticky {position: relative;}');
  88.         style.sheet.insertRule('#sticky #show-hide-button {border-bottom: #e0e0e0 solid 1px; font-size: 11px;}');
  89.         style.sheet.insertRule('#sticky #show-hide-button div {font-size: 11px;}');
  90.         style.sheet.insertRule('#sticky #show-hide-button div a {color: #11111199; display: flex;}');
  91.         style.sheet.insertRule('#sticky #show-hide-button div a:hover {color: #030303;}');
  92.         style.sheet.insertRule('#sticky #show-hide-button div a #button {border-radius: 0; margin: 0; padding: 8px 24px; width: 100%;}');
  93.         style.sheet.insertRule('#sticky #show-hide-button div a #button #text {font-weight: 500;}');
  94.         style.sheet.insertRule('#sticky #chat-header {box-sizing: border-box; display: flex; border-bottom: #e0e0e0 solid 1px; background-color: #fffffffa; height: 150px; padding: 0 0 0 4px; transition: all .15s cubic-bezier(0.0, 0.0, 0.2, 1);}');
  95.         style.sheet.insertRule('#sticky yt-icon-button {z-index: 0; transition: all .15s cubic-bezier(0.0, 0.0, 0.2, 1); visibility: hidden;}');
  96.         style.sheet.insertRule('#sticky #primary-content {height: inherit; overflow-x: hidden;}');
  97.         style.sheet.insertRule('#sticky #primary-content::-webkit-scrollbar {content: "";}');
  98.         style.sheet.insertRule('#sticky #primary-content::-webkit-scrollbar-track {background-color: #f1f1f1;}');
  99.         style.sheet.insertRule('#sticky #primary-content::-webkit-scrollbar-thumb {border: 2px solid #f1f1f1; min-height: 30px;}');
  100.         style.sheet.insertRule('#sticky #primary-content .sticky-item {padding: 4px; font-size: 13px; display: flex;}');
  101.         style.sheet.insertRule('#sticky #primary-content .sticky-item #author-photo {display: inline-table;}');
  102.         style.sheet.insertRule('#sticky #primary-content .sticky-item #img {max-width: inherit;}');
  103.         style.sheet.insertRule('#sticky #primary-content .timestamp {display: inline; color: #11111166; font-size: 11px; margin-right: 8px;}');
  104.         style.sheet.insertRule('#sticky #primary-content .author {display: inline-flex; margin-right: 8px;}');
  105.         style.sheet.insertRule('#sticky #primary-content .author .author-name {color: #5f84f1; font-weight: 500;}');
  106.         style.sheet.insertRule('#sticky #primary-content .author .author-name.owner {color: #000000de; background-color: #ffd600; padding: 2px 4px; border-radius: 2px;}');
  107.         style.sheet.insertRule('#sticky #primary-content #message {display: inline; line-height: 17px;}');
  108.         style.sheet.insertRule('#sticky.dark #show-hide-button {border-color: #303030; background-color: #181818;}');
  109.         style.sheet.insertRule('#sticky.dark #show-hide-button div a {color: #ffffffb3;}');
  110.         style.sheet.insertRule('#sticky.dark #show-hide-button div a:hover {color: #ffffff;}');
  111.         style.sheet.insertRule('#sticky.dark #chat-header {border-color: #303030; background-color: #202020;}');
  112.         style.sheet.insertRule('#sticky.dark #primary-content::-webkit-scrollbar-track {background-color: #0f0f0f;}');
  113.         style.sheet.insertRule('#sticky.dark #primary-content::-webkit-scrollbar-thumb {background-color: hsla(0, 0%, 53.3%, .2); border-color: #0f0f0f;');
  114.         style.sheet.insertRule('#sticky.dark #primary-content .timestamp {color: #ffffff8a;}');
  115.         style.sheet.insertRule('#sticky.dark #primary-content .author .author-name {color: #5e84f1;}');
  116.         style.sheet.insertRule('#sticky.dark #primary-content .author .author-name.owner {color: #111111;}');
  117.         style.sheet.insertRule('#sticky.hide-timestamps #primary-content .timestamp {display: none;}');
  118.     };
  119.  
  120.     let setUpSticky = () => {
  121.         let hideTimestamp = document.querySelector('yt-live-chat-renderer').hasAttribute('hide-timestamps');
  122.         let stickyAnchor = document.querySelector('yt-live-chat-app');
  123.         sticky = document.createElement('div');
  124.  
  125.         sticky.id = 'sticky';
  126.         sticky.setAttribute('class', `style-scope ytd-watch-flexy ${IS_DARK ? 'dark' : ''} ${hideTimestamp ? 'hide-timestamps': ''}`);
  127.         sticky.style.display = 'none';
  128.         sticky.innerHTML = '<div id="show-hide-button" class="style-scope ytd-live-chat-frame"><div class="style-scope ytd-live-chat-frame" use-keyboard-focused="" is-paper-button="" button-renderer="true"><a class="yt-simple-endpoint style-scope ytd-toggle-button-renderer" tabindex="-1"><paper-button id="button" class="style-scope ytd-toggle-button-renderer" role="button" tabindex="0" animated="" elevation="0" aria-disabled="false"><yt-formatted-string id="text" class="style-scope ytd-toggle-button-renderer"></yt-formatted-string><paper-ripple class="style-scope paper-button"><div id="background" class="style-scope paper-ripple"></div><div id="waves" class="style-scope paper-ripple"></div></paper-ripple></paper-button></a></div></div>'
  129.         sticky.innerHTML += '<div id="chat-header" role="heading" class="style-scope yt-live-chat-renderer"><div id="primary-content" class="style-scope yt-live-chat-header-renderer"></div>';
  130.         sticky.innerHTML += '<yt-icon-button id="show-more" class="style-scope yt-live-chat-item-list-renderer" style="transform: translateY(42px);"><button id="button" class="style-scope yt-icon-button"><button id="button" class="style-scope yt-icon-button" aria-label="More comments below"><yt-icon icon="down_arrow" class="style-scope yt-live-chat-item-list-renderer"><svg viewBox="0 0 24 24" preserveAspectRatio="xMidYMid meet" focusable="false" class="style-scope yt-icon" style="pointer-events: none; display: block; width: 100%; height: 100%;"><g class="style-scope yt-icon"><path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" class="style-scope yt-icon"></path></g></svg></yt-icon></button></button><paper-ripple class="style-scope yt-icon-button circle"><div id="background" class="style-scope paper-ripple" style="opacity: 0.006272;"></div><div id="waves" class="style-scope paper-ripple"></div></paper-ripple></yt-icon-button>'
  131.         stickyItemsContainer = sticky.querySelector('#chat-header');
  132.         toggleSticky = sticky.querySelector('#show-hide-button');
  133.         toggleStickyText = toggleSticky.querySelector('#text');
  134.         scrollButton = sticky.querySelector('yt-icon-button');
  135.         scrollButton.querySelector('#button').style.height = 'auto';
  136.  
  137.         stickyAnchor.parentNode.insertBefore(sticky, stickyAnchor);
  138.         stickyAnchor.style.position = 'relative';
  139.         toggleStickyText.innerText = 'Hide Sticky';
  140.  
  141.         sticky.querySelectorAll('#title, #view-selector, #action-buttons, #overflow').forEach(element => element.parentNode.removeChild(element));
  142.         stickyItems = sticky.querySelector('#primary-content');
  143.     };
  144.  
  145.     let monitorDarkTheme = () => {
  146.         let observer = new MutationObserver(() => {
  147.             sticky.classList.toggle('dark');
  148.         });
  149.         observer.observe(document.querySelector('html'), {
  150.             attributes: true,
  151.             attributeFilter: ['dark']
  152.         });
  153.     };
  154.  
  155.     let monitorTimestampToggle = () => {
  156.         let observer = new MutationObserver(() => {
  157.             sticky.classList.toggle('hide-timestamps');
  158.             scrollSticky();
  159.         });
  160.         observer.observe(document.querySelector('yt-live-chat-renderer'), {
  161.             attributes: true,
  162.             attributeFilter: ['hide-timestamps']
  163.         });
  164.     };
  165.  
  166.     let setUpEvents = () => {
  167.         stickyItems.addEventListener('scroll', () => {
  168.             setTimeout(() => {
  169.                 canScroll = stickyItems.scrollHeight - stickyItems.scrollTop === stickyItems.clientHeight;
  170.                 scrollButton.style.transform = `translateY(${canScroll ? 42 : 0}px)`;
  171.                 scrollButton.style.visibility = canScroll ? 'hidden' : 'visible';
  172.             });
  173.         });
  174.         scrollButton.addEventListener('click', () => {
  175.             canScroll = true;
  176.             stickyItems.scrollTop = stickyItems.scrollHeight;
  177.         });
  178.         toggleSticky.addEventListener('click', () => {
  179.             if (stickyItemsContainer.offsetHeight > 0) {
  180.                 chat.setAttribute('style', `max-height: ${chat.offsetHeight + 150}px;`);
  181.                 toggleStickyText.innerText = 'Show Sticky';
  182.                 stickyItemsContainer.setAttribute('style', 'border: none;');
  183.                 stickyItemsContainer.style.height = '0px';
  184.             } else {
  185.                 chat.setAttribute('style', `max-height: ${chat.offsetHeight - 150}px;`);
  186.                 itemScroller.scrollTop += 150;
  187.                 toggleStickyText.innerText = 'Hide Sticky';
  188.                 stickyItemsContainer.setAttribute('style', '');
  189.                 stickyItemsContainer.style.height = '150px';
  190.             }
  191.         });
  192.     };
  193.  
  194.     let initMonitoring = () => {
  195.         setUpCss();
  196.         setUpSticky();
  197.         monitor();
  198.         monitorDarkTheme();
  199.         monitorTimestampToggle();
  200.         setUpEvents();
  201.     };
  202.  
  203.     let init = () => {
  204.         if (window.top.document.readyState === 'complete') {
  205.             initMonitoring();
  206.         } else {
  207.             window.top.addEventListener('load', initMonitoring);
  208.         }
  209.     };
  210.  
  211.     init();
  212.  
  213. })();
  214.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement