Old Youtube Buttons

Changes various YouTube elements to resemble the old YouTube Design. (Green/Red Like/Dislike, Yellow Subscribe Button.)

  1. // ==UserScript==
  2. // @name Old Youtube Buttons
  3. // @namespace YellowSubButt
  4. // @version 0.3.26
  5. // @description Changes various YouTube elements to resemble the old YouTube Design. (Green/Red Like/Dislike, Yellow Subscribe Button.)
  6. // @author SomeSchmuck
  7. // @match *://*.youtube.com/*
  8. // @icon https://th.bing.com/th/id/R.a12178dd72afd2470f0d2285602f2374?rik=%2fZTUzR2M%2fWKHUA&riu=http%3a%2f%2fsguru.org%2fwp-content%2fuploads%2f2018%2f02%2fYouTube_logo.png&ehk=kk7ZapiqeyJwuqO64Byiid8PbemJtRLsbmphetcvtcE%3d&risl=&pid=ImgRaw&r=0
  9. // @grant GM_addStyle
  10. // @run-at document-end
  11. // @connect youtube.com
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. // grant GM.xmlHttpRequest TODO: is this needed?
  16.  
  17. // TODOs:
  18. // make the above section a little cleaner and see if certain parts are actually needed or not
  19. // maybe make this not use esversion 6? technically better browser support that way, although
  20. // that might not even be an issue... Too bad!
  21. /* jshint esversion: 6 */
  22.  
  23. //known issues:
  24. //sub button sometimes has a thin white/really bright line at the very bottom;
  25. // this might be a browser issue, though adjusting css padding can hide it a little bit
  26.  
  27. // 0.3.26 changes:
  28. // Major script refactor, allows for much easier JS and CSS development + better compatibility through YT updates?
  29. // Fix "Subscribe" button styling when signed out
  30. // Fix "Join" button styling not applying on channel page
  31. // Hide highlighted background on "Reply" and "More/Less Replies" buttons that would appear on hover
  32.  
  33. // 0.3.25 change:
  34. // Refactor code to be visually cleaner
  35. // Use template literals as multi-line strings when possible
  36. // Fix "Subscribe(d)" button styling not being correctly applied on channels (YouTube try not to change their CSS classes for no reason challenge failed instantly)
  37.  
  38. // 0.3.24 change:
  39. // fix video like/dislike buttons not being coloured.
  40. // fix comment "Reply" button text not being styled as shown on greasyfork.org page
  41. // fixed "Subscribe" button styling not always being correctly applied (such as on channels and not hiding icons when subscribed)
  42.  
  43. // 0.3.23 change:
  44. // fix video like/dislike buttons not being coloured.
  45.  
  46. // Supported values: 2008, 2012.
  47. // TODO: Add support for design changes YouTube made during supported years, instead
  48. // of a general hodgepodge of all the different designs ssen in one year.
  49. "use strict";
  50. var ytEra = 2008;
  51. var lastTime = Date.now();
  52. var delta = 0;
  53. const subButtClass = '.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--filled';
  54. const chaJoinButtClass = '.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--outline'
  55. locationChange();
  56.  
  57. function set_join_buttons(){
  58. let joinButtons = [document.querySelector(`yt-flexible-actions-view-model ${chaJoinButtClass}`)];
  59. for (let joinButt of joinButtons) {
  60. // Get "Join" button, and check if it actually exists + hasn't had class applied + has aria-label
  61. if (joinButt == null) {
  62. continue;
  63. }
  64. if (joinButt.classList.contains('oyt-join-button')) {
  65. continue;
  66. }
  67. if (!joinButt.hasAttribute('aria-label')) {
  68. continue;
  69. }
  70. // Only execute on buttons with aria-label that starts with "join"
  71. if (joinButt.ariaLabel.toLowerCase().startsWith('join')) {
  72. joinButt.classList.add('oyt-join-button')
  73. }
  74. }
  75. }
  76.  
  77. //TODO: Fix comments text formatting
  78. function set_buttons_text(){
  79. let reply_info = document.getElementsByTagName('yt-formatted-string');
  80. //console.log(reply_info.length);
  81. if (reply_info.length != 0){
  82. for(let r = 0; r < reply_info.length; r++){
  83. let reply_str = reply_info[r].innerText.toLowerCase();
  84. const reply_style = 'border-bottom: 1px dotted #0140FF; color: #0140FF; text-transform: capitalize; font-weight: normal;';
  85. const join_text_style = 'color: #039';
  86. if (reply_str != null){
  87. if (reply_str === 'reply'){
  88. reply_info[r].setAttribute('style', reply_style);
  89. } else if (reply_str === 'join' || reply_str === 'customize channel' || reply_str === 'manage videos'){
  90. reply_info[r].setAttribute('style', join_text_style);
  91. } else {
  92. //if we don't pass above checks, remove styling. Youtube shouldn't have anything
  93. // important formatted like this anyway, so we're... fine i think
  94. reply_info[r].removeAttribute('style');
  95. }
  96. }
  97. }
  98. }
  99. }
  100.  
  101. function set_uns_sub() {
  102. let subButton = document.querySelector(`yt-flexible-actions-view-model ${subButtClass}`);
  103. // Don't do anything if button doesn't exist, already has class applied and has no aria-label
  104. if (subButton == null) {
  105. return;
  106. }
  107. if (subButton.classList.contains('oyt-action-button')) {
  108. return;
  109. }
  110. if (!subButton.hasAttribute('aria-label')) {
  111. return;
  112. }
  113. // Only execute on button with aria-label === 'subscribe"
  114. if (subButton.ariaLabel.toLowerCase() === "subscribe") {
  115. subButton.classList.add('oyt-action-button');
  116. // console.log('Successfully added class to signed-out subscribe button!');
  117. }
  118. }
  119.  
  120. function set_video_inf(){
  121. // set_buttons_text();
  122. set_uns_sub();
  123. set_join_buttons();
  124. }
  125.  
  126. function createStyle() {
  127. const unsubButtClass = '.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--tonal';
  128. const subChaLoc = `yt-subscribe-button-view-model ${subButtClass}`;
  129. const unsubChaLoc = `yt-subscribe-button-view-model ${unsubButtClass}`;
  130. const subVidLoc = `#subscribe-button ${subButtClass}`;
  131. const unsubVidLoc = `#subscribe-button ${unsubButtClass}`;
  132. let style =
  133. `/*= Subscribe-Unsubscribe button (Channel, Video & Subbed, Unsubbed) =*/
  134. /* Common button formatting */
  135. ${subChaLoc},
  136. ${unsubChaLoc},
  137. ${subVidLoc},
  138. ${unsubVidLoc},
  139. .oyt-action-button {
  140. border-radius: 4px;
  141. text-transform: capitalize;
  142. font-weight: bold;
  143. padding: 2px 9px 0 10px;
  144. height: 27px;
  145. font-family: Arial, sans-serif;
  146. font-size: 12px;
  147. }
  148. ${subChaLoc}:hover,
  149. ${unsubChaLoc}:hover,
  150. ${subVidLoc}:hover,
  151. ${unsubVidLoc}:hover,
  152. .oyt-action-button:hover {
  153. text-decoration: underline;
  154. }
  155.  
  156. /* State specific (colours, subbed/unsubbed, etc.) */
  157. ${subChaLoc},
  158. ${subVidLoc},
  159. ${subButtClass}.oyt-action-button {
  160. background: linear-gradient(180deg, #fff9c1 0%, #fed81c 100%);
  161. border: 1px solid #ecc101;
  162. color: #994800;
  163. }
  164. ${subChaLoc}:hover,
  165. ${subVidLoc}:hover,
  166. ${subButtClass}.oyt-action-button:hover {
  167. background: linear-gradient(180deg, #fffffa 0%, #fed925 100%);
  168. }
  169. ${unsubChaLoc},
  170. ${unsubVidLoc} {
  171. background: linear-gradient(180deg, #fefefe 0%, #c2c2c2 100%);
  172. color: #333;
  173. border: 1px solid #ccc;
  174. max-width: 88.6667px;
  175. }
  176. ${unsubChaLoc}:hover,
  177. ${unsubVidLoc}:hover {
  178. /*
  179. 2008 YouTube actually used the same BG on hover as the "subscribe" button,
  180. but I think this looks better so I'll break accuracy slightly for it
  181. */
  182. background: linear-gradient(180deg, #fefefe 0%, #a8a6a6 100%);
  183. }
  184.  
  185. /* Hide Subscribed button icons (notif bell, dropdown arrow) */
  186. ${unsubChaLoc} > .yt-spec-button-shape-next__icon,
  187. ${unsubChaLoc} > .yt-spec-button-shape-next__secondary-icon,
  188. ${unsubVidLoc} > .yt-spec-button-shape-next__icon,
  189. ${unsubVidLoc} > .yt-spec-button-shape-next__secondary-icon{display: none;}
  190.  
  191. /*= Channel membership Join button =*/
  192. ${chaJoinButtClass}.oyt-join-button,
  193. #purchase-button .yt-spec-button-shape-next--call-to-action,
  194. #sponsor-button ${subButtClass} {
  195. background-image: linear-gradient(180deg, #fbfcff 0%, #93b2ff 100%);
  196. color: #1c1b16;
  197. font-size: 14px;
  198. text-transform: capitalize;
  199. font-weight: bold;
  200. font-family: Arial, sans-serif;
  201. height: 27px;
  202. border: 1px solid #8aa1d5;
  203. border-radius: 4px;
  204. }
  205.  
  206. /*= Like-Dislike button colours =*/
  207. /* Videos (+Comments for dislike) */
  208. like-button-view-model .yt-spec-button-shape-next__icon path {fill: green;}
  209. dislike-button-view-model .yt-spec-button-shape-next__icon,
  210. #dislike-button .yt-spec-button-shape-next__icon {color: red;}
  211.  
  212. /* Comments */
  213. #like-button .yt-spec-button-shape-next__icon {color: green;}
  214.  
  215. /*= "Reply" button + replies dropdown =*/
  216. `;
  217. let repCol = '#0140FF'; // default 2008 colour
  218. let repLapseCol = repCol;
  219. let repUnd =
  220. ` border-bottom: 1px dotted ${repCol};
  221. font-weight: normal;`; // Ends with semi-colon, mind before use
  222. if (ytEra == 2012) {
  223. repCol = '#999';
  224. repLapseCol = '#438bc5';
  225. repUnd =
  226. ` font-weight: bold;
  227. font-size: 11px;
  228. font-family: Arial, sans-serif;`;
  229. style +=
  230. `#reply-button-end button:hover span {
  231. color: ${repLapseCol};
  232. text-decoration: underline;
  233. }
  234. #more-replies span,
  235. #less-replies span {
  236. ${repUnd}
  237. font-size: 12px;
  238. }
  239. #more-replies:hover span,
  240. #less-replies:hover span {
  241. text-decoration: underline;
  242. }
  243. `;
  244. }
  245. style +=
  246. `#reply-button-end span {
  247. ${repUnd}
  248. color: ${repCol};
  249. }
  250. #more-replies .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text,
  251. #less-replies .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text,
  252. #more-replies-icon .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text,
  253. #less-replies-icon .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text {
  254. color: ${repCol};
  255. }
  256.  
  257. /* Hide background highlight when hovering */
  258. #reply-button-end yt-button-shape:hover,
  259. #reply-button-end .yt-spec-button-shape-next--mono.yt-spec-button-shape-next--text:hover,
  260. #more-replies .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text:hover,
  261. #less-replies .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text:hover,
  262. #more-replies-icon .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text:hover,
  263. #less-replies-icon .yt-spec-button-shape-next--call-to-action.yt-spec-button-shape-next--text:hover {
  264. background-color: transparent;
  265. }
  266.  
  267. /* Hide background highlight when clicking */
  268. #reply-button-end yt-touch-feedback-shape,
  269. #more-replies yt-touch-feedback-shape,
  270. #less-replies yt-touch-feedback-shape,
  271. #more-replies-icon yt-touch-feedback-shape,
  272. #less-replies-icon yt-touch-feedback-shape {
  273. display: none;
  274. }
  275. `;
  276. return style;
  277. }
  278. //trick to make buttons that don't originally have hover css have hover css part 2 :)
  279. //addGlobalStyle('ytd-button-renderer #button.ytd-button-renderer[join]:hover { border-color: green !important;}')
  280. GM_addStyle(createStyle());
  281. //this bit of script was taken and modified from the script "Youtube: Download Video" by HayaoGai
  282. //link to that script: https://greasyfork.org/en/scripts/404304-youtube-download-video
  283. function locationChange() {
  284. //console.log('Switched page!');
  285. const observer = new MutationObserver(mutations => {
  286. // limit update rate
  287. let tempTime = Date.now();
  288. delta += tempTime - lastTime;
  289. lastTime = tempTime;
  290. if (delta >= 500) {
  291. set_video_inf();
  292. delta = 0; // reset delta time
  293. }
  294. });
  295. const target = document.body;
  296. const config = { childList: true, subtree: true };
  297. observer.observe(target, config);
  298. }