SHARE
TWEET

FuckJewTubeSlowPokeEdition

dncrZMiUWH Sep 17th, 2019 168 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @description Lets you watch YouTube videos without all the bullshit - Max 360p version
  3. // @name FuckJewTubeSlowPokeEdition
  4. // @namespace https://vdn.neocities.org/MISC/USERSCRIPTS.html
  5. // @supportURL https://8ch.net/jewtube/res/54.html
  6. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAC+lBMVEUAAAA8IScrJSjZpbdRMjk/Jy10SlaJVGmNZXLHsZVMMThXPEIzHyMeExYOCwxeOEErIyVaNT43JSoqJCZ3TliHV2NMO0AgIyMCAgImERYFAwRCJy0NCgsaExUAAAAMCAktHyJHKzJhQkkfHB0cFBZZQEY9IypdQkkbFRcyKSs8LTG2b3tLLTSqj34qGBxZPkFCKzGVX2wfEhUPDQ02ICW+nY0qFxxXNDzEpZVVMju8n5RcOkEaFxi6mY+6l46RXmpBNTd3TFeDVF+zg4NsP0srHyN+UFweGxxHOj68jI7Lfo88LDCaa3bHiZoiFBfHsZgXEBIaExXGsJiGY199TlnEqpQXDhGUXGp3S1UuHCFjPEXCmY+mgHpDKjAVDQ84JitlP0jNrJs7IymBWVyujYNyR1HJq5g6JCpySFJmPkg5LTBJMjiqg4HBtJIAAAAZDRAnFRkmFBkbDhHBs5EkFBjBtZIjEhYeEBMgERUMBggNCAkXDA8dDxIVCw0GAwPHuZbDt5TDtpM5ICUJBQbFuZXBq5A2HSMtGR4qFhsRCAvBr5G+qo6ufXpEJS0xGyC/r4+5pImIW15yRk1kRkVWNTlGKzDIupfEo4+FUllrQkhBJCs8JinKu5nDs5PNpJPGoI++pIy7o4q5m4e1nIW0j4Gsj36iam93VVNlPENaMTpSLjZPLTTItJXOm5LCsJHFqJDAqI6/nYu8mIi8kIa4lYWxin+rk36wgXydfXGNX2F9YVqAWll+Vld6TVJ1TlBwTE1yPkpgQEFKMTNKJjDErpLHq5LKn5HOk5HTeYzBloq4j4S/gYOpinqjinikd3Sib3Ged3CUe2yWbWmaZWmRYmOJamKEYl1wVU9eOD7Mt5jKrJXRnpTeepLZeo/PiI7Li428p4vFjYq3oYi5iYOwmYK0hn+qgHircXSyYXSfgHOVdGqKcWSATVZ/Q1J3Qk5sSktnN0PWmJXGmI3GfIe0n4a5dX6udHimgneeV2iBZFyKS1pZQT9VQD1OOzdfs2hPAAAAbXRSTlMA/h4F8kQoEQr+fyD+9/eynI5wVEU+NDIRBfbx7ezjw7idl4tkUEhBPTkM/fTz7urg3d3Z2NfW0smqoJ6eiHx6dW9tampgUUtHQy4pJxb+8u3m3t7e1dLMzMzLycTEw8C3sK+km5uTkol+Zl9V1RHIkgAABkNJREFUWMPNl3VwGkEYxSFN26Tu7u7u7u7u7u3dwTncHU6AuLu71N1jdXd3d3eZ6V4IaeQI9L++AY6Zu/fb9327yw6i/1Xjqw+pXLFi78qrh1QbV+Kf3eMGLuqY6qFxARKLPRznrKru9C/2ahUdPTSeRokEB5JIJRKjJrTn4NL22qtXDNAYJBIpL94NLoBkFPesbp9/sKPGCGy8gBPI8t3Qbpgd9hKVAwxSftACCcxvY2gTm92s3TjUKJWah84FAIELKZWCdmhsEsrw8S3KA5CkBKdpkiZJTeXi/SPqGiUCoikS50kkjYuL7UMpR4PFY+kgToILKAAnKZZFUVZSt1QxgL6eOLDxL5yfOb5qlKJoCQXC0yiCIOAt6V1MgLoSqSU0ALA0iUtYBKGkNI2C0REU5T/Eza0CGhtBAPOLpGiaYmhSSrMcg/A+xCJ6vpO1AO34vpOgVwhLgrgUx5IUqMATRQqoXEtrU2jgVz4OGqfJzNwrYSmUQykWpTJcGIsX5VnkSmF/6U4SMB6oHCffrnd1TXVBEDGL0AiVHFwwAtWtjSCguSeF0DQfnb6iI9T73+BUiguKcIjnyQAEZLA0EdRQw0oFLP8IP+ZlHaZ7ccmF9fdl8QCWdD8HGpoPgLcQBCzBc+tkye86SHU60R8JSCTDnlxDD24T+wZwqFkcaEIZIb9TNz4+w9eYkqSDiDj3t1LfYKnflQs+B45f2bPDE2FyApoQhG0sBCjbgR/dxKCI8WISgRHeJ66mbYnfH60MV+pV0Tuu72MYPgQjB4/NFtqTLQ08gAMA6eN9bhARs/XCC6Vq65aY5/v9/K6eXh+rCTYwIIGc4ZgeQtNQEjcDOI7zT/dWQ3q920bIdXPsgX0h4uxk/6TDZ7alUhxjUsgUsg5lBQEokEmGupBfD23xgiCIgDCIiE5ITvNM3RN3QB9xODkt25Bt0MBweUEAzYGAJJe5Ifnyzh2bIbMwwtXXI+1dArQZg5z9EI8vISF7YLhCSSEAIkMZLjQk/UyoR7YPBlkI6h1vMvY82eUGQev3cR4h/hfdtbCiigCgRVh51CTPdL/mkhaieeWVB4C8tsTvPuVGYJDypUeKXOsDAHAlAUDrQY1QrSwrcr/fwdCUYD30l0CodCrgh1S7UxiZyecSDMMzBHd0FRaW4dt3J53yzTi7GSoqVQIpk8teXYNheXnB3TC2vMJEnQ+P9Tl3Qg9GLCL1TqlcLktlYLhfmUGCZ8rCHl0YPyXmhYHEGKTHCgMeGUECUICimchBJKSWraugGm+CrxsivGMLJyAeeMrNgFYiaypbnzuvw3Ke3u5WBHBPY05Qz0FkVZU4UAPEy21rkTa4hZkBDWpZBzg0cfQmzEtQ71o4QbTYNgBMZm4N4KNgBAyKsp2A11LXPAtRABLxEM8ByCYXDyjVXpfrInY9jSb+Am6kK/hZUNQfVVtUrPrGKXMHfhBjCQCuzrsQGADqDa8qsqGqATsDcwiYmvhbwqHjYWANa7VNRTZVdtKEl+tVGJa/f5g+kt9EWgVYhbbVCFb8ilPm3w6u+qDIJNigUMAyewBrwI7HL2/UWfJjGzcFBUX6VGpeXwvLR9oBcGjUpUIdpmN7tdrsP/zYPSroyJlqooZaRZ2xInvkUKNVC4caU+Nc1eqITScSnx4PCjpydpRogVYL9oH9mtU20X2X+8XEh0eioqIizw7nE3R1sttes6nj+6MnP5+8e/Pmhg0f7t8PrlOpK6xoaLe/VQWYDPY54Hsw/aCvf1Y5nJLDvPrZDRgJC0nR1G5AVa0goKp97jZrl3cSTCBvbd8fjpnPMhBBADjUbKv2wLa3fsDCcplW06a/dJ+jx449MwkD3t3qbIswplf4prt3br8WBry+fazziNrFDd9/ohKCCEx/1F9wEr7d2bTh49z+o639AVvXK1xtPhZUMeUEAPR2NUEcUgY6Tx8wXsA+evFGy48Zhul2soXtJuS35b4ucMrQwnanZc6B+X9ElLtlhQB7s/bmnjoAo7tRmDDgukqt5gewPKK8WtAf5vzztMpyl/De1r1UwbN5Xvyp+E9eqrwQGBGRVaCABOUFb8stIjbeK7B7/laOWRGBecUknHt+j8jLoHqE5JuAvYHYdiyX7rYNnJxYeB/zmvgD6WMceTRG7tcAAAAASUVORK5CYII=
  7. // @include https://www.youtube.com/
  8. // @include https://www.youtube.com/?disable_polymer=1
  9. // @include https://www.youtube.com/?disable_polymer=1&gl=*
  10. // @include https://www.youtube.com/feed/*
  11. // @include https://www.youtube.com/watch*
  12. // @include https://www.youtube.com/results*
  13. // @include https://www.youtube.com/channel/*
  14. // @include https://www.youtube.com/c/*
  15. // @include https://www.youtube.com/view_play_list*
  16. // @include https://www.youtube.com/user/*
  17. // @include https://www.youtube.com/playlist*
  18. // @include https://www.youtube.com/oops
  19. // @include https://r*.googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)
  20. // @version 9002.4.4
  21. // @updateURL https://vdn.neocities.org/MISC/JS/FuckJewTubeSlowPokeEdition.user.js
  22. // @downloadURL https://vdn.neocities.org/MISC/JS/FuckJewTubeSlowPokeEdition.user.js
  23. // @run-at document-start
  24. // @grant GM.getValue
  25. // @grant GM.setValue
  26. // @grant GM_download
  27. // @grant GM.info
  28. // @grant GM_xmlhttpRequest
  29. // @connect ytimg.com
  30. // @connect googlevideo.com
  31. // @connect youtube.com
  32. // @require https://vdn.neocities.org/MISC/JS/hls.js
  33. // @require https://vdn.neocities.org/MISC/JS/FuckJewTubeResources-v1-2.js
  34. // @require https://vdn.neocities.org/MISC/JS/FuckJewTubeRandomVideos-v1-3.js
  35. // ==/UserScript==
  36.  
  37. /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  38. - FuckJewTube -
  39. >tfw some random anon is more trustworthy than "respectable companies" like (((google)))
  40.  
  41. #########################################################################################################
  42. This script requires a special PAC script found at https://vdn.neocities.org/MISC/USERSCRIPTS.html
  43. Without it all region restricted videos and channels will not work
  44. #########################################################################################################
  45.  
  46. Special thanks to the creator of invidio.us for helping with understanding the deciphering and the anons
  47. helping with bugfixing
  48. The require hls.js is for decoding m3u8 livestreams, nothing shady
  49. hls.js orig source: https://cdn.jsdelivr.net/npm/hls.js@latest
  50. hls.js github: https://github.com/video-dev/hls.js/
  51. The require FuckJewTubeResources.js has Base64 encoded images/SFX
  52. The require FuckJewTubeRandomVideos.js is an array of randomly selected videos
  53. The UI is designed for widescreen, a minimum resolution of 1280x720 and the Courier New font
  54. combined with MS PGothic for unicode glyphs
  55. The userscript kind of works on mobile, but a lot of features are broken ¯\_(ツ)_/¯
  56. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
  57.  
  58. /* START OF USERSCRIPT */
  59. /* INIT START */
  60. /* loadfix start */
  61. var loadfix = document.createElement("div"); // this is used to hide the original page while the script is working
  62. loadfix.setAttribute("style", "position: fixed; left: 0; top: 0; width: 100%; height: 100%; background-color: #111; z-index: 9999999999;");
  63. loadfix.setAttribute("id", "loadfix");
  64. try {document.getElementsByTagName("html")[0].appendChild(loadfix); loadfix = document.getElementById("loadfix"); startUserScript();}
  65. catch(e) {console.log("HTML TAG NOT FOUND - RELOADING"); window.location.reload(); return;}
  66. /* loadfix end */
  67. function startUserScript() {
  68.     // bloat remove start
  69.     if (window.location.href.includes("youtube.com/watch") === true || window.location.href === "https://www.youtube.com/" || window.location.href === "https://www.youtube.com/?disable_polymer=1") { // watch page + front page (no googlevideo because it breaks gif animations)
  70.         window.stop(); // stop loading youtube bloat
  71.     }
  72.     /* bloat remove end */
  73.     /* region setting start */
  74.     var regionsetting = "";
  75.     GM.getValue("region").then(function(regionValue) {
  76.         if (regionValue === undefined) {GM.setValue("region", "gl=US");}
  77.         regionsetting = regionValue;
  78.         /* redirect start */
  79.         if (window.location.href.includes("youtube.com/c/") === true) { // for obscure /c/ links
  80.             if (window.location.href.includes("disable_polymer=1") === false) {
  81.                 if (window.location.href.includes("?") === false) {window.location.href = window.location.href + "?disable_polymer=1&" + regionsetting; return;}
  82.                 else {window.location.href = window.location.href + "&disable_polymer=1&" + regionsetting; return;}
  83.             }
  84.             try {loadfix = document.getElementsByClassName("branded-page-header-title-link")[0].href.match(/channel\/[^/]+/)[0].substring(8);}
  85.             catch(e) {loadfix = document.getElementsByTagName("html")[0].innerHTML.match(/CHANNEL_ID', "[^"]+/)[0].substring(14);}
  86.             window.location.href = "https://www.youtube.com/channel/" + loadfix + "/featured?disable_polymer=1&" + regionsetting; return;
  87.         }
  88.         if (window.location.href.includes("youtube.com/view_play_list") === true) { // for alt playlist URLs
  89.             window.location.href = "https://www.youtube.com/playlist?list=" + window.location.href.slice(41) + "&disable_polymer=1&" + regionsetting;
  90.         }
  91.         if (window.location.href.includes("youtube.com/results") === true || window.location.href.includes("youtube.com/channel/") === true || window.location.href.includes("youtube.com/user/") === true || window.location.href.includes("youtube.com/playlist") === true || window.location.href.includes("youtube.com/feed/") === true) { // non watch pages redirect
  92.             if (window.location.href.includes("disable_polymer=1") === false) {
  93.                 window.stop();
  94.                 if (window.location.href.includes("youtube.com/results") === true || window.location.href.includes("youtube.com/playlist") === true) {
  95.                     window.location.href = window.location.href + "&disable_polymer=1&" + regionsetting; return;
  96.                 }
  97.                 if (window.location.href.includes("sub_confirmation=1") === true) {
  98.                     window.location.href = window.location.href.match(/https:\/\/www\.\S+\?/)[0].slice(0, -1) + "/featured?disable_polymer=1&" + regionsetting; return;
  99.                 }
  100.                 if (window.location.href.includes("/feed/") === true) {window.location.href = window.location.href + "?disable_polymer=1&" + regionsetting; return;}
  101.                 if (window.location.href.match(/channel\/.{24}\/[\w]/) === null || window.location.href.match(/user\/.+\/[\w]/) === null) {
  102.                     if (window.location.href.includes("/videos") === true || window.location.href.includes("/featured") === true || window.location.href.includes("/channels") === true || window.location.href.includes("/community") === true || window.location.href.includes("/discussion") === true || window.location.href.includes("/about") === true) {
  103.                         if (window.location.href.includes("?") === true) {window.location.href = window.location.href + "&disable_polymer=1&" + regionsetting; return;}
  104.                         else {window.location.href = window.location.href + "?disable_polymer=1&" + regionsetting; return;}
  105.                     }
  106.                     else {window.location.href = window.location.href + "/featured?disable_polymer=1&" + regionsetting; return;}
  107.                 }
  108.             }
  109.         }
  110.         /* redirect end */
  111.     });
  112.     /* region setting end */
  113.     /* oops page start */
  114.     if (window.location.href === "https://www.youtube.com/oops") {document.getElementsByTagName("html")[0].innerHTML = ""; lainInit(); lainFail(); document.title = "Oopsie daisy!"; alert("ERROR: You did something wrong and ended up on the oops page.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page."); return;}
  115.     /* oops page end */
  116.     /* info start */
  117.     if (navigator.languages.includes("he") === true || navigator.languages.includes("he-IL") === true || navigator.languages.includes("yi") === true) {alert("Oy vey!"); window.location.href = "https://a.doko.moe/mundrx.webm"; return;} // :^)
  118.     if (GM.info.scriptHandler !== "Tampermonkey") {alert("This userscript is designed for Tampermonkey and will not work natively in Greasemonkey or Violentmonkey. Both can be made compatible by editing all the GM commands to their respective equivalents. Greasemonkey however, does not support GM_download and Violentmonkey's GM_download doesn't work with eventlisteners."); return;}
  119.     /* version check start */
  120.     GM.getValue("scriptVersion").then(function(scriptVersionValue) {
  121.         if (scriptVersionValue === undefined || scriptVersionValue !== GM.info.script.version) {
  122.             GM.setValue("scriptVersion", GM.info.script.version);
  123.             alert(GM.info.script.name + ": - " + GM.info.script.version + " -\n- Updated deciphering to new cipher.\n");
  124.         }
  125.     });
  126.     /* version check end */
  127.     /* info end */
  128.     /* global vars start */
  129.     var btn_area = "";
  130.     var btn_theatreMode = "";
  131.     var btn_randomVid = "";
  132.     var btn_randomMode = "";
  133.     var btn_channelGo = "";
  134.     var btn_searchGo = "";
  135.     var btn_favoritesplaylist = "";
  136.     var VID_THEATRE_MODE = false;
  137.     var VID_RANDOM_MODE = false;
  138.     var VID_PLAYLIST_MODE = false;
  139.     var VID_HAS_CC = false;
  140.     var VID_ERROR = false;
  141.     var muxstream = "";
  142.     var vid = "";
  143.     var vidtime = 0;
  144.     var lainchan = "";
  145.     var lainSFX = "";
  146.     var lainSFXdone = false;
  147.     var ytid = window.location.href.slice(32, 43);
  148.     var ytplid = "";
  149.     var playlistid = "";
  150.     var ytcheck = false;
  151.     var muxcheck = false;
  152.     var geocheck = false;
  153.     var ytTitle = "";
  154.     var ytPlaylistTitle = "";
  155.     var ytTitleDone = false;
  156.     var ytajax = "";
  157.     var sig = "";
  158.     var playerBaseURL = "";
  159.     var filetype = "";
  160.     var regex = "";
  161.     var decipherFunction = "";
  162.     var decipherVarName = "";
  163.     var decipherOperations = "";
  164.     var decipher = "";
  165.     var decipherExtractDone = false;
  166.     var a = "";
  167.     var offensivevidURL = "";
  168.     var livestreamURL = "";
  169.     var hls = "";
  170.     var GETattempts = 0;
  171.     var GETmixpopattempts = 0;
  172.     var GETplaylistattempts = 0;
  173.     var GETdescriptionattempts = 0;
  174.     var ccVTT = "";
  175.     var ccDone = false;
  176.     var ccURL = "";
  177.     var ccName = "";
  178.     var ccajax = "";
  179.     var ccStart = "";
  180.     var ccDur = "";
  181.     var ccText = "";
  182.     var ccVTTstart = "";
  183.     var ccVTTend = "";
  184.     var ccBlob = "";
  185.     var ccTrack = "";
  186.     var ccInterval = "";
  187.     var ccSRT = "";
  188.     var ccSRTinfo = "";
  189.     var ccSRTurls = [];
  190.     var i = "";
  191.     var u = "";
  192.     var channelid = "";
  193.     var channelauthor = "";
  194.     var randomytid = "";
  195.     var searchquery = "";
  196.     var playlistVideoIDs = "";
  197.     var playlistVideoTitles = "";
  198.     var playlistLoadMoreURL = "";
  199.     var moreplaylistVideoIDs = "";
  200.     var moreplaylistVideoTitles = "";
  201.     var playlistMenuEntries = "";
  202.     var playlistMenu = "";
  203.     var descriptionMenu = "";
  204.     var favoritesplaylistMenuBox = "";
  205.     var favoritesplaylistMenuShow = false;
  206.     var currentVideo = "";
  207.     var fp_btn_favorites = "";
  208.     var fp_btn_playlist = "";
  209.     var fp_btn_exit = "";
  210.     var mix_btn = "";
  211.     var fp_btn_description = "";
  212.     var pl_btn_shuffle = "";
  213.     var pl_btn_reverse = "";
  214.     var pl_btn_nextVid = "";
  215.     var pl_btn_prevVid = "";
  216.     var prevVideo = false;
  217.     var playlistpaid = "";
  218.     var playlistpos = 0;
  219.     var PLAYLIST_LOADING = false;
  220.     var PLAYLIST_SHUFFLE_MODE = false;
  221.     var PLAYLIST_REVERSE_MODE = false;
  222.     var PLAYLIST_IS_MIXPOP = false;
  223.     var PLAYLIST_MIXPOP_ALT = false;
  224.     var shuffleArray = [];
  225.     var playlistCurrent = "";
  226.     var favoritesVideoMenu = "";
  227.     var favoritesChannelMenu = "";
  228.     var favoritesPlaylistMenu = "";
  229.     var fav_btn_addVideo = "";
  230.     var fav_btn_addChannel = "";
  231.     var fav_btn_addPlaylist = "";
  232.     var fav_btn_removeMode = "";
  233.     var fav_btn_videos = "";
  234.     var fav_btn_channels = "";
  235.     var fav_btn_playlists = "";
  236.     var favoritesVideoIDsArray = [];
  237.     var favoritesVideoTitlesArray = [];
  238.     var favoritesChannelIDsArray = [];
  239.     var favoritesChannelAuthorsArray = [];
  240.     var favoritesPlaylistIDsArray = [];
  241.     var favoritesPlaylistTitlesArray = [];
  242.     var FAVORITES_REMOVE_MODE = false;
  243.     var favoritesMenuEntries = "";
  244.     var videoThumbnails = "";
  245.     var loadmoreURL = "";
  246.     var loadmoreContent = "";
  247.     var loadmoreVideosDone = false;
  248.     var descriptionDone = false;
  249.     var divMenu = "";
  250.     var divMenuDescPos = 0;
  251.     var divMenuFavChanPos = 0;
  252.     var divMenuFavVidPos = 0;
  253.     var divMenuFavPlaylistPos = 0;
  254.     var divMenuPlaylistPos = 0;
  255.     var customPlaylistArray = [];
  256.     var customPlaylist_btn_add = "";
  257.     var customPlaylist_btn_del = "";
  258.     var customPlaylist_btn_play = "";
  259.     var CUSTOM_PLAYLIST_EDIT_MODE = "OFF";
  260.     var regionCodes = ["gl=DZ", "gl=AR", "gl=AU", "gl=AT", "gl=AZ", "gl=BH", "gl=BY", "gl=BE", "gl=BA", "gl=BR", "gl=BG", "gl=CA", "gl=CL", "gl=CO", "gl=HR", "gl=CZ", "gl=DK", "gl=EG", "gl=EE", "gl=FI", "gl=FR", "gl=GE", "gl=DE", "gl=GH", "gl=GR", "gl=HK", "gl=HU", "gl=IS", "gl=IN", "gl=ID", "gl=IQ", "gl=IE", "gl=IL", "gl=IT", "gl=JM", "gl=JP", "gl=JO", "gl=KZ", "gl=KE", "gl=KW", "gl=LV", "gl=LB", "gl=LY", "gl=LT", "gl=LU", "gl=MK", "gl=MY", "gl=MT", "gl=MX", "gl=ME", "gl=MA", "gl=NP", "gl=NL", "gl=NZ", "gl=NG", "gl=NO", "gl=OM", "gl=PK", "gl=PE", "gl=PH", "gl=PL", "gl=PT", "gl=PR", "gl=QA", "gl=RO", "gl=RU", "gl=SA", "gl=SN", "gl=RS", "gl=SG", "gl=SK", "gl=SI", "gl=ZA", "gl=KR", "gl=ES", "gl=LK", "gl=SE", "gl=CH", "gl=TW", "gl=TZ", "gl=TH", "gl=TN", "gl=TR", "gl=UG", "gl=UA", "gl=AE", "gl=GB", "gl=US", "gl=VN", "gl=YE", "gl=ZW"];
  261.     var regionNames = ["Algeria", "Argentina", "Australia", "Austria", "Azerbaijan", "Bahrain", "Belarus", "Belgium", "Bosnia and Herzegovina", "Brazil", "Bulgaria", "Canada", "Chile", "Colombia", "Croatia", "Czechia", "Denmark", "Egypt", "Estonia", "Finland", "France", "Georgia", "Germany", "Ghana", "Greece", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iraq", "Ireland", "(((The Unholy Land)))", "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kuwait", "Latvia", "Lebanon", "Libya", "Lithuania", "Luxembourg", "Macedonia", "Malaysia", "Malta", "Mexico", "Montenegro", "Morocco", "Nepal", "Netherlands", "New Zealand", "Niggeria", "Norway", "Oman", "Pakistan", "Peru", "Philippines", "Poland", "Portugal", "Puerto Rico", "Qatar", "Romania", "Russia", "Saudi Arabia", "Senegal", "Serbia", "Singapore", "Slovakia", "Slovenia", "South Africa", "South Korea", "Spain", "Sri Lanka", "Sweden", "Switzerland", "Taiwan", "Tanzania", "Thailand", "Tunisia", "Turkey", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Vietnam", "Yemen", "Occupied Rhodesia"]; // #33 being the (((The Unholy Land))) sure is pure (((coincidence))) eh jewgle?
  262.     var regionInfo = "Input the number of the desired region you wish to change to         \nNOTE: Affects trending pages and auto-generated genre channels (i.e News, Popular on YouTube etc)         \nTo change the language of YouTube and preferred region for search results, then manually change your browser's preferred language setting         "; // spaces added to nowrap
  263.     var regionUnblockArray = ["/user/ToeiAnimationUS/", "/channel/UCQYYekTKCb1y12sas08T6gQ/", "/user/sonymusicnetwork/", "/channel/UCCy_q-N7F2FOIZ6ZggHIAKg/"]; // only the ones that can't be detected
  264.     var descViews = "";
  265.     var descDate = "";
  266.     var descGenre = "";
  267.     /* global vars end */
  268.     /* global functions start */
  269.     /* icon start */
  270.     function lainIcon() {
  271.         u = document.createElement("link");
  272.         u.setAttribute("rel", "shortcut icon");
  273.         u.setAttribute("href", resource_img_lain_icon); // ignore warning - is in FuckJewTubeResources.js
  274.         document.getElementsByTagName("head")[0].insertAdjacentElement("beforeend", u);
  275.     }
  276.     /* icon end */
  277.     function lainInit() {
  278.         setTimeout( function() { // timing fix
  279.             lainIcon();
  280.         }, 777);
  281.         document.getElementsByTagName("html")[0].style = "background-color: rgb(33, 33, 33); color: rgb(33, 33, 33); overflow: hidden; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; user-select: none; -moz-user-select: none; -ms-user-select: none; -khtml-user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;";
  282.         if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true || window.location.href === "https://www.youtube.com/?disable_polymer=1" || window.location.href === "https://www.youtube.com/") {document.getElementsByTagName("html")[0].innerHTML = "<head><style>#div_Menu {line-height: 1.4em;} *|*:root {font-size: 13px; width: 100% !important; height: 100% !important;} #description_Menu {user-select: text; -moz-user-select: text; -ms-user-select: text; -khtml-user-select: text; -webkit-user-select: text; -webkit-touch-callout: default;} #description_Menu a {color: #555;} #description_Menu a:hover {text-shadow: -0.5px -0.5px 0.5px teal, -0.5px -0.5px 0.5px skyblue, 0.5px 0.5px 0.5px teal, 0.5px 0.5px 0.5px skyblue; color: skyblue;} ol {counter-reset: items;} li {display: block; counter-increment: items;} li:before {content: '000' counter(items)': ';} li:nth-child(n+10):before {content: '00' counter(items)': ';} li:nth-child(n+100):before {content: '0' counter(items)': ';} li:nth-child(n+1000):before {content: counter(items)': ';} @keyframes fadein {from {opacity: 0;} to {opacity: 1;}} @keyframes fadeout {from {opacity: 1;} to {opacity: 0;}} .btn {font-family: Courier New, monospace} .btn:hover {color: skyblue !important; text-shadow: -1px -1px 1px teal, -1px -1px 1px skyblue, 1px 1px 1px teal, 1px 1px 1px skyblue !important; cursor: pointer;} ::cue {background-color: transparent; text-shadow: -1px -1px 2px #000, 1px -1px 2px #000, -1px 1px 2px #000, 1px 1px 2px #000;} .playlistEntries:hover, .favoritesEntries:hover {color: skyblue !important; cursor: pointer; text-shadow: -0.5px -0.5px 0.5px teal, -0.5px -0.5px 0.5px skyblue, 0.5px 0.5px 0.5px teal, 0.5px 0.5px 0.5px skyblue !important;} #currentvid {color: skyblue;}</style></head><body></body>";}
  283.         u = "<video id=\"videoplayer\" autoplay=\"\" controls=\"\" loop=\"\" style=\"display: none; z-index: 1; max-height: 100%; min-width: 33%; max-width: 66%; position: fixed; margin: auto; right: 0; bottom: 0; left: 0; top: 0; box-shadow: 0 0 5px rgba(0,0,0,0.6);\"></video><audio id=\"SFX\" loop=\"loop\" style=\"display: none;\"></audio><div id='lain'></div><div id=\"buttons_area\" style=\"display: none; z-index: 9001; position: fixed; left 0; bottom: 3px; width: 50px; height: 75px;\"><div id=\"btn_theatre\" class=\"btn\" style=\"display: none;\" title=\"Toggle theatre mode\">+</div><div id=\"btn_random\" class=\"btn\" style=\"display: none;\" title=\"Get a random video\nALT click for a random YouTube mix\">↯</div><div id=\"btn_random_mode\" class=\"btn\" style=\"display: none;\" title=\"Turn on random video playlist mode\">⥁</div><div id=\"btn_channel\" class=\"btn\" style=\"display: none;\">▣</div><div id=\"btn_search\" class=\"btn\" style=\"display: none;\" title=\"Search for videos\">⌕</div><div id='btn_favplaylist' class=\"btn\" title='Toggle FuckJewTube menu' style='display: none;'>★</div></div><div id='favoritesplaylist_MenuBox' style=\"display: none; position: fixed; left: 0; right: 0; top: 0; bottom: 0; margin: auto; overflow: hidden; max-width: 75%; z-index: 9001; border: 10px double; border-radius: 10px; max-height: 75%;\"><div id='fp_btn_fav' class='btn' style='display: none;'>FAVORITES</div><div id='fp_btn_pl' class='btn' style='display: none;'>PLAYLIST</div><div id='fp_btn_quit' class='btn' style='display: none;'>☒</div><div id='fp_btn_desc' class='btn' title='Show description' style='display: none;'>ⓘ</div><div id='ytmix_btn' class='btn' title='Generate YouTube mix from current video' style='display: none;'>⌘</div><div id='custompl_btn_play' class='btn' title='Show custom playlist menu' style='display: none;'>➤</div><div id='custompl_btn_add' class='btn' title='Turn on custom playlist add mode' style='display: none;'>+</div><div id='custompl_btn_del' class='btn' title='Turn on custom playlist removal mode' style='display: none;'>-</div><div id='fav_btn_addvid' class='btn' title='Add current video' style='display: none;'>★</div><div id='fav_btn_addchan' class='btn' title='Add current channel' style='display: none;'>▣</div><div id='fav_btn_addplaylist' class='btn' title='Add current playlist' style='display: none;'>⇉</div><div id='fav_btn_remove_mode' class='btn' title='Turn on removal mode' style='display: none;'>✖</div><div id='fav_btn_vid' class='btn' style='display: none;'>VIDEOS</div><div id='fav_btn_chan' class='btn' style='display: none;'>CHANNELS</div><div id='fav_btn_playlist' class='btn' style='display: none;'>PLAYLISTS</div><div id='pl_btn_shuf' class='btn' title='Shuffle playlist' style='display: none;'>⇉</div><div id='pl_btn_rev' class='btn' title='Turn on reverse mode' style='display: none;'>↬</div><div id='pl_btn_next' class='btn' title='Play next video' style='display: none;'>↣</div><div id='pl_btn_prev' class='btn' title='Play previous video' style='display: none;'>↢</div><div id='pl_cursong' style='display: none;'></div><div id='div_Menu' style='overflow-y: auto; overflow-x: hidden; height: 87.5%; margin-top: 50px; border: 3px dotted;'><div id='description_Menu' style='display: none; color: #888; margin-left: 5px; margin-right: 30px;'></div><ol id='playlist_Menu' style='display: none; color: #888; margin: 1px 1px 5px -35px;'></ol><ol id='favvid_Menu' style='display: none; color: #888; margin: 1px 1px 5px -35px;'></ol><ol id='favchan_Menu' style='display: none; color: #888; margin: 1px 1px 5px -35px;'></ol><ol id='favplaylist_Menu' style='display: none; color: #888; margin: 1px 1px 5px -35px;'></ol></div></div>";
  284.         document.getElementsByTagName("html")[0].insertAdjacentHTML("afterbegin", u);
  285.         document.getElementsByTagName("html")[0].style.backgroundImage = "url(\"" + resource_img_bg + "\")"; // ignore warning - is in FuckJewTubeResources.js
  286.         lainchan = document.getElementById("lain"); // Lain is Love
  287.         document.getElementsByTagName("body")[0].style = "background-repeat: no-repeat; background-position: bottom left; background-size: contain; margin: auto; height: 100%;";
  288.         document.getElementsByTagName("body")[0].style.backgroundImage = "url(\"" + resource_img_lain_smug + "\")"; // ignore warning - is in FuckJewTubeResources.js
  289.         vid = document.getElementById("videoplayer");
  290.         btn_area = document.getElementById("buttons_area");
  291.         btn_theatreMode = document.getElementById("btn_theatre");
  292.         btn_randomVid = document.getElementById("btn_random");
  293.         btn_randomMode = document.getElementById("btn_random_mode");
  294.         btn_channelGo = document.getElementById("btn_channel");
  295.         btn_searchGo = document.getElementById("btn_search");
  296.         btn_favoritesplaylist = document.getElementById("btn_favplaylist");
  297.         favoritesplaylistMenuBox = document.getElementById("favoritesplaylist_MenuBox");
  298.         playlistMenu = document.getElementById("playlist_Menu");
  299.         favoritesVideoMenu = document.getElementById("favvid_Menu");
  300.         favoritesChannelMenu = document.getElementById("favchan_Menu");
  301.         favoritesPlaylistMenu = document.getElementById("favplaylist_Menu");
  302.         descriptionMenu = document.getElementById("description_Menu");
  303.         fp_btn_favorites = document.getElementById("fp_btn_fav");
  304.         fp_btn_playlist = document.getElementById("fp_btn_pl");
  305.         fp_btn_exit = document.getElementById("fp_btn_quit");
  306.         fp_btn_description = document.getElementById("fp_btn_desc");
  307.         pl_btn_shuffle = document.getElementById("pl_btn_shuf");
  308.         pl_btn_reverse = document.getElementById("pl_btn_rev");
  309.         pl_btn_nextVid = document.getElementById("pl_btn_next");
  310.         pl_btn_prevVid = document.getElementById("pl_btn_prev");
  311.         playlistCurrent = document.getElementById("pl_cursong");
  312.         fav_btn_addVideo = document.getElementById("fav_btn_addvid");
  313.         fav_btn_addChannel = document.getElementById("fav_btn_addchan");
  314.         fav_btn_addPlaylist = document.getElementById("fav_btn_addplaylist");
  315.         fav_btn_removeMode = document.getElementById("fav_btn_remove_mode");
  316.         fav_btn_videos = document.getElementById("fav_btn_vid");
  317.         fav_btn_channels = document.getElementById("fav_btn_chan");
  318.         fav_btn_playlists = document.getElementById("fav_btn_playlist");
  319.         divMenu = document.getElementById("div_Menu");
  320.         customPlaylist_btn_add = document.getElementById("custompl_btn_add");
  321.         customPlaylist_btn_del = document.getElementById("custompl_btn_del");
  322.         customPlaylist_btn_play = document.getElementById("custompl_btn_play");
  323.         mix_btn = document.getElementById("ytmix_btn");
  324.         loadfix.remove();
  325.     }
  326.     function lainFail() {
  327.         document.getElementsByTagName("body")[0].style = "";
  328.         lainchan.style = "position: fixed; right: 0; left: 0; bottom: 0; top: 0; margin: auto; width: 66%; padding-bottom: 50%; background-repeat: no-repeat; background-position: bottom center; background-size: contain;";
  329.         lainchan.style.backgroundImage = "url(\"" + resource_img_lain_error + "\")"; // ignore warning - is in FuckJewTubeResources.js
  330.         lainchan.title = "(。╯︵╰。)";
  331.         lainSFX = document.getElementById("SFX");
  332.         lainSFX.src = resource_sfx_lain_humming; // ignore warning - is in FuckJewTubeResources.js
  333.         lainSFX.volume = 0.337;
  334.         lainSFX.play();
  335.         if (u !== "BAGU") {lainchan.addEventListener("click", function(e){if (e.altKey) {if (e.ctrlKey) {window.open("https://www.youtube.com/?disable_polymer=1", "_blank");} else {window.location.href = "https://www.youtube.com/?disable_polymer=1";}} else {GETrandomvid(e);}});}
  336.         lainchan.style.cursor = "pointer";
  337.         if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {document.title = "Kiking failed :^(";}
  338.         else if (window.location.href.includes("/channel") === true || window.location.href.includes("/user") === true) {document.title = "Invalid YT channel ID ¯\\_(ツ)_/¯"; alert("ERROR: Invalid channel ID.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");}
  339.         else if (window.location.href.includes("/playlist") === true || window.location.href.includes("/user") === true) {document.title = "Invalid YT playlist ID ¯\\_(ツ)_/¯"; alert("ERROR: Invalid playlist ID.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");}
  340.     }
  341.     function lainBugReport() {
  342.         u = "BAGU"; lainFail(); console.log("VID_PLAYLIST_MODE = " + VID_PLAYLIST_MODE + "\nVID_HAS_CC = " + VID_HAS_CC + "\nmuxstream = " + muxstream + "\nytid = " + ytid + "\nytplid = " + ytplid + "\nytcheck = " + ytcheck + "\nmuxcheck = " + muxcheck + "\ngeocheck = " + geocheck + "\nytTitle = " + ytTitle + "\nytPlaylistTitle = " + ytPlaylistTitle + "\nsig = " + sig + "\nplayerBaseURL = " + playerBaseURL + "\nregex = " + regex + "\ndecipherFunction = " + decipherFunction + "\ndecipherVarName = " + decipherVarName + "\ndecipherOperations = " + decipherOperations + "\ndecipher = " + decipher + "\ndecipherExtractDone = " + decipherExtractDone + "\noffensivevidURL = " + offensivevidURL + "\nlivestreamURL = " + livestreamURL + "\nGETattempts = " + GETattempts + "\nGETmixpopattempts = " + GETmixpopattempts + "\nccDone = " + ccDone + "\nccSRTurls = " + ccSRTurls + "\nchannelid = " + channelid + "\nchannelauthor = " + channelauthor + "\nplaylistVideoIDs = " + playlistVideoIDs + "\nplaylistVideoTitles = " + playlistVideoTitles + "\nplaylistLoadMoreURL = " + playlistLoadMoreURL + "\nPLAYLIST_IS_MIXPOP = " + PLAYLIST_IS_MIXPOP + "\nPLAYLIST_MIXPOP_ALT = " + PLAYLIST_MIXPOP_ALT + "\nytajax = " + ytajax); alert("ERROR: Userscript failure detected. Please open your browser's console and check which error is getting spammed and report it.\nKindly copy the debug log dump in the console and paste it in a ghost/pastebin and post it in the FuckJewTube thread on /jewtube/ or send it to jewtube@nuke.africa.\nPROTIP: Click on Lain-chan to get redirected to the FuckJewTube thread on /jewtube/ where you can report it.\nNOTE: Firefox tracking protection breaks the XHRs of the script due to the YouTube URLs getting blocked, so turn it off or whitelist youtube."); lainchan.addEventListener("click", function(){window.location.href = "https://8ch.net/jewtube/res/54.html";});
  343.     }
  344.     function lainLoading() {
  345.         if (lainSFXdone === false) {
  346.             lainSFXdone = true;
  347.             lainSFX = document.getElementById("SFX");
  348.             lainSFX.src = resource_sfx_lain_static; // ignore warning - is in FuckJewTubeResources.js
  349.             lainSFX.volume = 0.1;
  350.             lainSFX.play();
  351.             document.getElementsByTagName("body")[0].style = "";
  352.             lainchan.style = "position: fixed; right: 0; left: 0; bottom: 0; top: 0; margin: auto; width: 50%; padding-bottom: 38.75%; background-repeat: no-repeat; background-position: center; background-size: contain;";
  353.             lainchan.style.backgroundImage = "url(\"" + resource_img_lain_load + "\")"; // ignore warning - is in FuckJewTubeResources.js
  354.             lainchan.title = "Hang in there...";
  355.         }
  356.     }
  357.     function lainPlaylistLoading() {
  358.         currentVideo.id = "";
  359.         currentVideo = playlistMenuEntries[playlistpos];
  360.         currentVideo.id = "currentvid";
  361.         playlistCurrent.innerText = "Loading #" + (playlistpos + 1) + ": " + playlistMenuEntries[playlistpos].innerText;
  362.         if (lainchan.title !== "Loading: " + playlistMenuEntries[playlistpos].innerText) {
  363.             lainchan.hidden = false;
  364.             lainchan.style = "position: fixed; right: 0; left: 0; bottom: -5px; margin: auto; width: 50%; padding-bottom: 40%; background-repeat: no-repeat; background-position: center; background-size: contain;";
  365.             if (window.innerWidth / window.innerHeight <= 1.8) {lainchan.style.paddingBottom = "50%";} // fullscreen fix
  366.             lainchan.style.backgroundImage = "url(\"" + resource_img_lain_playlist + "\")"; // ignore warning - is in FuckJewTubeResources.js
  367.             lainchan.title = "Loading: " + playlistMenuEntries[playlistpos].innerText;
  368.             lainchan.replaceWith(lainchan.cloneNode(true));
  369.             lainchan = document.getElementById("lain");
  370.         }
  371.     }
  372.     function lainPlaylistPlaying() {
  373.         lainchan.replaceWith(lainchan.cloneNode(true)); // extra for quick loading
  374.         lainchan = document.getElementById("lain"); // extra for quick loading
  375.         if (VID_THEATRE_MODE === true) {lainchan.hidden = true;}
  376.         setupDownload();
  377.     }
  378.     function lainLeave() {
  379.         vid.onerror = function() {};
  380.         vid.remove();
  381.         if (lainSFX !== "") {lainSFX.remove();}
  382.         btn_area.remove();
  383.         favoritesplaylistMenuBox.remove();
  384.         lainchan.remove();
  385.         document.getElementsByTagName("body")[0].innerHTML = "";
  386.         document.getElementsByTagName("html")[0].style.backgroundImage = "url(\"" + resource_img_bg + "\")"; // ignore warning - is in FuckJewTubeResources.js
  387.         document.getElementsByTagName("body")[0].style = "background-repeat: no-repeat; background-position: bottom left; background-size: contain; margin: auto; height: 100%; background-color: transparent !important;";
  388.         document.getElementsByTagName("body")[0].style.backgroundImage = "url(\"" + resource_img_lain_smug + "\")"; // ignore warning - is in FuckJewTubeResources.js
  389.     }
  390.     function GETrandomvid(e) {
  391.         randomytid = randomVidIDarray[Math.floor(Math.random()*randomVidIDarray.length)]; // ignore warning - is in FuckJewTubeRandomVideos.js
  392.         while (randomytid === ytid) {randomytid = randomVidIDarray[Math.floor(Math.random()*randomVidIDarray.length)];} // ignore warning - is in FuckJewTubeRandomVideos.js
  393.         if (e === "hk_random") {window.location.href = "https://www.youtube.com/watch?v=" + randomytid;} // hotkey random
  394.         else if (e === "hk_mix") {window.location.href = "https://www.youtube.com/watch?v=" + randomytid + "&list=RD" + randomytid;} // hotkey mix
  395.         else if (e.altKey) {
  396.             if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + randomytid + "&list=RD" + randomytid, "_blank");} // new tab
  397.             else {window.location.href = "https://www.youtube.com/watch?v=" + randomytid + "&list=RD" + randomytid;} // random mix
  398.         }
  399.         else if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + randomytid, "_blank");}
  400.         else {
  401.             if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {lainLeave();}
  402.             window.location.href = "https://www.youtube.com/watch?v=" + randomytid;
  403.         }
  404.     }
  405.     function searchVid(e) {
  406.         searchquery = prompt("Input search query\nPROTIP: -query = exclude (-query -query for multiple) | \"query\" = match | intitle:\"query\" = match in title | queries,[tag] = tag filtering (queries,[tag],[tag] for multiple)\nTags: hour, today, week, month, year, video, channel, playlist, movie, show, live, hd, cc, creativecommons, spherical, 3d, hdr, short, long\nSorting tags: date, views, rating (only use one - default sorting without a sorting tag is sort by relevance)\nExamples: \"dreamcast gameplay\" -sonic,video,long,views | intitle:\"sega saturn\" -music -trailer -opening,short,date | 同人ゲーム,rating\nNOTE: The language setting in your browser and the location of your IP affects which search results you get (i.e region restricted videos will not show up)");
  407.         if (searchquery === null || searchquery === undefined || searchquery === "" || searchquery.match(/[^ ]+/) === null) {if (searchquery === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  408.         else if (searchquery !== undefined || searchquery !== null || searchquery !== "") {
  409.             if (searchquery.includes(",date") === true || searchquery.includes(",views") === true || searchquery.includes(",rating") === true) {
  410.                 if (searchquery.includes(",date") === true) {
  411.                     u = "&search_sort=video_date_uploaded";
  412.                 }
  413.                 else if (searchquery.includes(",views") === true) {
  414.                     u = "&search_sort=video_view_count";
  415.                 }
  416.                 else {
  417.                     u = "&search_sort=video_avg_rating";
  418.                 }
  419.                 searchquery = searchquery.replace(",date", "").replace(",views", "").replace(",rating", "");
  420.             }
  421.             else {u = "";}
  422.             if (e.ctrlKey) {
  423.                 window.open("https://www.youtube.com/results?search_query=" + encodeURIComponent(searchquery) + u + "&disable_polymer=1&" + regionsetting, "_target");
  424.             }
  425.             else {
  426.                 if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {lainLeave();} window.location.href = "https://www.youtube.com/results?search_query=" + encodeURIComponent(searchquery) + u + "&disable_polymer=1&" + regionsetting;
  427.             }
  428.         }
  429.     }
  430.     function GETdescription() {
  431.         GETdescriptionattempts++;
  432.         if (GETdescriptionattempts > 13.37) {lainBugReport(); return;}
  433.         if (descriptionDone === false) {
  434.             u = "https://www.youtube.com/watch?v=" + ytid + "&disable_polymer=1&bpctr=9999999999&hl=en";
  435.             if (geocheck === true) {
  436.                 u = u + "&proxy=1";
  437.             }
  438.             GM_xmlhttpRequest({
  439.                 method: "GET",
  440.                 url: u,
  441.                 headers: {"Accept-Language": "en"},
  442.                 onerror: function(e) {console.log("GET DESCRIPTION FAIL #1"); GETdescription(); return;},
  443.                 onload: function(xhrDescription) {
  444.                     if (xhrDescription.status === 200) {
  445.                         try {
  446.                             descViews = xhrDescription.responseText.match(/interactionCount\" content=\"([^"]+)/)[1];
  447.                             descDate = xhrDescription.responseText.match(/datePublished" content="([^"]+)/)[1];
  448.                             descGenre = xhrDescription.responseText.match(/genre\" content=\"([^"]+)/)[1];
  449.                             try {u = xhrDescription.responseText.match(/<div id="watch-description-text[^>]+>[^>]+[^\n]+<\/p><\/div>/)[0];} // grab description
  450.                             catch(e) {u = "";} // if fail
  451.                             descriptionMenu.innerHTML = "";
  452.                             if (u === '<div id="watch-description-text" class=""><p id="eow-description" class="" ></p></div>' || u === '<div id="watch-description-text" class=""><p id="eow-description" class="metadata-updateable-description" ></p></div>') { // if empty
  453.                                 descriptionMenu.innerHTML = '<div id="watch-description-text" class=""><p id="eow-description" class="" style="margin-top: 5px;"><b style="color: skyblue; font-size: 18px;">No description</b></p></div>';
  454.                             }
  455.                             else if (u === "") { // if fail
  456.                                 descriptionMenu.innerHTML = '<div id="watch-description-text" class=""><p id="eow-description" class="" style="margin-top: 5px;"><b style="color: skyblue; font-size: 18px;">Description grabbing failed</b></p></div>';
  457.                             }
  458.                             else { // otherwise clean up etc
  459.                                 descriptionMenu.innerHTML = "<p style='color: skyblue; font-weight: bold; font-size: 18px; margin-top: 5px; margin-bottom: -5px;'>Description:</p>" + u;
  460.                                 if (descriptionMenu.getElementsByTagName("a")[0] !== undefined) { // fix links
  461.                                     Array.from(descriptionMenu.getElementsByTagName("a")).forEach(function(u) {
  462.                                         if (u.href.includes("disable_polymer=1") === false && u.href.includes("/watch") === false && u.href.includes("/redirect") === false) { // remove cancer
  463.                                             if (u.href.includes("/results") === true) {
  464.                                                 u.href = u.href + "&disable_polymer=1&" + regionsetting;
  465.                                             }
  466.                                             else if (u.href.includes("/playlist?") === true) {
  467.                                                 u.href = u.href + "&disable_polymer=1&" + regionsetting;
  468.                                             }
  469.                                             else if (u.href.includes("/channel") === true || u.href.includes("/user") === true) {
  470.                                                 if (u.href.includes("/featured") === false && u.href.includes("/videos") === false && u.href.includes("/playlist") === false && u.href.includes("/community") === false && u.href.includes("/discussion") === false && u.href.includes("/channels") === false && u.href.includes("/about") === false) {
  471.                                                     if (u.href.includes("?sub_confirmation=1") === true) {
  472.                                                         u.href = u.href.replace("?sub_confirmation=1", "");
  473.                                                     }
  474.                                                     u.href = u.href + "/featured?disable_polymer=1&" + regionsetting;
  475.                                                 }
  476.                                                 else if (u.href.includes("?") === false) {u.href = u.href + "?disable_polymer=1&" + regionsetting;}
  477.                                                 else {u.href = u.href + "&disable_polymer=1&" + regionsetting;}
  478.                                             }
  479.                                         }
  480.                                         if (u.href.includes("/redirect") === true) { // remove datamining
  481.                                             u.href = decodeURIComponent(u.href.match(/q=[^&]+/)[0].substring(2));
  482.                                             if (u.href.includes("https://www.youtube.com") === true) {
  483.                                                 u.href = u.href.replace(/https:\/\/www\.youtube\.com\/[^/]+\/[^/]+\//, "http://");
  484.                                             }
  485.                                         }
  486.                                         if (u.href.includes("view_play_list?p=") === true) { // alt playlist URLs
  487.                                             u.href = u.href.replace("view_play_list?p=", "playlist?list=");
  488.                                             u.href = u.href + "&disable_polymer=1&" + regionsetting;
  489.                                         }
  490.                                         if (u.href.includes("youtube.com/c/") === true) {
  491.                                             u.href = "https://www.youtube.com/channel/" + channelid + "/featured?disable_polymer=1&" + regionsetting;
  492.                                         }
  493.                                         if (u.href.includes("feed?disable_polymer=1") === true) {
  494.                                             u.href = u.href.replace("feed?disable_polymer=1", "featured?disable_polymer=1");
  495.                                         }
  496.                                         if (u.href.match(/https:\/\/[a-z0-9-.]+googlevideo\.com/) !== null) { // fix local links for livestreams
  497.                                             u.href = u.href.replace(/https:\/\/[a-z0-9-.]+googlevideo\.com/, "https://www.youtube.com");
  498.                                         }
  499.                                         if (u.getAttribute("onclick") !== null) { // fix fastSeek links
  500.                                             if (u.getAttribute("onclick").includes("yt.www.watch.player.seekTo") === true) {
  501.                                                 u.setAttribute("onclick", u.getAttribute("onclick").replace("yt.www.watch.player.seekTo", "videoplayer.fastSeek").replace("return false;", ""));
  502.                                                 u.removeAttribute("href");
  503.                                                 u.style.cursor = "pointer";
  504.                                                 u.addEventListener("click", function(){window.eval(u.getAttribute("onclick"));}); // ignore warning
  505.                                             }
  506.                                         }
  507.                                     });
  508.                                 }
  509.                             }
  510.                             descriptionMenu.insertAdjacentHTML("afterbegin", "<p style='color: skyblue; font-weight: bold; font-size: 16px; margin-top: 5px; margin-bottom: 5px;'>" + ytTitle + "</p><p style='color: #888; font-size: 14px; margin-top: 5px; margin-bottom: -15px;'>Author: " + channelauthor + "<br>Views: " + descViews + "<br>Genre: " + descGenre + "<br>Upload date: " + descDate + "</p><br>"); // extra info
  511.                             descriptionDone = true;
  512.                             GETdescriptionattempts = 0;
  513.                             return;
  514.                         }
  515.                         catch(e) {console.log("RETRYING GET DESCRIPTION"); GETdescription(); return;}
  516.                     }
  517.                     else {console.log("GET DESCRIPTION FAIL #2"); GETdescription(); return;}
  518.                 }
  519.             });
  520.         }
  521.     }
  522.     function GETvid() {
  523.         GETattempts ++;
  524.         if (GETattempts > 13.37) {
  525.             if (geocheck === true) {if (VID_PLAYLIST_MODE === true) {GETplaylistattempts++;} alert("ERROR: Proxying video id [" + ytid + "] failed.\nNOTE: Make sure the PAC script is properly setup. If it is, please report this video so it can be tested.\nIf this is happening to all region restricted videos please report that the current proxies might be offline.");}
  526.             if (VID_PLAYLIST_MODE === true) {if (GETplaylistattempts.length === playlistVideoIDs.length - 1) {alert("ERROR: Failed proxying every video in the playlist. Proxies might be offline or none of these videos are proxyable, be sure to report it."); lainBugReport();} else {GETattempts = 0; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}}
  527.             else {lainBugReport(); return;}
  528.         }
  529.         /* video title + author/channel start */
  530.         if (ytTitleDone === false) {
  531.             u = "https://www.youtube.com/watch?v=" + ytid + "&disable_polymer=1&bpctr=9999999999&hl=en";
  532.             if (geocheck === true) {
  533.                 u = u + "&proxy=1";
  534.             }
  535.             GM_xmlhttpRequest({
  536.                 method: "GET",
  537.                 url: u,
  538.                 headers: {"Accept-Language": "en"},
  539.                 onerror: function(e) {console.log("GET TITLE XHR FAIL"); GETvid(); return;},
  540.                 onload: function(xhrTitle) {
  541.                     if (xhrTitle.status === 200) {
  542.                         try {
  543.                             ytTitle = xhrTitle.responseText.match(/\"name\" content=\"([^"]+)/)[1];
  544.                             try {channelid = xhrTitle.responseText.match(/channelId\" content=\"([^"]+)/)[1];}
  545.                             catch {
  546.                                 try {channelid = xhrTitle.responseText.match(/channelId\\":\\"([^\\"]+)/)[1];} //fix1
  547.                                 catch {channelid = xhrTitle.responseText.match(/data-channel-external-id=\"([^"])+/)[1];} // fix2 extra
  548.                             }
  549.                             channelauthor = xhrTitle.responseText.match(/\"name\": \"([^"]+)/)[1];
  550.                             ytTitle = ytTitle.replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/\\u0026/g, "&").replace(/&amp;/g, "&");
  551.                             if (ytTitle.slice(0, 1) === "&" && ytTitle.match(/&[^&]+=/) !== null && VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video";}
  552.                             else {document.title = "Loading YT video: " + ytTitle;}
  553.                             ytTitleDone = true;
  554.                             startGETvid();
  555.                         }
  556.                         catch(e) {
  557.                             console.log("GET TITLE FAIL 1");
  558.                             GETvid(); return;
  559.                         }
  560.                     }
  561.                     else {console.log("GET TITLE FAIL 2"); GETvid(); return;}
  562.                 }
  563.             });
  564.         }
  565.         else {startGETvid();}
  566.         function startGETvid() {
  567.             /* video title + author/channel end */
  568.             console.log("Trying to GET video");
  569.             if (ytcheck === false) {
  570.                 ytajax = "https://www.youtube.com/get_video_info?video_id=" + ytid + "&el=embedded&hl=en&eurl=https%3A%2F%2Fyoutube.googleapis.com%2Fv%2F" + ytid + "&channelid=" + channelid; // embedded supports more videos - i.e age restricted
  571.             }
  572.             else {
  573.                 ytajax = "https://www.youtube.com/get_video_info?video_id=" + ytid + "&el=detailpage&hl=en&channelid=" + channelid; // makes videos without embed support work
  574.             }
  575.             if (geocheck === true) {ytajax = ytajax + "&proxy=1";} // for region restricted
  576.             function decipherVid() {
  577.                 document.title = "Deciphering YT video: " + ytTitle;
  578.                 function startDecipher() {
  579.                     muxstream = ytajax.substring(ytajax.indexOf("url_encoded_fmt_stream_map")).replace(/[&,]url=/g, "\n");
  580.                     if (GM.info.script.name === "FuckJewTubeSlowPokeEdition" && ytajax.includes("quality=hd720") === true) { // for 360p
  581.                         muxstream = muxstream.match(/https:\/\/[a-z0-9-.]+googlevideo\.com\/videoplayback\?.+/g)[1];
  582.                     }
  583.                     else {muxstream = muxstream.match(/https:\/\/[a-z0-9-.]+googlevideo\.com\/videoplayback\?.+/g)[0];} // for 720p + 360p with no 720p
  584.                     /* begin URL fix-up */
  585.                     muxstream = muxstream.replace(muxstream.match(/[?&=,]lsig=[^&]+(.+)/)[1], ""); // fix new garbage in video url
  586.                     if (muxstream.match(/[?&,=]itag=[^,&]+/g) !== null) { // in case of double itag= breaking the URL - this should fix the random retry bullshit
  587.                         if (muxstream.match(/[?&,=]itag=[^,&]+/g).length > 1) {
  588.                             muxstream = muxstream.replace(muxstream.match(/[?&,=]itag=[^,&]+/g)[1], "");
  589.                         }
  590.                     }
  591.                     if (muxstream.match(/[?&=,]s=[^&]+/g) !== null) { // remove s=
  592.                         muxstream = muxstream.replace(/[?&=,]s=[^&]+/g, "");
  593.                     }
  594.                     if (muxstream.match(/[?&=,]sp=[a-zA-Z0-9]+/g) !== null) { // remove sp=
  595.                         muxstream = muxstream.replace(/[?&=,]sp=[a-zA-Z0-9]+/g, "");
  596.                     }
  597.                     if (muxstream.match(/,[^,&]+=.+/) !== null) {
  598.                         muxstream = muxstream.replace(muxstream.match(/,[^,&]+=.+/)[0], "");
  599.                     }
  600.                     /* end URL fix up */
  601.                     /* sig begin */
  602.                     if (GM.info.script.name === "FuckJewTubeSlowPokeEdition" && ytajax.includes("quality=hd720") === true) {
  603.                         try {sig = ytajax.substring(ytajax.indexOf("url_encoded_fmt_stream_map")).match(/[?&=,]s=[.A-Za-z0-9=_-]+/g)[1];}
  604.                         catch(e) {console.log("CIPHERED SIGNATURE FAIL #1"); GETvid(); return;}
  605.                     }
  606.                     else {
  607.                         try {sig = ytajax.substring(ytajax.indexOf("url_encoded_fmt_stream_map")).match(/[?&=,]s=[.A-Za-z0-9=_-]+/g)[0];}
  608.                         catch(e) {console.log("CIPHERED SIGNATURE FAIL #2"); GETvid(); return;}
  609.                     }
  610.                     sig = sig.substring(3); // store signature that needs to be deciphered
  611.                     /* sig end */
  612.                     function uncipheredURL() {
  613.                         a = decipher(sig); // decipher signature
  614.                         muxstream = muxstream.replace("videoplayback?", "videoplayback?sig=" + a + "&");
  615.                         console.log("Trying to play deciphered video");
  616.                         vid.src = muxstream;
  617.                         if (VID_ERROR === true) {VID_ERROR = false; vid.fastSeek(vidtime); if (VID_PLAYLIST_MODE === false) {document.title = "YT video: " + ytTitle;} else {document.title = "YT playlist: " + ytPlaylistTitle + " | " + ytTitle;}}
  618.                         else {vid.play();}
  619.                         return;
  620.                     }
  621.                     if (decipherExtractDone === false) {
  622.                         GM_xmlhttpRequest({
  623.                             method: "GET",
  624.                             url: playerBaseURL,
  625.                             headers: {"Accept-Language": "en"},
  626.                             onerror: function(e) {console.log("DECIPHER FAIL #1"); GETvid(); return;},
  627.                             onload: function(xhrPlayerBase) {
  628.                                 if (xhrPlayerBase.status === 200) { // remove jewish trickery
  629.                                     try { // get decipher function
  630.                                         decipherFunction = xhrPlayerBase.responseText.match(/(\w+)\s*=\s*function\((\w+)\)({\s*\2=\s*\2\.split\(""\)\s*;.+)/)[3];
  631.                                     }
  632.                                     catch(e) {console.log("DECIPHER FAIL #2"); playerBaseURL = ""; GETvid(); return;} // grab playerbase again if fail
  633.                                     decipherVarName = xhrPlayerBase.responseText.match(/(\w+)\s*=\s*function\((\w+)\){\s*\2=\s*\2\.split\(""\)\s*;.{2}/)[0];
  634.                                     decipherVarName = decipherVarName.slice(decipherVarName.length - 2); // get decipher var name
  635.                                     if (decipherVarName.includes("$")) {decipherVarName = decipherVarName.replace("$", "\\$");} // extra
  636.                                     regex = "var " + decipherVarName + "=\{[^:]+:[^}]+\},[^:]+:[^}]+\},[^:]+:[^}]+\}\};"; // regex for getting decipher operations
  637.                                     decipherOperations = xhrPlayerBase.responseText.replace(/\r?\n|\r/g, ""); // remove newline
  638.                                     try {decipherOperations = decipherOperations.match(RegExp(regex)).toString();} // get decipher operations
  639.                                     catch(e) {console.log("DECIPHER FAIL #3"); playerBaseURL = ""; GETvid(); return;} // grab playerbase again if fail
  640.                                     window.eval(decipherOperations); // convert from string to actual operation - ignore the warning
  641.                                     decipher = new Function("a", decipherFunction); // convert from string to actual function
  642.                                     decipherExtractDone = true;
  643.                                     uncipheredURL();
  644.                                     return;
  645.                                 }
  646.                                 else {
  647.                                     console.log("DECIPHER FAIL #4"); GETvid();
  648.                                     return;
  649.                                 }
  650.                             }
  651.                         });
  652.                     }
  653.                     else {uncipheredURL(); return;}
  654.                 }
  655.                 if (playerBaseURL.includes("base.js") === false) {
  656.                     lainLoading();
  657.                     GM_xmlhttpRequest({
  658.                         method: "GET",
  659.                         url: "https://www.youtube.com/watch?v=" + ytid + "&disable_polymer=1&bpctr=9999999999&hl=en",
  660.                         headers: {"Accept-Language": "en"},
  661.                         onerror: function(e) {console.log("PLAYER BASE FAIL #1"); GETvid(); return;},
  662.                         onload: function(xhrBaseURL) {
  663.                             if (xhrBaseURL.status === 200) {
  664.                                 try {playerBaseURL = xhrBaseURL.responseText.match(/yts\/[^"]+\/base\.js/)[0];} // this should work for everyone now, thanks for all the help anon
  665.                                 catch(e) {console.log("PLAYER BASE FAIL #2"); GETvid(); return;}
  666.                                 playerBaseURL = "https://s.ytimg.com/" + playerBaseURL;
  667.                                 startDecipher();
  668.                                 return;
  669.                             }
  670.                             else {console.log("PLAYER BASE FAIL #3"); GETvid(); return;}
  671.                         }
  672.                     });
  673.                 }
  674.                 else {startDecipher(); return;}
  675.             }
  676.             function PLAYvid() {
  677.                 console.log("Trying to play video");
  678.                 muxstream = ytajax.substring(ytajax.indexOf("url_encoded_fmt_stream_map")).replace(/[&,]url=/g, "\n");
  679.                 if (GM.info.script.name === "FuckJewTubeSlowPokeEdition" && ytajax.includes("quality=hd720") === true) { // for 360p
  680.                     muxstream = muxstream.match(/https:\/\/[a-z0-9-.]+googlevideo\.com\/videoplayback\?.+/g)[1];
  681.                 }
  682.                 else {muxstream = muxstream.match(/https:\/\/[a-z0-9-.]+googlevideo\.com\/videoplayback\?.+/g)[0];} // for 720p + 360p with no 720p
  683.                 /* begin URL fix-up */
  684.                 if (muxstream.match(/[?&,=]itag=[^,&]+/g) !== null) { // in case of double itag= breaking the URL - this should fix the random retry bullshit
  685.                     if (muxstream.match(/[?&,=]itag=[^,&]+/g).length > 1) {
  686.                         muxstream = muxstream.replace(muxstream.match(/[?&,=]itag=[^,&]+/g)[1], "");
  687.                     }
  688.                 }
  689.                 if (muxstream.match(/,[^,&]+=.+/) !== null) {
  690.                     muxstream = muxstream.replace(muxstream.match(/,[^,&]+=.+/)[0], "");
  691.                 }
  692.                 /* end URL fix-up */
  693.                 setTimeout( function() { // timing fix
  694.                     vid.src = muxstream;
  695.                     if (VID_ERROR === true) {VID_ERROR = false; vid.fastSeek(vidtime); if (VID_PLAYLIST_MODE === false) {document.title = "YT video: " + ytTitle;} else {document.title = "YT playlist: " + ytPlaylistTitle + " | " + ytTitle;}}
  696.                     else {vid.play();}
  697.                     return;
  698.                 }, 777);
  699.             }
  700.             GM_xmlhttpRequest({
  701.                 method: "GET",
  702.                 url: ytajax,
  703.                 headers: {"Accept-Language": "en"},
  704.                 onerror: function(e) {console.log("GET VIDEO FAIL #1"); GETvid(); return;},
  705.                 onload: function(xhr) {
  706.                     if (xhr.status === 200) {
  707.                         /* regular start */
  708.                         try {ytajax = decodeURIComponent(decodeURIComponent(decodeURIComponent(xhr.responseText)));} // fix-up the URI encoding
  709.                         catch(e) { // in-case of URIError
  710.                             ytajax = decodeURIComponent(xhr.responseText);
  711.                             ytajax = ytajax.replace(/(%3A%2F%2F)+/g, "://"); ytajax = ytajax.replace(/(%2F)+/g, "/"); ytajax = ytajax.replace(/(%26)+/g, "&"); ytajax = ytajax.replace(/(%3D)+/g, "="); ytajax = ytajax.replace(/(%2C)+/g, ","); ytajax = ytajax.replace(/(%252C)+/g, ","); ytajax = ytajax.replace(/(%3F)+/g, "?"); ytajax = ytajax.replace(/(%252F)+/g, "/"); ytajax = ytajax.replace(/(%20)+/g, " ");
  712.                         }
  713.                         /* captions start */
  714.                         if (ytajax.includes("captionTracks") === true && ccDone === false) {
  715.                             VID_HAS_CC = true;
  716.                             ccURL = ytajax.match(/timedtext\?[^"]+lang=[^\"]+/g);
  717.                             ccName = ytajax.match(/","name":\{"simpleText":"[^"]+/g);
  718.                             function GETcc(u, index) {
  719.                                 u = "https://www.youtube.com/api/" + u;
  720.                                 u = u.replace(/\\\\u0026/g, "&"); u = u.replace(/\\u0026/g, "&");
  721.                                 GM_xmlhttpRequest({
  722.                                     method: "GET",
  723.                                     url: u,
  724.                                     headers: {"Accept-Language": "en"},
  725.                                     onerror: function(e) {console.log("GET CAPTIONS FAIL #1"); GETvid(); return;},
  726.                                     onload: function(xhrCC) {
  727.                                         if (xhrCC.status === 200) {
  728.                                             if (xhrCC.responseText !== undefined) {
  729.                                                 ccajax = xhrCC.responseText;
  730.                                                 /* begin CC cleanup */
  731.                                                 ccajax = ccajax.replace(/&amp;#39;/g, "'").replace(/&amp;quot;/g, '"').replace(/&quot;/g, "").replace(/&lt;font[^&]+&gt;/g, "").replace(/&lt;\/font&gt;/g, "").replace(/&amp;lt;[bciuv]&amp;gt;/g, "").replace(/&amp;lt;\/[bciuv]&amp;gt;/g, "").replace(/&amp;amp;/g, "&").replace(/[ ][ ]+/g, " ").replace(/&amp;lt;/g, "&lt;").replace(/&amp;gt;/g, "&gt;").replace(/&lt;[bciuv]&gt;/g, "").replace(/&lt;\/[bciuv]&gt;/g, "").replace(/\n[ ]+/g, "\n").replace(/>[ ]+/g, ">");
  732.                                                 /* end CC cleanup */
  733.                                                 ccStart = ccajax.match(/start="\S+\"/g);
  734.                                                 ccDur = ccajax.match(/dur="\S+\"/g); // end = start + dur
  735.                                                 ccText = ccajax.match(/>[^<]+<\/text/g);
  736.                                                 if (ccStart.length > ccDur.length) { // fix CC with start being alone at beginning
  737.                                                     while (ccStart.length > ccDur.length) {
  738.                                                         ccStart.splice(0, 1);
  739.                                                     }
  740.                                                     ytsbv2vtt();
  741.                                                 }
  742.                                                 else {ytsbv2vtt();}
  743.                                                 function ytsbv2vtt() { // convert YT sbv 2 vtt
  744.                                                     ccVTT = "WEBVTT";
  745.                                                     for (i = 0; ccText.length - 1 >= i; i++) {
  746.                                                         ccVTTstart = parseFloat(ccStart[i].match(/"[\d.]+"/)[0].replace(/\"/g, "")); // get start seconds
  747.                                                         ccVTTend = parseFloat(ccStart[i].match(/"[\d.]+"/)[0].replace(/\"/g, "")) + parseFloat(ccDur[i].match(/"[\d.]+"/)[0].replace(/\"/g, "")); // get end seconds
  748.                                                         ccVTTstart = new Date(ccVTTstart * 1000).toISOString().substr(11, 12); // fixup format and convert to string
  749.                                                         ccVTTend = new Date(ccVTTend * 1000).toISOString().substr(11, 12); // same as above
  750.                                                         ccVTT = ccVTT + "\n\n" + ccVTTstart + " --> " + ccVTTend + " line:99% size:"; // add timing to VTT
  751.                                                         if (ccText[i].slice(1, -6).length > 60 && ccText[i].slice(1, -6).includes("\n") === false) {ccVTT = ccVTT + "85%";} // line wrap fixup for no \n included
  752.                                                         else {ccVTT = ccVTT + "99%";}
  753.                                                         ccVTT = ccVTT + "\n" + ccText[i].slice(1, -6); // add text to VTT string
  754.                                                     }
  755.                                                     if (ccVTT.match(/.+\s+.+--&amp;gt;.+/g) !== null) { // extra fixup in case CC creator messed up
  756.                                                         ccVTT.match(/.+\s+.+--&amp;gt;.+/g).forEach(function(u, i, a){
  757.                                                             u = u.replace("&amp;gt;", ">").replace(/.+\s+/, "\n") + " line:99% size:99%";
  758.                                                             ccVTT = ccVTT.replace(a[i], u);
  759.                                                         });
  760.                                                     }
  761.                                                     if (ccVTT.match(/[\d]{2},[\d]{3}/g) !== null) { // extra fixup in case CC creator messed up
  762.                                                         ccVTT.match(/[\d]{2},[\d]{3}/g).forEach(function(u, i, a){
  763.                                                             u = u.replace(",", ".");
  764.                                                             ccVTT = ccVTT.replace(a[i], u);
  765.                                                         });
  766.                                                     }
  767.                                                     ccBlob = new Blob([ccVTT], {type : "text/vtt"}); // convert to blob to be used in track src
  768.                                                     ccBlob = URL.createObjectURL(ccBlob);
  769.                                                     ccTrack = document.createElement("track");
  770.                                                     ccTrack.setAttribute("kind", "captions");
  771.                                                     ccTrack.setAttribute("label", ccName[index].replace(/","name":{"simpleText":"/, "").replace(/[+]/g, " ").replace(/ - .+/, "")); // fix language names in html5 player menu
  772.                                                     ccTrack.setAttribute("src", ccBlob);
  773.                                                     vid.appendChild(ccTrack);
  774.                                                 }
  775.                                             }
  776.                                         }
  777.                                         else {
  778.                                             console.log("GET CAPTIONS FAIL #2"); GETvid(); return;
  779.                                         }
  780.                                     }
  781.                                 });
  782.                             }
  783.                             ccURL.forEach(GETcc);
  784.                             ccInterval = setInterval( function() {
  785.                                 for (i = 0; vid.textTracks.length - 1 >= i; i++) {
  786.                                     if (vid.textTracks[i] !== undefined && vid.textTracks[i].mode === "showing") {
  787.                                         trackPosFix(333);
  788.                                         break;
  789.                                     }
  790.                                 }
  791.                             }, 333);
  792.                             function trackPosFix(u) {
  793.                                 if (vid.textTracks[i] !== undefined && vid.textTracks[i].activeCues[0] !== undefined) {
  794.                                     vid.textTracks[i].activeCues[0].line = 98.9999999;
  795.                                     setTimeout( function() {
  796.                                         if (vid.textTracks[i] !== undefined && vid.textTracks[i].activeCues[0] !== undefined) {
  797.                                             vid.textTracks[i].activeCues[0].line = 99;
  798.                                         }
  799.                                     }, u);
  800.                                 }
  801.                             }
  802.                             ccDone = true;
  803.                         }
  804.                         else if (ccDone === false) {VID_HAS_CC = false;}
  805.                         /* captions end */
  806.                         /* ciphered check start */
  807.                         if (ytajax.match(/[?&=,]s=[.A-Z0-9]+/g) !== null) { // in case of ciphered video
  808.                             decipherVid();
  809.                             return;
  810.                         }
  811.                         /* ciphered check end */
  812.                         /* muxcheck start */
  813.                         else if (ytajax.includes("This+video+requires+payment+to+watch") === true) { // paid vid
  814.                             document.title = "Loading paid YT video trailer: " + ytTitle;
  815.                             try {ytid = ytajax.match(/ypc_vid=.{11}/)[0].replace("ypc_vid=", "");}
  816.                             catch(e){
  817.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping paid video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  818.                                 else {
  819.                                     lainFail();
  820.                                     alert("ERROR: Paid video trailer is unavailable.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  821.                                     document.title = "Paid YT video: " + ytTitle;
  822.                                     return;
  823.                                 }
  824.                             }
  825.                             geocheck = false; muxcheck = false; GETvid(); return;
  826.                         }
  827.                         else if (ytajax.includes("quality=hd720") === false && ytajax.includes("quality=medium") === false && ytcheck === true) { // in case no direct links are found
  828.                             /* livestream check start */
  829.                             if (ytajax.includes(".m3u8") === true) { // livestream
  830.                                 if (VID_PLAYLIST_MODE === true) { // ask if skip or play livestream in playlist mode
  831.                                     u = confirm("NOTE: The following video is a livestream.\n" + ytTitle + "\nPress OK to play with playlist mode disabled or CANCEL to skip.");
  832.                                     if (u === false) {document.title = "Skipping livestream"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  833.                                 }
  834.                                 GM.setValue("videoTitle", ytTitle); // store video title
  835.                                 GM.setValue("videoAuthor", channelauthor); // store video author
  836.                                 GM.setValue("videoChannelID", channelid); // store video channel ID
  837.                                 GM.setValue("videoOrigURL", window.location.href); // store orig vid URL
  838.                                 document.title = "YT livestream: " + ytTitle;
  839.                                 GM_xmlhttpRequest({
  840.                                     method: "GET",
  841.                                     url: "https://www.youtube.com/watch?v=" + ytid + "&disable_polymer=1&bpctr=9999999999&hl=en",
  842.                                     headers: {"Accept-Language": "en"},
  843.                                     onerror: function(e) {GETvid(); console.log("LIVESTREAM FAIL #1"); return;},
  844.                                     onload: function(xhrLS1) {
  845.                                         ytajax = xhrLS1.responseText;
  846.                                         ytajax = ytajax.replace(/(%3A%2F%2F)+/g, "://"); ytajax = ytajax.replace(/(%2F)+/g, "/"); ytajax = ytajax.replace(/(%26)+/g, "&"); ytajax = ytajax.replace(/(%3D)+/g, "="); ytajax = ytajax.replace(/(%2C)+/g, ","); ytajax = ytajax.replace(/(%252C)+/g, ","); ytajax = ytajax.replace(/(%3F)+/g, "?"); ytajax = ytajax.replace(/(%252F)+/g, "/"); ytajax = ytajax.replace(/(%20)+/g, " "); ytajax = ytajax.replace(/(%25)+/g, "");
  847.                                         livestreamURL = ytajax.match(/https:\\\/\\\/manifest.googlevideo.com\\\/api\\\/manifest\\\/hls_variant\\\/.+.m3u8/)[0].replace(/\\\//g, "/");
  848.                                         GM.setValue("videoLivestreamURL", livestreamURL);
  849.                                         GM_xmlhttpRequest({
  850.                                             method: "GET",
  851.                                             url: livestreamURL,
  852.                                             headers: {"Accept-Language": "en"},
  853.                                             onerror: function(e) {GETvid(); console.log("LIVESTREAM FAIL #2"); return;},
  854.                                             onload: function(xhrLS2) {
  855.                                                 if (xhrLS2.responseText.includes("Error 404") === true) {
  856.                                                     lainFail();
  857.                                                     alert("ERROR: This livestream is not available for an unknown reason.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  858.                                                     document.title = "Unavailable YT livestream: " + ytTitle;
  859.                                                     return;
  860.                                                 }
  861.                                                 livestreamURL = xhrLS2.responseText.match(/\/r\d[^.]+./)[0].substring(1);
  862.                                                 window.location.href = "https://" + livestreamURL + "googlevideo.com/videoplayback?(´。• ω •。`)"; // redirect to googlevideo.com so hls.js can do XHRs
  863.                                             }
  864.                                         });
  865.                                     }
  866.                                 });
  867.                                 return;
  868.                             }
  869.                             /* livestream check end */
  870.                             else if (ytajax.includes("The+YouTube+account+associated+with+this+video+has+been+terminated+due+to+multiple+third-party+notifications+of+copyright+infringement") === true) {
  871.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  872.                                 else {
  873.                                     lainFail();
  874.                                     alert("ERROR: This brave soul ignored multiple (((third party))) copyright infringement notifications and paid the ultimate price.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  875.                                     document.title = "[REDACTED] YT video ;_;7";
  876.                                     return;
  877.                                 }
  878.                             }
  879.                             else if (ytajax.includes("This+live+event+will+begin") === true || ytajax.includes("reason\":\"Offline.") === true) {
  880.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping unstarted livestream"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  881.                                 else {
  882.                                     lainFail();
  883.                                     alert("ERROR: Livestream has not yet started.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  884.                                     document.title = "Unstarted YT livestream: " + ytTitle;
  885.                                     return;
  886.                                 }
  887.                             }
  888.                             else if (ytajax.includes("This+live+stream+recording+is+not+available") === true || ytajax.includes("This+live+event+has+ended") === true) {
  889.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping ended livestream"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  890.                                 else {
  891.                                     lainFail();
  892.                                     alert("ERROR: Livestream has ended and a livestream recording is not available.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  893.                                     document.title = "Unavailable YT livestream: " + ytTitle;
  894.                                     return;
  895.                                 }
  896.                             }
  897.                             else if (ytajax.includes("This+video+is+no+longer+available+because+the+YouTube+account+associated+with+this+video+has+been+terminated") === true) {
  898.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  899.                                 else {
  900.                                     lainFail();
  901.                                     alert("ERROR: Video uploader and all video uploads have been [REDACTED].\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  902.                                     document.title = "[REDACTED] YT video ;_;7";
  903.                                     return;
  904.                                 }
  905.                             }
  906.                             else if (ytajax.includes("This+video+has+been+removed+for+violating+YouTube's+policy+on+hate+speech") === true) {
  907.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  908.                                 else {
  909.                                     lainFail();
  910.                                     alert("ERROR: This video has been [REDACTED] for \"hate speech\".\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  911.                                     document.title = "[REDACTED] YT video ;_;7";
  912.                                     return;
  913.                                 }
  914.                             }
  915.                             else if (ytajax.includes("This+video+has+been+removed+for+violating+YouTube's+policy+on+violent+or+graphic+content") === true) {
  916.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  917.                                 else {
  918.                                     lainFail();
  919.                                     alert("ERROR: This video has been [REDACTED] for featuring \"violent or graphical content\".\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  920.                                     document.title = "[REDACTED] YT video ;_;7";
  921.                                     return;
  922.                                 }
  923.                             }
  924.                             else if (ytajax.includes("This+video+is+no+longer+available+because+the+uploader+has+closed+their+YouTube+account") === true) {
  925.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  926.                                 else {
  927.                                     lainFail();
  928.                                     alert("ERROR: This video has been [REDACTED] because the uploader deleted their account.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  929.                                     document.title = "[REDACTED] YT video ;_;7";
  930.                                     return;
  931.                                 }
  932.                             }
  933.                             else if (ytajax.includes("This+video+is+unavailable") === true || ytajax.includes("This+video+has+been+removed+by+the+user") === true || ytajax.includes("The+uploader+has+not+made+this+video+available.") === true) {
  934.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  935.                                 else {
  936.                                     lainFail();
  937.                                     alert("ERROR: This video has been [REDACTED] by the uploader.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  938.                                     document.title = "[REDACTED] YT video ;_;7";
  939.                                     return;
  940.                                 }
  941.                             }
  942.                             else if (ytajax.includes("blocked+it+in+your+country+on+copyright+grounds") === true || ytajax.includes("blocked+it+on+copyright+grounds") === true) { // if no proxies seem to work
  943.                                 if (GETattempts === 13 && VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  944.                                 else if (GETattempts === 13) {
  945.                                     lainFail();
  946.                                     ytajax = ytajax.match(/from\+[^"]+[+]who/)[0];
  947.                                     ytajax = ytajax.replace("from+", ""); ytajax = ytajax.replace(",+who", "");
  948.                                     alert("ERROR: This video has been [REDACTED] by (((" + ytajax.replace(/\++/g, " ").replace(/\\u0026/g, "&") + "))) who has [REDACTED] it on your planet on \"copyright grounds\".\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  949.                                     document.title = "Copyright claimed YT video: " + ytTitle;
  950.                                     return;
  951.                                 }
  952.                             }
  953.                             if (ytajax.includes("is+no+longer+available+due+to+a+copyright+claim") === true) {
  954.                                 if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  955.                                 else {
  956.                                     lainFail();
  957.                                     ytajax = ytajax.match(/simpleText\":\"\\".+\.\"},/)[0];
  958.                                     ytajax = ytajax.replace('simpleText\":\"\\\"', '');
  959.                                     ytTitle = ytajax.substring(0, ytajax.indexOf('...\\\"')).replace(/\++/g, " ");
  960.                                     ytajax = ytajax.replace('\\\"', ''); ytajax = ytajax.replace("by+", "by: ((("); ytajax = ytajax.replace('.\"},', ')))'); ytajax = ytajax.replace(/\++/g, " ");
  961.                                     alert("ERROR: " + ytajax + "\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  962.                                     document.title = "Copyright claimed YT video: " + ytTitle + "...";
  963.                                     return;
  964.                                 }
  965.                             }
  966.                             else if (ytajax.includes("The+uploader+has+not+made+this+video+available+in+your+country") === true || ytajax.includes("This+content+is+not+available+on+this+country+domain") === true || ytajax.includes("This+video+is+not+available") === true || ytajax.includes("blocked+it+in+your+country+on+copyright+grounds") === true || ytajax.includes("blocked+it+on+copyright+grounds") === true) { // geo restricted
  967.                                 if (muxcheck === false) {
  968.                                     muxcheck = true;
  969.                                     document.title = "Proxying YT video: " + ytTitle;
  970.                                     lainLoading();
  971.                                 }
  972.                                 geocheck = true;
  973.                                 console.log("TRYING TO PROXY VIDEO"); GETvid();
  974.                                 return;
  975.                             }
  976.                             else if (ytajax.includes("The+following+content+has+been+identified+by+the+YouTube+community+as+inappropriate+or+offensive+to+some+audiences") === true) { // scrape page to get links
  977.                                 if (muxcheck === false) {
  978.                                     muxcheck = true;
  979.                                     if (geocheck === true) {document.title = "Proxying YT video: " + ytTitle;}
  980.                                     else {document.title = "Loading YT video: " + ytTitle;}
  981.                                     lainLoading();
  982.                                 }
  983.                                 offensivevidURL = "https://www.youtube.com/watch?v=" + ytid + "&disable_polymer=1&bpctr=9999999999&hl=en";
  984.                                 if (geocheck === true) {
  985.                                     offensivevidURL = offensivevidURL + "&proxy=1";
  986.                                 }
  987.                                 function GEToffensivevid() {
  988.                                     GM_xmlhttpRequest({
  989.                                         method: "GET",
  990.                                         url: offensivevidURL,
  991.                                         headers: {"Accept-Language": "en"},
  992.                                         onerror: function(e) {console.log("OFFENSIVE FAIL #1"); GETvid(); return;},
  993.                                         onload: function(xhrRedacted) {
  994.                                             if (xhrRedacted.status === 200) {
  995.                                                 ytajax = xhrRedacted.responseText;
  996.                                                 ytajax = ytajax.replace(/(%3A%2F%2F)+/g, "://"); ytajax = ytajax.replace(/(%2F)+/g, "/"); ytajax = ytajax.replace(/(%26)+/g, "&"); ytajax = ytajax.replace(/(%3D)+/g, "="); ytajax = ytajax.replace(/(%2C)+/g, ","); ytajax = ytajax.replace(/(%252C)+/g, ","); ytajax = ytajax.replace(/(%3F)+/g, "?"); ytajax = ytajax.replace(/(%252F)+/g, "/"); ytajax = ytajax.replace(/(%20)+/g, " "); ytajax = ytajax.replace(/(%25)+/g, ""); ytajax = ytajax.replace(/(\\u0026)+/g, "&");
  997.                                                 if (ytajax.match(/[?&=,]s=[.A-Z0-9]+/g) !== null) {
  998.                                                     decipherVid();
  999.                                                     return;
  1000.                                                 }
  1001.                                                 else {
  1002.                                                     PLAYvid();
  1003.                                                     return;
  1004.                                                 }
  1005.                                             }
  1006.                                             else {console.log("OFFENSIVE FAIL #2"); GETvid(); return;}
  1007.                                         }
  1008.                                     });
  1009.                                 }
  1010.                                 GEToffensivevid();
  1011.                                 return;
  1012.                             }
  1013.                             else {
  1014.                                 if (ytajax.includes("quality=small") === true || ytajax.includes("quality=tiny") === true) {PLAYvid(); return;} // if missing both 360p & 720p but still have 240p or 144p
  1015.                                 else if (VID_PLAYLIST_MODE === true) {document.title = "Skipping [REDACTED] video"; if (prevVideo === false) {nextPlaylist();} else {prevPlaylist();} return;}
  1016.                                 else {
  1017.                                     lainFail();
  1018.                                     alert("ERROR: Invalid video ID.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  1019.                                     document.title = "Invalid YT video ID ¯\\_(ツ)_/¯";
  1020.                                     return;
  1021.                                 }
  1022.                             }
  1023.                         }
  1024.                         /* muxcheck end */
  1025.                         /* embed fail check start */
  1026.                         else if (ytajax.includes("quality=hd720") === false && ytajax.includes("quality=medium") === false && ytcheck === false) { // in case of no embed support
  1027.                             ytcheck = true;
  1028.                             console.log("EMBED VIDEO INFO FAIL"); GETvid();
  1029.                             return;
  1030.                         }
  1031.                         /* embed fail check end */
  1032.                         else {PLAYvid(); return;}
  1033.                     }
  1034.                     /* regular end */
  1035.                     else {console.log("GET VIDEO FAIL #2"); GETvid(); return;} // if we fail even though all the above
  1036.                 }
  1037.             });
  1038.         }
  1039.     }
  1040.     /* start playlists */
  1041.     function nextPlaylist() {
  1042.         if (PLAYLIST_REVERSE_MODE === true) {prevPlaylist();}
  1043.         else {
  1044.             if (btn_area.style.display === "none") {setupUI();} // fix for playlists with unplayable vids at start
  1045.             prevVideo = false;
  1046.             clearInterval(ccInterval);
  1047.             ccDone = false;
  1048.             lainSFX.pause();
  1049.             vid.style.display = "none";
  1050.             vid.innerHTML = "";
  1051.             if (PLAYLIST_SHUFFLE_MODE === true) {
  1052.                 shuffleArray.push(playlistpos);
  1053.                 if (shuffleArray.length >= playlistVideoIDs.length) {shuffleArray = [playlistpos];}
  1054.                 while (shuffleArray.indexOf(playlistpos) !== -1) {playlistpos = Math.floor(Math.random() * playlistVideoIDs.length);}
  1055.             }
  1056.             else if (playlistpos >= playlistVideoIDs.length - 1) {
  1057.                 playlistpos = 0;
  1058.             }
  1059.             else {
  1060.                 playlistpos = playlistpos + 1;
  1061.             }
  1062.             ytid = playlistVideoIDs[playlistpos];
  1063.             ytTitleDone = false;
  1064.             ytcheck = false;
  1065.             descriptionDone = false;
  1066.             geocheck = false;
  1067.             muxcheck = false;
  1068.             setTimeout( function() { // timing fix
  1069.                 lainPlaylistLoading();
  1070.             }, 100);
  1071.             GETvid(); return;
  1072.         }
  1073.     }
  1074.     function prevPlaylist() {
  1075.         prevVideo = true;
  1076.         clearInterval(ccInterval);
  1077.         ccDone = false;
  1078.         lainSFX.pause();
  1079.         vid.style.display = "none";
  1080.         vid.innerHTML = "";
  1081.         if (PLAYLIST_SHUFFLE_MODE === true) {
  1082.             shuffleArray.push(playlistpos);
  1083.             if (shuffleArray.length >= playlistVideoIDs.length) {shuffleArray = [playlistpos];}
  1084.             while (shuffleArray.indexOf(playlistpos) !== -1) {playlistpos = Math.floor(Math.random() * playlistVideoIDs.length);}
  1085.         }
  1086.         else if (playlistpos <= 0) {
  1087.             playlistpos = playlistVideoIDs.length - 1;
  1088.         }
  1089.         else {
  1090.             playlistpos = playlistpos - 1;
  1091.         }
  1092.         ytid = playlistVideoIDs[playlistpos];
  1093.         ytTitleDone = false;
  1094.         ytcheck = false;
  1095.         descriptionDone = false;
  1096.         geocheck = false;
  1097.         muxcheck = false;
  1098.         setTimeout( function() { // timing fix
  1099.             lainPlaylistLoading();
  1100.         }, 100);
  1101.         GETvid(); return;
  1102.     }
  1103.     function playPlaylist() {
  1104.         /* check if all [REDACTED] start */
  1105.         i = 0;
  1106.         playlistVideoTitles.forEach(function(u) {
  1107.             if (u === "[Private video]" || u === "[Deleted video]") {i++;}
  1108.         });
  1109.         if (i === playlistVideoTitles.length) {playlistNoPlayable(); return;}
  1110.         /* check if all [REDACTED] end */
  1111.         GM.setValue("videoRandomMode", "false");
  1112.         VID_RANDOM_MODE = false;
  1113.         if (window.location.href.match(/index=\d+/) !== null) {
  1114.             playlistpos = window.location.href.match(/index=\d+/)[0].substring(6) - 2;
  1115.             ytid = playlistVideoIDs[playlistpos];
  1116.             ytTitle = playlistVideoTitles[playlistpos];
  1117.         }
  1118.         else {
  1119.             playlistpos = 0;
  1120.             ytid = playlistVideoIDs[0];
  1121.             ytTitle = playlistVideoTitles[0];
  1122.         }
  1123.         vid.loop = false;
  1124.         vid.onended = function() {
  1125.             PLAYLIST_LOADING = true; nextPlaylist(); return;
  1126.         };
  1127.         document.title = "YT playlist: " + ytPlaylistTitle + " | " + ytTitle;
  1128.         GETvid(); return;
  1129.     }
  1130.     function playlistMenuLoad() {
  1131.         playlistVideoTitles.forEach(function(u, i) {
  1132.             playlistMenuEntries = document.createElement("li");
  1133.             playlistMenuEntries.addEventListener("click", function(e){
  1134.                 if (CUSTOM_PLAYLIST_EDIT_MODE === "ADD") {if (customPlaylistArray.indexOf(this.getAttribute("ytid")) === -1) {this.style.textDecoration = "underline dashed skyblue"; customPlaylistArray.push(this.getAttribute("ytid"));}}
  1135.                 else if (CUSTOM_PLAYLIST_EDIT_MODE === "DEL") {if (customPlaylistArray.indexOf(this.getAttribute("ytid")) !== -1) {this.style.textDecoration = ""; i = customPlaylistArray.indexOf(this.getAttribute("ytid")); customPlaylistArray.splice(i, 1);}}
  1136.                 else if (e.altKey) {
  1137.                     if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + this.getAttribute("ytid"), "_blank"); return;}
  1138.                     else {window.location.href = "https://www.youtube.com/watch?v=" + this.getAttribute("ytid"); return;}
  1139.                 }
  1140.                 else if (this.getAttribute("ytid") === ytid) {return;}
  1141.                 else if (PLAYLIST_LOADING === false) {PLAYLIST_LOADING = true; prevVideo = false; vid.pause(); playlistpos = i; ytid = playlistVideoIDs[i]; clearInterval(ccInterval); ccDone = false; vid.style.display = "none"; vid.innerHTML = ''; ytcheck = false; descriptionDone = false; ytTitleDone = false; geocheck = false; muxcheck = false; lainPlaylistLoading(); GETvid(); return;}
  1142.             });
  1143.             playlistMenuEntries.setAttribute("class", "playlistEntries");
  1144.             playlistMenuEntries.setAttribute("ytid", playlistVideoIDs[i]);
  1145.             playlistMenuEntries.innerText = u;
  1146.             playlistMenu.appendChild(playlistMenuEntries);
  1147.         });
  1148.         playlistMenuEntries = document.getElementsByClassName("playlistEntries");
  1149.     }
  1150.     function playlistNoPlayable() {
  1151.         lainFail(); document.title = "Unplayable YT playlist: " + ytPlaylistTitle; alert("ERROR: No playable videos in playlist.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  1152.     }
  1153.     function GETmixpop() {
  1154.         if (GETattempts > 13.37) {lainBugReport(); return;}
  1155.         if (window.location.href.includes("list=RD") === true) {document.title = "Loading YT mix";}
  1156.         else {document.title = "Loading popular uploads playlist";}
  1157.         u = new Date();
  1158.         u = "1." + u.toISOString().substring(0, 10).replace(/[-]/g, "");
  1159.         if (window.location.href.includes("list=RD") === true) { // mix
  1160.             a = window.location.href.substring(0, 44) + window.location.href.match(/list=[^&]+/)[0] + "&radio_start=1&disable_polymer=1&bpctr=9999999999&hl=en";
  1161.         }
  1162.         else { // popular uploads
  1163.             a = window.location.href.substring(0, 44) + window.location.href.match(/list=[^&]+/)[0] + "&disable_polymer=1&bpctr=9999999999&hl=en";
  1164.         }
  1165.         if (geocheck === true) {a = a + "&proxy=1";}
  1166.         GM_xmlhttpRequest({
  1167.             method: "GET",
  1168.             url: a,
  1169.             headers: {
  1170.                 "X-YouTube-Client-Name": "1",
  1171.                 "X-YouTube-Client-Version": u,
  1172.                 "Accept-Language": "en"
  1173.             },
  1174.             onerror: function(e) {console.log("GET MIX FAIL #1"); GETattempts ++; GETmixpop(); return;},
  1175.             onload: function(xhrMixPop) {
  1176.                 if (xhrMixPop.status === 200) {
  1177.                     if (xhrMixPop.responseText.includes("The uploader has not made this video available in your country") === true || xhrMixPop.responseText.includes("This content is not available on this country domain") === true || xhrMixPop.responseText.includes("blocked it in your country on copyright grounds") === true) {geocheck = true; console.log("GET MIX REGION FAIL - RETRYING WITH PROXY"); GETattempts ++; GETmixpop(); return;} // check if region restricted
  1178.                     else if (xhrMixPop.responseText.includes("This video is not available") === true) {
  1179.                         lainFail();
  1180.                         alert("ERROR: This video can't be mixed due to not having any related videos available.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  1181.                         document.title = "Unmixable YT video";
  1182.                         return;
  1183.                     }
  1184.                     if (GETmixpopattempts < 7) { // regular
  1185.                         try {ytPlaylistTitle = xhrMixPop.responseText.match(/data-list-title=\"([^"]+)/)[1].replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/\\\//g, "/").replace(/\\/g, "\\");} // regular
  1186.                         catch(e) {console.log("PLAYLIST TITLE GRAB FAIL - RETRYING"); GETmixpopattempts ++; GETmixpop(); return;} // for random wrong responsetext
  1187.                     }
  1188.                     else if (GETmixpopattempts >= 7) { // alt for mix fail
  1189.                         try { // for videos without proper mix support
  1190.                             console.log("PLAYLIST TITLE GRAB FAIL - TRYING ALTERNATE METHOD"); ytTitle = xhrMixPop.responseText.match(/title\":\"([^"]+)/)[1].replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/\\\//g, "/").replace(/\\/g, "\\"); ytPlaylistTitle = "Mix - " + ytTitle; PLAYLIST_MIXPOP_ALT = true;
  1191.                         }
  1192.                         catch(e) { // for videos without related vids or mix support
  1193.                             lainFail();
  1194.                             alert("ERROR: This video can't be mixed due to not having any related videos available.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page.");
  1195.                             document.title = "Unmixable YT video";
  1196.                             return;
  1197.                         }
  1198.                     }
  1199.                     if (ytPlaylistTitle.includes("Popular uploads") === true && window.location.href.includes("list=PU") === true) { // add author name
  1200.                         u = xhrMixPop.responseText.match(/\"name\": \"([^"]+)/)[1];
  1201.                         ytPlaylistTitle = ytPlaylistTitle + " by " + u;
  1202.                         document.title = "Loading YT playlist: " + ytPlaylistTitle;
  1203.                     }
  1204.                     else {document.title = "Loading YT playlist: " + ytPlaylistTitle;}
  1205.                     function cleanUpMixPop(u, i, a) {
  1206.                         if (u.includes("data-video-id") === true) {u = u.slice(15);} // reg ytid
  1207.                         else if (u.includes("content-link") === true) {u = u.slice(18, 29);} // alt ytid
  1208.                         else if (u.includes("class=\"title\"") === true) {u = u.match(/class=\"title\" aria.+\s+(.+)/)[1].replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/\\\//g, "/").replace(/\\/g, "\\");} // alt title
  1209.                         else {u = u.slice(18).replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/\\\//g, "/").replace(/\\/g, "\\");}
  1210.                         a[i] = u;
  1211.                     }
  1212.                     if (PLAYLIST_MIXPOP_ALT === false) { // regular
  1213.                         playlistVideoIDs = xhrMixPop.responseText.match(/data-video-id=\"[^"]+/g); // grab ytids
  1214.                         playlistVideoIDs.forEach(cleanUpMixPop);
  1215.                         playlistVideoTitles = xhrMixPop.responseText.match(/data-video-title=\"[^"]+/g); // grab ytTitles
  1216.                         playlistVideoTitles.forEach(cleanUpMixPop);
  1217.                     }
  1218.                     else { // alt
  1219.                         playlistVideoIDs = xhrMixPop.responseText.match(/<a href=\"\/watch\?v=.{11}\" class=\" content-link/g); // grab ytids
  1220.                         playlistVideoIDs.forEach(cleanUpMixPop);
  1221.                         playlistVideoIDs.splice(0, 0, ytid);
  1222.                         playlistVideoTitles = xhrMixPop.responseText.match(/class=\"title\" aria.+\s+.+/g); // grab ytTitles
  1223.                         playlistVideoTitles.forEach(cleanUpMixPop);
  1224.                         playlistVideoTitles.splice(0, 0, ytTitle);
  1225.                     }
  1226.                     playlistMenuLoad(); playPlaylist(); return;
  1227.                 }
  1228.                 else {
  1229.                     console.log("GET MIX FAIL #2"); GETattempts ++; GETmixpop();
  1230.                     return;
  1231.                 }
  1232.             }
  1233.         });
  1234.     }
  1235.     function GETplaylist() {
  1236.         if (GETattempts > 13.37) {lainBugReport(); return;}
  1237.         u = new Date();
  1238.         u = "1." + u.toISOString().substring(0, 10).replace(/[-]/g, "");
  1239.         ytplid = window.location.href.match(/list=[^&]+/)[0];
  1240.         GM_xmlhttpRequest({
  1241.             method: "GET",
  1242.             url: "https://www.youtube.com/playlist?" + ytplid + "&disable_polymer=1&hl=en",
  1243.             headers: {
  1244.                 "X-YouTube-Client-Name": "1", // these two headers are needed for the buggy RD playlists
  1245.                 "X-YouTube-Client-Version": u,
  1246.                 "Accept-Language": "en"
  1247.             },
  1248.             onerror: function(e) {console.log("GET PLAYLIST FAIL #1"); GETattempts ++; GETplaylist(); return;},
  1249.             onload: function(xhrPlaylist) {
  1250.                 if (xhrPlaylist.status === 200) {
  1251.                     try {ytPlaylistTitle = xhrPlaylist.responseText.match(/pl-header-title.+\s+.+/)[0].match(/\s[ ]+.+/)[0].replace(/\s[ ]+/, "").replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/\\\//g, "/").replace(/\\/g, "\\");}
  1252.                     catch(e) {
  1253.                         if (window.location.href.includes("list=RD") === true || window.location.href.includes("list=PU") === true) { // mix & popular uploads
  1254.                             GETmixpop(); return;
  1255.                         }
  1256.                         else { // invalid ID
  1257.                             lainFail(); alert("ERROR: Faulty playlist ID.\nPROTIP: You can click on Lain-chan to get a random video instead.\nYou can also ALT click on Lain-chan to go back to the front page."); document.title = "Invalid YT playlist ID"; return;
  1258.                         }
  1259.                     }
  1260.                     if (ytPlaylistTitle.includes("Uploads from ") === false && window.location.href.includes("list=TL") === false) { // add author name
  1261.                         try {u = xhrPlaylist.responseText.match(/pl-header-details\"><li>([^<]+)/)[1];}
  1262.                         catch(e) {u = xhrPlaylist.responseText.match(/pl-header-details\"><li><[^>]+>([^<]+)/)[1];}
  1263.                         if (u.slice(0, 7) === "YouTube") {u = u.substring(8);}
  1264.                         ytPlaylistTitle = ytPlaylistTitle + " by " + u;
  1265.                         document.title = "Loading YT playlist: " + ytPlaylistTitle;
  1266.                     }
  1267.                     else {document.title = "Loading YT playlist: " + ytPlaylistTitle;}
  1268.                     function cleanUpPlaylists(u, i, a) {
  1269.                         if (u.includes("data-video-id") === true) {u = u.slice(15);}
  1270.                         else {u = u.slice(12).replace(/&#39;/g, "'").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/\\\//g, "/").replace(/\\/g, "\\");}
  1271.                         a[i] = u;
  1272.                     }
  1273.                     playlistVideoIDs = xhrPlaylist.responseText.match(/data-video-id=\"[^"]+/g); // grab ytids
  1274.                     playlistVideoIDs.forEach(cleanUpPlaylists);
  1275.                     playlistVideoTitles = xhrPlaylist.responseText.match(/data-title=\"[^"]+/g); // grab ytTitles
  1276.                     playlistVideoTitles.forEach(cleanUpPlaylists);
  1277.                     if (xhrPlaylist.responseText.match(/Requires payment to watch/g) !== null) {playlistpaid = xhrPlaylist.responseText.match(/Requires payment to watch/g);} // checking how many paid
  1278.                     function playlistLoadMore() {
  1279.                         if (GETattempts > 13.37) {lainBugReport(); return;}
  1280.                         playlistLoadMoreURL = playlistLoadMoreURL.replace(/\\u0026amp;/g, "&").replace(/&amp;/g, "&");
  1281.                         u = new Date();
  1282.                         u = "1." + u.toISOString().substring(0, 10).replace(/[-]/g, "");
  1283.                         GM_xmlhttpRequest({
  1284.                             method: "GET",
  1285.                             url: "https://www.youtube.com" + playlistLoadMoreURL,
  1286.                             headers: {
  1287.                                 "X-YouTube-Client-Name": "1", // these two headers are needed or we get don't get the JSON we want
  1288.                                 "X-YouTube-Client-Version": u,
  1289.                                 "Accept-Language": "en"
  1290.                             },
  1291.                             onerror: function(e) {console.log("PLAYLIST LOADMORE FAIL #1"); GETattempts ++; playlistLoadMore(); return;},
  1292.                             onload: function(xhrMorePlaylist) {
  1293.                                 if (xhrMorePlaylist.status === 200) {
  1294.                                     function cleanUpMorePlaylists(u, i, a) {
  1295.                                         if (u.includes("data-video-id") === true) {u = u.substring(16);}
  1296.                                         else {u = u.substring(13).replace(/\\u0026#39;/g, "'").replace(/\\u0026quot;/g, '"').replace(/\\u0026amp;/g, "&");}
  1297.                                         u = u.replace(/[\\]/g, "");
  1298.                                         a[i] = u;
  1299.                                     }
  1300.                                     moreplaylistVideoIDs = xhrMorePlaylist.responseText.match(/data-video-id=\\"[^"]+/g); // grab more ytids
  1301.                                     moreplaylistVideoIDs.forEach(cleanUpMorePlaylists);
  1302.                                     moreplaylistVideoTitles = xhrMorePlaylist.responseText.match(/data-title=\\"[^"]+/g); // grab more ytTitles
  1303.                                     moreplaylistVideoTitles.forEach(cleanUpMorePlaylists);
  1304.                                     playlistVideoIDs = playlistVideoIDs.concat(moreplaylistVideoIDs); // add into main ytid array
  1305.                                     playlistVideoTitles = playlistVideoTitles.concat(moreplaylistVideoTitles); // add into main ytTitle array
  1306.                                     if (xhrMorePlaylist.responseText.match(/Requires payment to watch/g) !== null) {u = xhrMorePlaylist.responseText.match(/Requires payment to watch/g);}
  1307.                                     playlistpaid = playlistpaid.concat(u); // more paid check
  1308.                                     if (xhrMorePlaylist.responseText.match(/\/browse_ajax?[^"]+/) !== null) {playlistLoadMoreURL = xhrMorePlaylist.responseText.match(/\/browse_ajax?[^"]+/)[0]; playlistLoadMoreURL = playlistLoadMoreURL.slice(0, -1); playlistLoadMore();}
  1309.                                     else if (playlistpaid.length === playlistVideoIDs.length) {playlistNoPlayable(); return;}
  1310.                                     else {playlistMenuLoad(); playPlaylist(); return;}
  1311.                                 }
  1312.                                 else {
  1313.                                     console.log("PLAYLIST LOADMORE FAIL #2"); GETattempts ++; playlistLoadMore();
  1314.                                     return;
  1315.                                 }
  1316.                             }
  1317.                         });
  1318.                     }
  1319.                     if (xhrPlaylist.responseText.match(/\/browse_ajax?[^"]+/) !== null && window.location.href.includes("list=RD") === false) {playlistLoadMoreURL = xhrPlaylist.responseText.match(/\/browse_ajax?[^"]+/)[0]; playlistLoadMore();}
  1320.                     else if (playlistpaid.length === playlistVideoIDs.length) {playlistNoPlayable(); return;}
  1321.                     else {
  1322.                         playlistMenuLoad();
  1323.                         playPlaylist(); return;
  1324.                     }
  1325.                 }
  1326.                 else {
  1327.                     console.log("GET PLAYLIST FAIL #2"); GETattempts ++; GETplaylist();
  1328.                     return;
  1329.                 }
  1330.             }
  1331.         });
  1332.     }
  1333.     /* end playlists */
  1334.     /* start favorites */
  1335.     function favoritesSetupVideos(u, i) {
  1336.         favoritesMenuEntries = document.createElement("li");
  1337.         favoritesMenuEntries.addEventListener("click", function(e){
  1338.             if (FAVORITES_REMOVE_MODE === true) {
  1339.                 a = this;
  1340.                 Promise.all([GM.getValue("favoriteVideoIDs"), GM.getValue("favoriteVideoTitles")]).then(function(values) {
  1341.                     favoritesVideoIDsArray = values[0]; favoritesVideoTitlesArray = values[1];
  1342.                     i = favoritesVideoIDsArray.indexOf(a.getAttribute("ytid")); favoritesVideoIDsArray.splice(i, 1); favoritesVideoTitlesArray.splice(i, 1); GM.setValue("favoriteVideoIDs", favoritesVideoIDsArray); GM.setValue("favoriteVideoTitles", favoritesVideoTitlesArray);
  1343.                     a.remove();
  1344.                 });
  1345.             }
  1346.             else if (CUSTOM_PLAYLIST_EDIT_MODE === "ADD") {if (customPlaylistArray.indexOf(this.getAttribute("ytid")) === -1) {this.style.textDecoration = "underline dashed skyblue"; customPlaylistArray.push(this.getAttribute("ytid"));}}
  1347.             else if (CUSTOM_PLAYLIST_EDIT_MODE === "DEL") {if (customPlaylistArray.indexOf(this.getAttribute("ytid")) !== -1) {this.style.textDecoration = ""; i = customPlaylistArray.indexOf(this.getAttribute("ytid")); customPlaylistArray.splice(i, 1);}}
  1348.             else {if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + this.getAttribute("ytid"), "_blank");} else {if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {lainLeave();} window.location.href = "https://www.youtube.com/watch?v=" + this.getAttribute("ytid");}}
  1349.         });
  1350.         favoritesMenuEntries.setAttribute("class", "favoritesEntries");
  1351.         favoritesMenuEntries.setAttribute("ytid", u);
  1352.         favoritesMenuEntries.innerText = favoritesVideoTitlesArray[i];
  1353.         favoritesVideoMenu.appendChild(favoritesMenuEntries);
  1354.     }
  1355.     function favoritesSetupChannels(u, i) {
  1356.         favoritesMenuEntries = document.createElement("li");
  1357.         favoritesMenuEntries.addEventListener("click", function(e){
  1358.             if (FAVORITES_REMOVE_MODE === true) {
  1359.                 a = this;
  1360.                 Promise.all([GM.getValue("favoriteChannelIDs"), GM.getValue("favoriteChannelAuthors")]).then(function(values) {
  1361.                     favoritesChannelIDsArray = values[0]; favoritesChannelAuthorsArray = values[1];
  1362.                     i = favoritesChannelIDsArray.indexOf(a.getAttribute("channelid")); favoritesChannelIDsArray.splice(i, 1); favoritesChannelAuthorsArray.splice(i, 1); GM.setValue("favoriteChannelIDs", favoritesChannelIDsArray); GM.setValue("favoriteChannelAuthors", favoritesChannelAuthorsArray);
  1363.                     a.remove();
  1364.                 });
  1365.             }
  1366.             else {if (e.ctrlKey) {window.open("https://www.youtube.com/channel/" + this.getAttribute("channelid") + "/featured?disable_polymer=1&" + regionsetting, "_blank");} else {if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {lainLeave();} window.location.href = "https://www.youtube.com/channel/" + this.getAttribute("channelid") + "/featured?disable_polymer=1&" + regionsetting;}}
  1367.         });
  1368.         favoritesMenuEntries.setAttribute("class", "favoritesEntries");
  1369.         favoritesMenuEntries.setAttribute("channelid", u);
  1370.         favoritesMenuEntries.innerText = favoritesChannelAuthorsArray[i];
  1371.         favoritesChannelMenu.appendChild(favoritesMenuEntries);
  1372.     }
  1373.     function favoritesSetupPlaylists(u, i) {
  1374.         favoritesMenuEntries = document.createElement("li");
  1375.         favoritesMenuEntries.addEventListener("click", function(e){
  1376.             if (FAVORITES_REMOVE_MODE === true) {
  1377.                 a = this;
  1378.                 Promise.all([GM.getValue("favoritePlaylistIDs"), GM.getValue("favoritePlaylistTitles")]).then(function(values) {
  1379.                     favoritesPlaylistIDsArray = values[0]; favoritesPlaylistTitlesArray = values[1];
  1380.                     i = favoritesPlaylistIDsArray.indexOf(a.getAttribute("playlistid")); favoritesPlaylistIDsArray.splice(i, 1); favoritesPlaylistTitlesArray.splice(i, 1); GM.setValue("favoritePlaylistIDs", favoritesPlaylistIDsArray); GM.setValue("favoritePlaylistTitles", favoritesPlaylistTitlesArray);
  1381.                     a.remove();
  1382.                 });
  1383.             }
  1384.             else {
  1385.                 if (e.altKey && this.getAttribute("playlistid").includes("/watch") === false) {
  1386.                     if (e.ctrlKey) {window.open("https://www.youtube.com/playlist?" + this.getAttribute("playlistid") + "&disable_polymer=1&" + regionsetting, "_blank");} // open playlist in new tab
  1387.                     else {window.location.href = "https://www.youtube.com/playlist?" + this.getAttribute("playlistid") + "&disable_polymer=1&" + regionsetting;} // open playlist
  1388.                 }
  1389.                 else if (e.ctrlKey) {if (this.getAttribute("playlistid").includes("/watch") === true) {window.open(this.getAttribute("playlistid"), "_blank");} else {window.open("https://www.youtube.com/watch?v=playlistYes&" + this.getAttribute("playlistid"), "_blank");}} // play in new tab
  1390.                 else {if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {lainLeave();} if (this.getAttribute("playlistid").includes("/watch") === true) {window.location.href = this.getAttribute("playlistid");} else {window.location.href = "https://www.youtube.com/watch?v=playlistYes&" + this.getAttribute("playlistid");}} // play regular
  1391.             }
  1392.         });
  1393.         favoritesMenuEntries.setAttribute("class", "favoritesEntries");
  1394.         favoritesMenuEntries.setAttribute("playlistid", u);
  1395.         favoritesMenuEntries.innerText = favoritesPlaylistTitlesArray[i];
  1396.         favoritesPlaylistMenu.appendChild(favoritesMenuEntries);
  1397.     }
  1398.     function favoritesMenuLoad() {
  1399.         Promise.all([GM.getValue("favoriteVideoIDs"), GM.getValue("favoriteVideoTitles")]).then(function(values) {
  1400.             if (values[0] !== undefined && values[0].length > 0) {
  1401.                 favoritesVideoIDsArray = values[0];
  1402.                 favoritesVideoTitlesArray = values[1];
  1403.                 favoritesVideoIDsArray.forEach(function (u, i) {favoritesSetupVideos(u, i);});
  1404.             }
  1405.         });
  1406.         Promise.all([GM.getValue("favoriteChannelIDs"), GM.getValue("favoriteChannelAuthors")]).then(function(values) {
  1407.             if (values[0] !== undefined && values[0].length > 0) {
  1408.                 favoritesChannelIDsArray = values[0];
  1409.                 favoritesChannelAuthorsArray = values[1];
  1410.                 favoritesChannelIDsArray.forEach(function (u, i) {favoritesSetupChannels(u, i);});
  1411.             }
  1412.         });
  1413.         Promise.all([GM.getValue("favoritePlaylistIDs"), GM.getValue("favoritePlaylistTitles")]).then(function(values) {
  1414.             if (values[0] !== undefined && values[0].length > 0) {
  1415.                 favoritesPlaylistIDsArray = values[0];
  1416.                 favoritesPlaylistTitlesArray = values[1];
  1417.                 favoritesPlaylistIDsArray.forEach(function (u, i) {favoritesSetupPlaylists(u, i);});
  1418.             }
  1419.         });
  1420.     }
  1421.     /* end favorites */
  1422.     /* misc functions start */
  1423.     function GOTOdivMenuPos() { // goto scroll positions
  1424.         if (descriptionMenu.style.display !== "none") {
  1425.             divMenu.scrollTop = divMenuDescPos;
  1426.         }
  1427.         else if (playlistMenu.style.display !== "none") {
  1428.             divMenu.scrollTop = divMenuPlaylistPos;
  1429.         }
  1430.         else if (favoritesVideoMenu.style.display !== "none") {
  1431.             divMenu.scrollTop = divMenuFavVidPos;
  1432.         }
  1433.         else if (favoritesPlaylistMenu.style.display !== "none") {
  1434.             divMenu.scrollTop = divMenuFavPlaylistPos;
  1435.         }
  1436.         else {
  1437.             divMenu.scrollTop = divMenuFavChanPos;
  1438.         }
  1439.     }
  1440.     function downloadClosedCaptions() {
  1441.         if (ccDone === true) {
  1442.             ccSRTinfo = "To download closed captions in .srt format input the number of the desired closed captions track         "; // spaces added to nowrap
  1443.             ccSRTurls = [];
  1444.             Array.from(vid.getElementsByTagName("track")).forEach(function(u, i){
  1445.                 ccSRTinfo = ccSRTinfo + "\n" + (i + 1) + " - " + u.label;
  1446.                 ccSRTurls.push(u.src);
  1447.             });
  1448.             ccDone = false;
  1449.         }
  1450.         ccSRT = prompt(ccSRTinfo);
  1451.         if (ccSRT === null || ccSRT === undefined || ccSRT === "" || ccSRT.match(/[^ ]+/) === null) {if (ccSRT === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  1452.         else if (ccSRT !== undefined || ccSRT !== null || ccSRT !== "") {
  1453.             ccSRT = parseInt(ccSRT);
  1454.             if (isNaN(ccSRT) === true || ccSRT <= 0 || ccSRT > ccSRTurls.length) {
  1455.                 alert("ERROR: Faulty input"); return;
  1456.             }
  1457.             else {
  1458.                 /* convert vtt2srt start */
  1459.                 ccSRT = ccSRTurls[ccSRT - 1];
  1460.                 GM_xmlhttpRequest({
  1461.                     method: "GET",
  1462.                     url: ccSRT,
  1463.                     headers: {"Accept-Language": "en"},
  1464.                     onerror: function(e) {alert("ERROR: Closed captions conversion failed - try again."); return;},
  1465.                     onload: function(xhrccSRT) {
  1466.                         ccSRT = xhrccSRT.responseText;
  1467.                         /* start fix up */
  1468.                         ccSRT = ccSRT.replace(/WEBVTT\s\s/, "1\n").replace(/ line:\d+%.+/g, "").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
  1469.                         if (ccSRT.match(/\n\n/g) !== null) { // in case of there only being 1 line of text
  1470.                             Array.from(ccSRT.match(/\n\n/g)).forEach(function(u, i){
  1471.                                 ccSRT = ccSRT.replace(ccSRT.slice(ccSRT.search(u), ccSRT.search(u) + 2), "\n:\n:" + (i + 2) + "\n:");
  1472.                             });
  1473.                         }
  1474.                         ccSRT = ccSRT.replace(/\n:/g, "\n");
  1475.                         /* end fix up */
  1476.                         ccSRT = new Blob([ccSRT], {type : "text/plain"});
  1477.                         ccSRT = URL.createObjectURL(ccSRT);
  1478.                         u = document.createElement("a"); // GM_download doesn't work with blobs or base64 URLs so this workaround is used instead
  1479.                         u.setAttribute("href", ccSRT);
  1480.                         u.setAttribute("download", ytTitle.replace(/[\\\/:*"<>|?\.]+/g, "") + ".srt");
  1481.                         u.style.display = "none";
  1482.                         document.getElementsByTagName("html")[0].appendChild(u);
  1483.                         u.click();
  1484.                         document.getElementsByTagName("html")[0].removeChild(u);
  1485.                     }
  1486.                 });
  1487.                 /* convert vtt2srt end */
  1488.             }
  1489.         }
  1490.     }
  1491.     function showLoadCustomPlaylistsMenu(e) {
  1492.         GM.getValue("customPlaylists").then(function(customPlaylistsValue) {
  1493.             if (customPlaylistsValue === undefined || customPlaylistsValue.length === 0) {alert("ERROR: No saved custom playlists"); return;}
  1494.             else {
  1495.                 a = customPlaylistsValue;
  1496.                 a.forEach(function(u, i){
  1497.                     if (i === 0) {a = (i + 1) + " - " + decodeURIComponent(u.match(/Custom\+playlist%3A\+.+/)[0]).replace("Custom+playlist:+", "Custom playlist: ");}
  1498.                     else {a = a + "\n" + (i + 1) + " - " + decodeURIComponent(u.match(/Custom\+playlist%3A\+.+/)[0]).replace("Custom+playlist:+", "Custom playlist: ");}
  1499.                 });
  1500.                 i = prompt("Input the number of the saved custom playlist you wish to load and generate         \n" + a);
  1501.                 if (i === null || i === undefined || i === "" || i.match(/[^ ]+/) === null) {if (i === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  1502.                 else if (i !== undefined || i !== null || i !== "") {
  1503.                     i = parseInt(i);
  1504.                     if (isNaN(i) === true || i <= 0 || i > customPlaylistsValue.length) {alert("ERROR: Faulty input");}
  1505.                     else if (isNaN(i) === true || i > 0 || i < customPlaylistsValue.length) {
  1506.                         if (e.ctrlKey && e.key !== "Delete") {window.open(customPlaylistsValue[i - 1], "_blank");}
  1507.                         else {window.location.href = customPlaylistsValue[i - 1];}
  1508.                     }
  1509.                 }
  1510.             }
  1511.         });
  1512.     }
  1513.     function setupDownload() {
  1514.         if (vid.src.includes("mime%3Dvideo%2Fwebm") === true || vid.src.includes("mime=video/webm") === true) {
  1515.             filetype = ".webm";
  1516.         }
  1517.         else {
  1518.             filetype = ".mp4";
  1519.         }
  1520.         document.getElementsByTagName("body")[0].style = "";
  1521.         lainchan.style = "position: fixed; right: 0; bottom: 0; width: 15%; padding-bottom: 25.5%; cursor: pointer; background-repeat: no-repeat; background-position: bottom center; background-size: contain;";
  1522.         lainchan.style.backgroundImage = "url(\"" + resource_img_lain_smile + "\")"; // ignore warning - is in FuckJewTubeResources.js
  1523.         if (VID_HAS_CC === true) {lainchan.title = "Click to download video\nALT click to go back to the front page\nCTRL click to download closed captions";}
  1524.         else {lainchan.title = "Click to download video\nALT click to go back to the front page";}
  1525.         lainchan.addEventListener("click", function(e){
  1526.             if (e.altKey) {
  1527.                 if (e.ctrlKey) {window.open("https://www.youtube.com/?disable_polymer=1", "_blank");}
  1528.                 else {window.location.href = "https://www.youtube.com/?disable_polymer=1";}
  1529.             }
  1530.             else if (e.ctrlKey && VID_HAS_CC === true) {
  1531.                 downloadClosedCaptions();
  1532.             }
  1533.             else {GM_download(vid.src, ytTitle.replace(/[\\\/:*"<>|?\.]+/g, "") + filetype);}
  1534.         });
  1535.     }
  1536.     function setupHotkeys() {
  1537.         document.getElementsByTagName("html")[0].addEventListener("keydown", function(e) {
  1538.             if (e.key === "F1" || e.key == "Escape" || (e.ctrlKey && e.key == "Enter" && window.location.href !== "https://www.youtube.com/?disable_polymer=1" && window.location.href !== "https://www.youtube.com/") || e.key == "Delete" || (e.altKey && e.key === "PageUp") || (e.altKey && e.key === "PageDown")) {e.preventDefault();} // disable default behaviour for all pages
  1539.             else if (favoritesplaylistMenuShow === true && (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "PageDown" || e.key === "PageUp" || (e.ctrlKey && e.key === "ArrowDown") || (e.ctrlKey && e.key === "ArrowUp"))) {e.preventDefault();} // disable default behaviour for scrolling
  1540.             else if ((window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) && (e.key === "F4" || e.key === "Insert" || e.key === "F2" || e.key === "F3" || (e.ctrlKey && e.key === "s") || (e.ctrlKey && e.key === "S") || e.key === "PageDown" || e.key === "PageUp" || e.key === "Tab") || (e.altKey && e.key === "Enter")) {e.preventDefault();} // disable default behaviour for watch page/livestream
  1541.             else {return;} // if not hotkey skip rest
  1542.             /* start scrolling in FJT menu */
  1543.             if (favoritesplaylistMenuShow === true) {
  1544.                 if (divMenu.scrollTop < divMenu.scrollTopMax) {
  1545.                     if (e.ctrlKey && e.key === "ArrowDown") {divMenu.scrollTop = divMenu.scrollTopMax; return;} // scroll bot
  1546.                     else if (e.key === "PageDown") {divMenu.scrollTop = divMenu.scrollTop + (window.innerHeight * 0.65); return;} // pgdn
  1547.                     else if (e.key === "ArrowDown" && divMenu.scrollTop < divMenu.scrollTopMax) {divMenu.scrollTop = divMenu.scrollTop + 16; return;} // reg
  1548.                 }
  1549.                 else if (e.key === "PageDown" || e.key === "ArrowDown") {return;} // disable next vid
  1550.                 if (divMenu.scrollTop > 0) {
  1551.                     if (e.ctrlKey && e.key === "ArrowUp") {divMenu.scrollTop = 0; return;} // scroll top
  1552.                     else if (e.key === "PageUp") {divMenu.scrollTop = divMenu.scrollTop - (window.innerHeight * 0.65); return;} //pgup
  1553.                     else if (e.key === "ArrowUp") {divMenu.scrollTop = divMenu.scrollTop - 16; return;} // reg
  1554.                 }
  1555.                 else if (e.key === "PageUp" || e.key === "ArrowUp") {return;} // disable prev vid
  1556.             }
  1557.             /* end scrolling in FJT menu */
  1558.             if (e.key === "F1") {alert("- Universal Hotkeys -\nF1: Display hotkey list\nESC: Toggle FuckJewTube menu\nDELETE: Display load custom playlist menu\nCTRL + ENTER: Back to front page\nALT + PageUp: Get random video\nALT + PageDown: Get random YouTube mix\n\n- Video Page Hotkeys -\nF2: Favorite video\nF3: Favorite channel\nF4: Favorite playlist\nTAB: Cycle between FuckJewTube menus\nINSERT: Toggle video description\nCTRL + S: Download video\nCTRL + SHIFT + S: Download closed captions\nPageUp: Previous video in playlist\nPageDown: Next video in playlist\nALT + ENTER: Generate YouTube mix from current video\n\n- Other Notes -\nThe Up/Down arrows, PageUp and PageDown are used for scrolling in the FuckJewTube menu.\nHold CTRL + Up/Down arrow to go to the top or bottom of the FuckJewTube menu.\nCTRL clicking buttons that will redirect you in the FuckJewTube menu opens them in a new tab instead.         \nALT clicking in the playlist menu plays the video with playlist mode disabled.\nALT clicking on favorited playlists or the playlist button opens the playlist page.\nALT can be combined with CTRL to open in a new tab as well.");} // help
  1559.             else if (e.key === "Escape") {btn_favoritesplaylist.click();} // toggle FJT menu
  1560.             else if (e.key === "Delete") {showLoadCustomPlaylistsMenu(e);} // show custom playlist menu
  1561.             else if (e.ctrlKey && e.key === "Enter" && window.location.href !== "https://www.youtube.com/?disable_polymer=1" && window.location.href !== "https://www.youtube.com/") {window.location.href = "https://www.youtube.com/?disable_polymer=1";} // front page
  1562.             else if (e.altKey && e.key === "PageUp") {GETrandomvid("hk_random");} // random vid
  1563.             else if (e.altKey && e.key === "PageDown") {GETrandomvid("hk_mix");} // random vid
  1564.             if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {
  1565.                 if (e.key === "F4" && VID_PLAYLIST_MODE === true) {fav_btn_addPlaylist.click();} // fav playlist
  1566.                 else if (e.altKey && e.key === "Enter") {mix_btn.click();} // mix
  1567.                 else if (e.key === "Tab") { // cycle FJT menu
  1568.                     if (favoritesplaylistMenuShow === false) {btn_favoritesplaylist.click();} // display FJT menu if not shown
  1569.                     if (descriptionMenu.style.display === "") {fp_btn_favorites.click();} // desc to fav
  1570.                     else if (favoritesVideoMenu.style.display === "") {fav_btn_channels.click();} // fav vid to fav chan
  1571.                     else if (favoritesChannelMenu.style.display === "") {fav_btn_playlists.click();} // fav chan to fav pl
  1572.                     else if (favoritesPlaylistMenu.style.display === "") {
  1573.                         if (VID_PLAYLIST_MODE === true) {fp_btn_playlist.click();} // fav pl to playlist
  1574.                         else {fp_btn_description.click();} // fav pl to desc
  1575.                     }
  1576.                     else if (playlistMenu.style.display === "" && VID_PLAYLIST_MODE === true) {fp_btn_description.click();} // playlist to desc
  1577.                 }
  1578.                 else if (e.key === "Insert") {if (favoritesplaylistMenuShow === false || descriptionMenu.style.display === "") {btn_favoritesplaylist.click();} fp_btn_description.click();} // show description
  1579.                 else if (PLAYLIST_LOADING === false) {
  1580.                     if (window.location.href.includes("youtube.com/watch") === true) {
  1581.                         if (e.ctrlKey && e.key === "s") {GM_download(vid.src, ytTitle.replace(/[\\\/:*"<>|?\.]+/g, "") + filetype);} // download video
  1582.                         else if (e.ctrlKey && e.key === "S" && VID_HAS_CC === true) {downloadClosedCaptions();} // download captions
  1583.                         else if (e.key === "PageDown" && VID_PLAYLIST_MODE === true) {pl_btn_nextVid.click();} // next vid
  1584.                         else if (e.key === "PageUp" && VID_PLAYLIST_MODE === true) {pl_btn_prevVid.click();} // prev vid
  1585.                     }
  1586.                     if (e.key === "F2") {fav_btn_addVideo.click();} // fav video
  1587.                     else if (e.key === "F3") {fav_btn_addChannel.click();} // fav channel
  1588.                 }
  1589.             }
  1590.         });
  1591.     }
  1592.     /* misc functions end */
  1593.     function setupUI() {
  1594.         if (window.location.href.includes("youtube.com/watch") === true) {setupDownload();}
  1595.         setupHotkeys();
  1596.         /* buttons area start */
  1597.         btn_area.style.display = "";
  1598.         btn_area.style.backgroundImage = "url(\"" + resource_img_bg2 + "\")"; // ignore warning - is in FuckJewTubeResources.js
  1599.         btn_area.style.border = "3px double";
  1600.         btn_area.style.borderRadius = "3px";
  1601.         /* buttons area end */
  1602.         /* favsplaylist menu start */
  1603.         divMenu.onscroll = function() { // store scroll positions
  1604.             if (descriptionMenu.style.display !== "none") {
  1605.                 divMenuDescPos = divMenu.scrollTop;
  1606.             }
  1607.             else if (playlistMenu.style.display !== "none") {
  1608.                 divMenuPlaylistPos = divMenu.scrollTop;
  1609.             }
  1610.             else if (favoritesVideoMenu.style.display !== "none") {
  1611.                 divMenuFavVidPos = divMenu.scrollTop;
  1612.             }
  1613.             else if (favoritesPlaylistMenu.style.display !== "none") {
  1614.                 divMenuFavPlaylistPos = divMenu.scrollTop;
  1615.             }
  1616.             else {
  1617.                 divMenuFavChanPos = divMenu.scrollTop;
  1618.             }
  1619.         };
  1620.         /* start show reset functions */
  1621.         function showCustomPlaylistButtons() {
  1622.             if (customPlaylist_btn_add.style.display === "none") {
  1623.                 CUSTOM_PLAYLIST_EDIT_MODE = "OFF";
  1624.                 if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {
  1625.                     customPlaylist_btn_play.style = "position: absolute; left: 32px; top: 0; color: #888; font-size: 18px;";
  1626.                     customPlaylist_btn_add.style = "position: absolute; left: 52px; top: -5px; color: #888; font-size: 24px; font-weight: bold;";
  1627.                     customPlaylist_btn_del.style = "position: absolute; left: 77px; top: -5px; color: #888; font-size: 24px; font-weight: bold;";
  1628.                 }
  1629.                 else {
  1630.                     customPlaylist_btn_play.style = "position: absolute; left: 8px; top: 0; color: #888; font-size: 18px;";
  1631.                     customPlaylist_btn_add.style = "position: absolute; left: 28px; top: -5px; color: #888; font-size: 24px; font-weight: bold;";
  1632.                     customPlaylist_btn_del.style = "position: absolute; left: 53px; top: -5px; color: #888; font-size: 24px; font-weight: bold;";
  1633.                 }
  1634.             }
  1635.             else {return;}
  1636.         }
  1637.         function resetCustomPlaylistButtons() {
  1638.             CUSTOM_PLAYLIST_EDIT_MODE = "OFF";
  1639.             if (favoritesVideoMenu.style.display === "none" && playlistMenu.style.display === "none") {
  1640.                 customPlaylist_btn_add.style = "display: none";
  1641.                 customPlaylist_btn_add.title = "Turn on custom playlist add mode";
  1642.                 customPlaylist_btn_del.style = "display: none";
  1643.                 customPlaylist_btn_del.title = "Turn on custom playlist removal mode";
  1644.             }
  1645.             else {
  1646.                 customPlaylist_btn_add.title = "Turn on custom playlist add mode";
  1647.                 customPlaylist_btn_del.title = "Turn on custom playlist removal mode";
  1648.                 customPlaylist_btn_add.style.color = "#888";
  1649.                 customPlaylist_btn_del.style.color = "#888";
  1650.             }
  1651.         }
  1652.         function resetRemovalMode() {
  1653.             FAVORITES_REMOVE_MODE = false;
  1654.             fav_btn_removeMode.title = "Turn on removal mode"; fav_btn_removeMode.style.color = "#888"; fav_btn_removeMode.style.fontWeight = ""; fav_btn_removeMode.style.textShadow = "";
  1655.         }
  1656.         /* end show reset functions */
  1657.         btn_favoritesplaylist.style = "position: fixed; left: 5.5px; bottom: 26px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 24px; cursor: pointer; z-index: -1;";
  1658.         btn_favoritesplaylist.addEventListener("click", function(){
  1659.             if (favoritesplaylistMenuShow === false) {
  1660.                 favoritesplaylistMenuShow = true;
  1661.                 favoritesplaylistMenuBox.style.display = "";
  1662.             }
  1663.             else {
  1664.                 favoritesplaylistMenuShow = false;
  1665.                 favoritesplaylistMenuBox.style.display = "none";
  1666.                 resetRemovalMode();
  1667.                 resetCustomPlaylistButtons();
  1668.             }
  1669.             if (divMenu.scrollTopMax > 0) { // goto last scroll pos
  1670.                 GOTOdivMenuPos();
  1671.             }
  1672.         });
  1673.         favoritesplaylistMenuBox.style.backgroundImage = "url(\"" + resource_img_bg2 + "\")"; // ignore warning - is in FuckJewTubeResources.js
  1674.         fp_btn_exit.style = "position: absolute; right: 5px; top: -5px; color: #888; font-size: 24px;";
  1675.         fp_btn_exit.addEventListener("click", function(){btn_favoritesplaylist.click();});
  1676.         fav_btn_addVideo.addEventListener("click", function(){
  1677.             Promise.all([GM.getValue("favoriteVideoIDs"), GM.getValue("favoriteVideoTitles")]).then(function(values) {
  1678.                 favoritesVideoIDsArray = values[0];
  1679.                 favoritesVideoTitlesArray = values[1];
  1680.                 if (favoritesVideoIDsArray.indexOf(ytid) === -1 && PLAYLIST_LOADING === false) {
  1681.                     favoritesVideoIDsArray.push(ytid);
  1682.                     favoritesVideoTitlesArray.push(ytTitle);
  1683.                     GM.setValue("favoriteVideoIDs", favoritesVideoIDsArray);
  1684.                     GM.setValue("favoriteVideoTitles", favoritesVideoTitlesArray);
  1685.                     favoritesSetupVideos(ytid, favoritesVideoIDsArray.length - 1);
  1686.                     alert("The following video has been favorited.\n" + ytTitle);
  1687.                 }
  1688.                 else {alert("The following video is already in your favorites.\n" + ytTitle); return;}
  1689.             });
  1690.         });
  1691.         fav_btn_addChannel.addEventListener("click", function(){
  1692.             Promise.all([GM.getValue("favoriteChannelIDs"), GM.getValue("favoriteChannelAuthors")]).then(function(values) {
  1693.                 favoritesChannelIDsArray = values[0];
  1694.                 favoritesChannelAuthorsArray = values[1];
  1695.                 if (favoritesChannelIDsArray.indexOf(channelid) === -1 && PLAYLIST_LOADING === false) {
  1696.                     favoritesChannelIDsArray.push(channelid);
  1697.                     favoritesChannelAuthorsArray.push(channelauthor);
  1698.                     GM.setValue("favoriteChannelIDs", favoritesChannelIDsArray);
  1699.                     GM.setValue("favoriteChannelAuthors", favoritesChannelAuthorsArray);
  1700.                     favoritesSetupChannels(channelid, favoritesChannelIDsArray.length - 1);
  1701.                     alert("The following channel has been favorited.\n" + channelauthor);
  1702.                 }
  1703.                 else {alert("The following channel is already in your favorites.\n" + channelauthor); return;}
  1704.             });
  1705.         });
  1706.         if (VID_PLAYLIST_MODE === true || window.location.href.includes("/playlist?list") === true) {
  1707.             if ((window.location.href.match(/list=RD[^&]{12}/) === null && window.location.href.includes("list=RD") === true) || window.location.href.includes("list=PU") === true) {PLAYLIST_IS_MIXPOP = true;}
  1708.             if (window.location.href.includes("/playlist?list") === true) {
  1709.                 playlistid = window.location.href.match(/list=[^&]+/)[0];
  1710.                 ytPlaylistTitle = document.getElementsByClassName("pl-header-title")[0].innerText;
  1711.                 if (window.location.href.includes("list=TL") === false) {ytPlaylistTitle = ytPlaylistTitle + " by " + channelauthor;}
  1712.             }
  1713.             else if (PLAYLIST_IS_MIXPOP === true) {
  1714.                 playlistid = window.location.href.substring(0, 44) + window.location.href.match(/list=[^&]+/)[0];
  1715.             }
  1716.             else {
  1717.                 playlistid = window.location.href.match(/list=[^&]+/)[0];
  1718.             }
  1719.             fav_btn_addPlaylist.addEventListener("click", function(){
  1720.                 Promise.all([GM.getValue("favoritePlaylistIDs"), GM.getValue("favoritePlaylistTitles")]).then(function(values) {
  1721.                     favoritesPlaylistIDsArray = values[0];
  1722.                     favoritesPlaylistTitlesArray = values[1];
  1723.                     if (favoritesPlaylistIDsArray.indexOf(playlistid) === -1) {
  1724.                         favoritesPlaylistIDsArray.push(playlistid);
  1725.                         if (playlistid.includes("list=TL") === true) {a = "TEMPORARY PLAYLIST | " + ytPlaylistTitle;}
  1726.                         else {a = ytPlaylistTitle;}
  1727.                         favoritesPlaylistTitlesArray.push(a);
  1728.                         GM.setValue("favoritePlaylistIDs", favoritesPlaylistIDsArray);
  1729.                         GM.setValue("favoritePlaylistTitles", favoritesPlaylistTitlesArray);
  1730.                         favoritesSetupPlaylists(playlistid, favoritesPlaylistIDsArray.length - 1);
  1731.                         if (playlistid.includes("list=TL") === true) {alert("The following playlist has been favorited.\n" + ytPlaylistTitle + "\nNOTE: This is a temporary playlist that gets automatically deleted by YouTube after circa 2 days.");}
  1732.                         else {alert("The following playlist has been favorited.\n" + ytPlaylistTitle);}
  1733.                     }
  1734.                     else {alert("The following playlist is already in your favorites.\n" + ytPlaylistTitle); return;}
  1735.                 });
  1736.             });
  1737.         }
  1738.         fav_btn_removeMode.addEventListener("click", function(){
  1739.             if (FAVORITES_REMOVE_MODE === false) {
  1740.                 FAVORITES_REMOVE_MODE = true;
  1741.                 fav_btn_removeMode.title = "Turn off removal mode"; fav_btn_removeMode.style.color = "#8c0000"; fav_btn_removeMode.style.fontWeight = "bold"; fav_btn_removeMode.style.textShadow = "-1px -1px 1px #880000, -1px -1px 1px #000, 1px 1px 1px #880000, 1px 1px 1px #000"; // fav removal mode
  1742.                 resetCustomPlaylistButtons();
  1743.             }
  1744.             else {
  1745.                 resetRemovalMode();
  1746.             }
  1747.         });
  1748.         customPlaylist_btn_add.addEventListener("click", function(){
  1749.             if (CUSTOM_PLAYLIST_EDIT_MODE === "OFF" || CUSTOM_PLAYLIST_EDIT_MODE === "DEL") {
  1750.                 CUSTOM_PLAYLIST_EDIT_MODE = "ADD";
  1751.                 customPlaylist_btn_add.title = "Turn off custom playlist add mode"; customPlaylist_btn_add.style.color = "skyblue"; // custompl add
  1752.                 customPlaylist_btn_del.title = "Turn on custom playlist removal mode"; customPlaylist_btn_del.style.color = "#888"; // custompl del
  1753.                 resetRemovalMode();
  1754.             }
  1755.             else {
  1756.                 resetCustomPlaylistButtons();
  1757.             }
  1758.         });
  1759.         customPlaylist_btn_del.addEventListener("click", function(){
  1760.             if (CUSTOM_PLAYLIST_EDIT_MODE === "OFF" || CUSTOM_PLAYLIST_EDIT_MODE === "ADD") {
  1761.                 CUSTOM_PLAYLIST_EDIT_MODE = "DEL";
  1762.                 customPlaylist_btn_del.title = "Turn off custom playlist removal mode"; customPlaylist_btn_del.style.color = "#8c0000"; // custompl del
  1763.                 customPlaylist_btn_add.title = "Turn on custom playlist add mode"; customPlaylist_btn_add.style.color = "#888"; // custompl add
  1764.                 resetRemovalMode();
  1765.             }
  1766.             else {
  1767.                 resetCustomPlaylistButtons();
  1768.             }
  1769.         });
  1770.         customPlaylist_btn_play.addEventListener("click", function(e){
  1771.             i = prompt("Input the number of the desired action\n1 - Generate and play custom playlist\n2 - Save custom playlist\n3 - Load and generate a saved custom playlist\n4 - Remove a saved custom playlist");
  1772.             if (i === null || i === undefined || i === "" || i.match(/[^ ]+/) === null) {if (i === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  1773.             else if (i !== undefined || i !== null || i !== "") {
  1774.                 i = parseInt(i);
  1775.                 if (isNaN(i) === true || i <= 0 || i > 4) {alert("ERROR: Faulty input");}
  1776.                 else if (i === 1) { // generate and play
  1777.                     if (customPlaylistArray.length === 0) {alert("ERROR: No videos added to custom playlist"); return;} // check if empty
  1778.                     else {
  1779.                         i = prompt("Input the name of your custom playlist");
  1780.                         if (i === null || i === undefined || i === "" || i.match(/[^ ]+/) === null) {if (i === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  1781.                         else if (i !== undefined || i !== null || i !== "") {
  1782.                             if (e.ctrlKey) {window.open("https://www.youtube.com/watch_videos?more_url=&type=0&feature=c4-overview&video_ids=" + customPlaylistArray.join("%2C") + "&title=Custom+playlist%3A+" + i, "_blank");}
  1783.                             else {window.location.href = "https://www.youtube.com/watch_videos?more_url=&type=0&feature=c4-overview&video_ids=" + customPlaylistArray.join("%2C") + "&title=Custom+playlist%3A+" + i;}
  1784.                         }
  1785.                     }
  1786.                 }
  1787.                 else if (i === 2) { // save
  1788.                     if (customPlaylistArray.length === 0) {alert("ERROR: No videos added to custom playlist"); return;} // check if empty
  1789.                     else {
  1790.                         i = prompt("Input the name of your custom playlist");
  1791.                         if (i === null || i === undefined || i === "" || i.match(/[^ ]+/) === null) {if (i === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  1792.                         else if (i !== undefined || i !== null || i !== "") {
  1793.                             GM.getValue("customPlaylists").then(function(customPlaylistsValue) {
  1794.                                 if (customPlaylistsValue === undefined) {a = [];}
  1795.                                 else {a = customPlaylistsValue;}
  1796.                                 a.push("https://www.youtube.com/watch_videos?more_url=&type=0&feature=c4-overview&video_ids=" + customPlaylistArray.join("%2C") + "&title=Custom+playlist%3A+" + i);
  1797.                                 GM.setValue("customPlaylists", a);
  1798.                                 alert("Custom playlist: " + i + " has been saved.");
  1799.                             });
  1800.                         }
  1801.                     }
  1802.                 }
  1803.                 else if (i === 3) { // load
  1804.                     showLoadCustomPlaylistsMenu(e);
  1805.                 }
  1806.                 else if (i === 4) { // remove
  1807.                     GM.getValue("customPlaylists").then(function(customPlaylistsValue) {
  1808.                         if (customPlaylistsValue === undefined || customPlaylistsValue.length === 0) {alert("ERROR: No saved custom playlists"); return;}
  1809.                         else {
  1810.                             a = customPlaylistsValue;
  1811.                             a.forEach(function(u, i){
  1812.                                 if (i === 0) {a = (i + 1) + " - " + decodeURIComponent(u.match(/Custom\+playlist%3A\+.+/)[0]).replace("Custom+playlist:+", "Custom playlist: ");}
  1813.                                 else {a = a + "\n" + (i + 1) + " - " + decodeURIComponent(u.match(/Custom\+playlist%3A\+.+/)[0]).replace("Custom+playlist:+", "Custom playlist: ");}
  1814.                             });
  1815.                             i = prompt("Input the number of the saved custom playlist you wish to remove         \n" + a);
  1816.                             if (i === null || i === undefined || i === "" || i.match(/[^ ]+/) === null) {if (i === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  1817.                             else if (i !== undefined || i !== null || i !== "") {
  1818.                                 i = parseInt(i);
  1819.                                 if (isNaN(i) === true || i <= 0 || i > customPlaylistsValue.length) {alert("ERROR: Faulty input");}
  1820.                                 else if (isNaN(i) === true || i > 0 || i < customPlaylistsValue.length) {
  1821.                                     a = customPlaylistsValue;
  1822.                                     u = customPlaylistsValue[i - 1].match(/Custom\+playlist%3A\+.+/)[0];
  1823.                                     a.splice(i - 1, 1);
  1824.                                     GM.setValue("customPlaylists", a);
  1825.                                     alert(decodeURIComponent(u).replace("Custom+playlist:+", "Custom playlist: ") + " has been removed.");
  1826.                                 }
  1827.                             }
  1828.                         }
  1829.                     });
  1830.                 }
  1831.             }
  1832.         });
  1833.         fav_btn_videos.addEventListener("click", function(){
  1834.             if (favoritesVideoMenu.style.display === "none") {
  1835.                 favoritesVideoMenu.style.display = "";
  1836.                 favoritesChannelMenu.style.display = "none";
  1837.                 favoritesPlaylistMenu.style.display = "none";
  1838.                 descriptionMenu.style.display = "none";
  1839.                 fav_btn_videos.style.color = "skyblue";
  1840.                 fav_btn_channels.style.color = "#888";
  1841.                 fav_btn_playlists.style.color = "#888";
  1842.                 fp_btn_description.style.color = "#888";
  1843.                 showCustomPlaylistButtons();
  1844.                 GOTOdivMenuPos();
  1845.             }
  1846.             else {return;}
  1847.         });
  1848.         fav_btn_channels.addEventListener("click", function(){
  1849.             if (favoritesChannelMenu.style.display === "none") {
  1850.                 favoritesVideoMenu.style.display = "none";
  1851.                 favoritesChannelMenu.style.display = "";
  1852.                 favoritesPlaylistMenu.style.display = "none";
  1853.                 descriptionMenu.style.display = "none";
  1854.                 fav_btn_videos.style.color = "#888";
  1855.                 fav_btn_channels.style.color = "skyblue";
  1856.                 fav_btn_playlists.style.color = "#888";
  1857.                 fp_btn_description.style.color = "#888";
  1858.                 resetCustomPlaylistButtons();
  1859.                 GOTOdivMenuPos();
  1860.             }
  1861.             else {return;}
  1862.         });
  1863.         fav_btn_playlists.addEventListener("click", function(){
  1864.             if (favoritesPlaylistMenu.style.display === "none") {
  1865.                 favoritesVideoMenu.style.display = "none";
  1866.                 favoritesChannelMenu.style.display = "none";
  1867.                 favoritesPlaylistMenu.style.display = "";
  1868.                 descriptionMenu.style.display = "none";
  1869.                 fav_btn_videos.style.color = "#888";
  1870.                 fav_btn_channels.style.color = "#888";
  1871.                 fav_btn_playlists.style.color = "skyblue";
  1872.                 fp_btn_description.style.color = "#888";
  1873.                 resetCustomPlaylistButtons();
  1874.                 GOTOdivMenuPos();
  1875.             }
  1876.             else {return;}
  1877.         });
  1878.         if (window.location.href.includes("youtube.com/watch") === true || window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === true) {
  1879.             fp_btn_description.style = "position: absolute; left: 5px; top: -2px; color: #888; font-size: 20px;";
  1880.             fp_btn_description.addEventListener("click", function(){
  1881.                 if (descriptionMenu.style.display === "none") {
  1882.                     favoritesVideoMenu.style.display = "none";
  1883.                     favoritesChannelMenu.style.display = "none";
  1884.                     favoritesPlaylistMenu.style.display = "none";
  1885.                     playlistMenu.style.display = "none";
  1886.                     descriptionMenu.style.display = "";
  1887.                     fp_btn_description.style.color = "skyblue";
  1888.                     fp_btn_playlist.style.color = "#888";
  1889.                     fp_btn_favorites.style.color = "#888";
  1890.                     fav_btn_addVideo.style = "display: none";
  1891.                     fav_btn_addChannel.style = "display: none";
  1892.                     fav_btn_addPlaylist.style = "display: none";
  1893.                     fav_btn_removeMode.style = "display: none";
  1894.                     fav_btn_videos.style = "display: none";
  1895.                     fav_btn_channels.style = "display: none";
  1896.                     fav_btn_playlists.style = "display: none";
  1897.                     pl_btn_nextVid.style = "display: none";
  1898.                     pl_btn_prevVid.style = "display: none";
  1899.                     pl_btn_shuffle.style = "display: none";
  1900.                     pl_btn_reverse.style = "display: none";
  1901.                     playlistCurrent.style = "display: none";
  1902.                     resetCustomPlaylistButtons();
  1903.                     GOTOdivMenuPos();
  1904.                 }
  1905.                 else {return;}
  1906.             });
  1907.         }
  1908.         if (window.location.href.includes("youtube.com/watch") === true) { // mix button
  1909.             mix_btn.style = "position: absolute; right: 29px; top: -9px; color: #888; font-size: 30px;";
  1910.             mix_btn.addEventListener("click", function(e){
  1911.                 if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + ytid + "&list=RD" + ytid, "_blank");} // new tab
  1912.                 else {window.location.href = "https://www.youtube.com/watch?v=" + ytid + "&list=RD" + ytid;} // mix
  1913.             });
  1914.         }
  1915.         function showPlaylistMenu() {
  1916.             favoritesVideoMenu.style.display = "none";
  1917.             favoritesChannelMenu.style.display = "none";
  1918.             favoritesPlaylistMenu.style.display = "none";
  1919.             playlistMenu.style.display = "";
  1920.             descriptionMenu.style.display = "none";
  1921.             pl_btn_nextVid.style = "position: absolute; left: 55%; top: -2px; color: #888; font-size: 24px;";
  1922.             pl_btn_prevVid.style = "position: absolute; left: 43%; top: -2px; color: #888; font-size: 24px;";
  1923.             pl_btn_shuffle.style = "position: absolute; left: 47%; top: -2px; color: #888; font-size: 24px;";
  1924.             pl_btn_reverse.style = "position: absolute; left: 51%; top: -2px; color: #888; font-size: 24px;";
  1925.             playlistCurrent.style = "position: relative; left: 8px; top: 30px; color: skyblue; font-size: 14px; text-shadow: 1.337px 1.337px teal; margin-bottom: -16px;";
  1926.             fav_btn_addVideo.style = "display: none";
  1927.             fav_btn_addChannel.style = "display: none";
  1928.             fav_btn_addPlaylist.style = "display: none";
  1929.             fav_btn_removeMode.style = "display: none";
  1930.             fav_btn_videos.style = "display: none";
  1931.             fav_btn_channels.style = "display: none";
  1932.             fav_btn_playlists.style = "display: none";
  1933.             showCustomPlaylistButtons();
  1934.             GOTOdivMenuPos();
  1935.         }
  1936.         function showFavoritesMenu() {
  1937.             FAVORITES_REMOVE_MODE = false;
  1938.             fav_btn_removeMode.title = "Turn on removal mode";
  1939.             playlistMenu.style.display = "none";
  1940.             favoritesVideoMenu.style.display = "";
  1941.             descriptionMenu.style.display = "none";
  1942.             if (window.location.href.includes("youtube.com/watch") === false && window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === false) {
  1943.                 fav_btn_removeMode.style = "position: absolute; left: 48%; color: #888; font-size: 22px;";
  1944.             }
  1945.             else {
  1946.                 if (VID_PLAYLIST_MODE === true || window.location.href.includes("/playlist?list") === true) {
  1947.                     fav_btn_addVideo.style = "position: absolute; left: 42%; top: -2px; color: #888; font-size: 24px;";
  1948.                     fav_btn_addChannel.style = "position: absolute; left: 46%; color: #888; font-size: 22px;";
  1949.                     fav_btn_addPlaylist.style = "position: absolute; left: 50%; color: #888; font-size: 24px; top: -2px;";
  1950.                     fav_btn_removeMode.style = "position: absolute; left: 54%; color: #888; font-size: 22px;";
  1951.                 }
  1952.                 else {
  1953.                     fav_btn_addVideo.style = "position: absolute; left: 44%; top: -2px; color: #888; font-size: 24px;";
  1954.                     fav_btn_addChannel.style = "position: absolute; left: 48%; color: #888; font-size: 22px;";
  1955.                     fav_btn_removeMode.style = "position: absolute; left: 52%; color: #888; font-size: 22px;";
  1956.                 }
  1957.             }
  1958.             fav_btn_videos.style = "z-index: 9001; position: absolute; left: 38%; top: 25px; color: skyblue; font-size: 14px; font-weight: bold; margin-top: 5px;";
  1959.             fav_btn_channels.style = "z-index: 9001; position: absolute; left: 46%; top: 25px; color: #888; font-size: 14px; font-weight: bold; margin-top: 5px;";
  1960.             fav_btn_playlists.style = "z-index: 9001; position: absolute; left: 55.50%; top: 25px; color: #888; font-size: 14px; font-weight: bold; margin-top: 5px;";
  1961.             showCustomPlaylistButtons();
  1962.             pl_btn_nextVid.style = "display: none";
  1963.             pl_btn_prevVid.style = "display: none";
  1964.             pl_btn_shuffle.style = "display: none";
  1965.             pl_btn_reverse.style = "display: none";
  1966.             playlistCurrent.style = "display: none";
  1967.             GOTOdivMenuPos();
  1968.         }
  1969.         fp_btn_favorites.style = "position: absolute; left: 25%; color: skyblue; font-size: 20px; font-weight: bold; margin-top: 5px;";
  1970.         fp_btn_favorites.addEventListener("click", function(){
  1971.             if (fp_btn_favorites.style.color !== "skyblue") {
  1972.                 fp_btn_playlist.style.color = "#888";
  1973.                 fp_btn_favorites.style.color = "skyblue";
  1974.                 fp_btn_description.style.color = "#888";
  1975.                 showFavoritesMenu();
  1976.             }
  1977.             else {return;}
  1978.         });
  1979.         if (VID_PLAYLIST_MODE === true) {
  1980.             showPlaylistMenu();
  1981.             fp_btn_favorites.style.color = "#888";
  1982.             fp_btn_playlist.style = "position: absolute; right: 25%; color: skyblue; font-size: 20px; font-weight: bold; margin-top: 5px;";
  1983.             fp_btn_playlist.addEventListener("click", function(e){
  1984.                 if (e.altKey && PLAYLIST_IS_MIXPOP === false) {
  1985.                     if (e.ctrlKey) {window.open("https://www.youtube.com/playlist?" + playlistid + "&disable_polymer=1&" + regionsetting, "_blank");} // open playlist in new tab
  1986.                     else {window.location.href = "https://www.youtube.com/playlist?" + playlistid + "&disable_polymer=1&" + regionsetting;} // open playlist
  1987.                 }
  1988.                 else if (fp_btn_playlist.style.color !== "skyblue") {
  1989.                     fp_btn_playlist.style.color = "skyblue";
  1990.                     fp_btn_favorites.style.color = "#888";
  1991.                     fp_btn_description.style.color = "#888";
  1992.                     showPlaylistMenu();
  1993.                 }
  1994.                 else {return;}
  1995.             });
  1996.             pl_btn_nextVid.addEventListener("click", function(){
  1997.                 if (PLAYLIST_LOADING === false) {
  1998.                     PLAYLIST_LOADING = true; vid.pause(); nextPlaylist(); return;
  1999.                 }
  2000.                 else {return;}
  2001.             });
  2002.             pl_btn_prevVid.addEventListener("click", function(){
  2003.                 if (PLAYLIST_LOADING === false) {
  2004.                     PLAYLIST_LOADING = true; vid.pause(); prevPlaylist(); return;
  2005.                 }
  2006.                 else {return;}
  2007.             });
  2008.             pl_btn_shuffle.addEventListener("click", function(){
  2009.                 if (PLAYLIST_SHUFFLE_MODE === false) {PLAYLIST_SHUFFLE_MODE = true; pl_btn_shuffle.innerText = "⇄"; pl_btn_shuffle.title = "Unshuffle playlist";}
  2010.                 else {PLAYLIST_SHUFFLE_MODE = false; pl_btn_shuffle.innerText = "⇉"; pl_btn_shuffle.title = "Shuffle playlist";}
  2011.             });
  2012.             pl_btn_reverse.addEventListener("click", function(){
  2013.                 if (PLAYLIST_REVERSE_MODE === false) {PLAYLIST_REVERSE_MODE = true; pl_btn_reverse.innerText = "↫"; pl_btn_reverse.title = "Turn off reverse mode";}
  2014.                 else {PLAYLIST_REVERSE_MODE = false; pl_btn_reverse.innerText = "↬"; pl_btn_reverse.title = "Turn on reverse mode";}
  2015.             });
  2016.         }
  2017.         else {showFavoritesMenu();}
  2018.         favoritesMenuLoad();
  2019.         /* favsplaylist menu end */
  2020.         /* search start */
  2021.         btn_searchGo.style = "position: fixed; left: 28.5px; bottom: 0px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 24px; cursor: pointer; z-index: -2;";
  2022.         btn_searchGo.addEventListener("click", function(e){searchVid(e);});
  2023.         /* search end */
  2024.         /* random start */
  2025.         btn_randomVid.style = "position: fixed; left: 28.5px; bottom: 50px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 24px; cursor: pointer;";
  2026.         btn_randomVid.addEventListener("click", function(e){GETrandomvid(e);});
  2027.         /* random end */
  2028.         /* random mode + live sync start */
  2029.         btn_randomMode.style = "position: fixed; left: 27.5px; bottom: 25px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 24px; cursor: pointer; z-index: -1;";
  2030.         if (window.location.href.includes("googlevideo.com/videoplayback?(%C2%B4%EF%BD%A1%E2%80%A2%20%CF%89%20%E2%80%A2%EF%BD%A1`)") === false) { // disable on livestreams
  2031.             GM.getValue("videoRandomMode").then(function(videoRandomModeValue) {
  2032.                 if (videoRandomModeValue === "true") {
  2033.                     vid.loop = false;
  2034.                     vid.onended = function(e) {GETrandomvid(e);};
  2035.                     btn_randomMode.innerText = "⇄";
  2036.                     btn_randomMode.title = "Turn off random video playlist mode";
  2037.                     GM.setValue("videoRandomMode", "true");
  2038.                     VID_RANDOM_MODE = true;
  2039.                 }
  2040.             });
  2041.             btn_randomMode.addEventListener("click", function(){
  2042.                 if (VID_RANDOM_MODE === false) {
  2043.                     vid.loop = false;
  2044.                     vid.onended = function(e) {GETrandomvid(e);};
  2045.                     btn_randomMode.innerText = "⇄";
  2046.                     btn_randomMode.title = "Turn off random video playlist mode";
  2047.                     GM.setValue("videoRandomMode", "true");
  2048.                     VID_RANDOM_MODE = true;
  2049.                 }
  2050.                 else {
  2051.                     vid.loop = true;
  2052.                     if (VID_PLAYLIST_MODE === true) {
  2053.                         vid.loop = false;
  2054.                         vid.onended = function() {
  2055.                             PLAYLIST_LOADING = true; nextPlaylist(); return;
  2056.                         };
  2057.                     }
  2058.                     else {vid.onended = function() {};}
  2059.                     btn_randomMode.innerText = "⥁";
  2060.                     btn_randomMode.title = "Turn on random video playlist mode";
  2061.                     GM.setValue("videoRandomMode", "false");
  2062.                     VID_RANDOM_MODE = false;
  2063.                 }
  2064.             });
  2065.         }
  2066.         else { // livestream resync
  2067.             btn_randomMode.title = "Re-sync livestream";
  2068.             btn_randomMode.style.fontSize = "22px";
  2069.             btn_randomMode.style.bottom = "26px";
  2070.             btn_randomMode.innerText = "◷";
  2071.             btn_randomMode.addEventListener("click", function(){
  2072.                 if (vid.currentTime < hls.liveSyncPosition) {
  2073.                     vid.fastSeek(hls.liveSyncPosition);
  2074.                 }
  2075.             });
  2076.         }
  2077.         /* random mode + live sync end */
  2078.         /* channel start */
  2079.         btn_channelGo.style = "position: fixed; left: 5.5px; bottom: 51px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 22px; cursor: pointer;";
  2080.         btn_channelGo.title = "Go to the channel of " + channelauthor;
  2081.         btn_channelGo.addEventListener("click", function(e){
  2082.             if (e.ctrlKey) {window.open("https://www.youtube.com/channel/" + channelid + "/featured?disable_polymer=1&" + regionsetting, "_blank");}
  2083.             else {
  2084.                 lainLeave();
  2085.                 window.location.href = "https://www.youtube.com/channel/" + channelid + "/featured?disable_polymer=1&" + regionsetting;
  2086.             }
  2087.         });
  2088.         /* channel end */
  2089.         /* theatremode start */
  2090.         btn_theatreMode.style = "position: fixed; left: 3.5px; bottom: -1px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 24px; cursor: pointer; z-index: -2;";
  2091.         GM.getValue("videoTheatreMode").then(function(theatreModeValue) {
  2092.             if (theatreModeValue === "true") {
  2093.                 vid.style.maxWidth = "100%"; vid.style.height = "100%";
  2094.                 btn_theatreMode.innerText = "-";
  2095.                 btn_area.onmouseout = function() {btn_area.style.animation = "fadeout ease-in-out 333ms forwards";};
  2096.                 btn_area.onmouseover = function() {btn_area.style.animation = "fadein ease-in-out 333ms forwards";};
  2097.                 btn_area.style.opacity = "0";
  2098.                 if (PLAYLIST_LOADING === false) {lainchan.hidden = true;}
  2099.                 GM.setValue("videoTheatreMode", "true");
  2100.                 VID_THEATRE_MODE = true;
  2101.             }
  2102.         });
  2103.         btn_theatreMode.addEventListener("click", function(){
  2104.             if (VID_THEATRE_MODE === false) {
  2105.                 vid.style.maxWidth = "100%"; vid.style.height = "100%";
  2106.                 btn_theatreMode.innerText = "-";
  2107.                 btn_area.onmouseout = function() {btn_area.style.animation = "fadeout ease-in-out 333ms forwards";};
  2108.                 btn_area.onmouseover = function() {btn_area.style.animation = "fadein ease-in-out 333ms forwards";};
  2109.                 if (PLAYLIST_LOADING === false) {lainchan.hidden = true;}
  2110.                 GM.setValue("videoTheatreMode", "true");
  2111.                 VID_THEATRE_MODE = true;
  2112.             }
  2113.             else {
  2114.                 vid.style.maxWidth = "66%"; vid.style.height = "";
  2115.                 btn_theatreMode.innerText = "+";
  2116.                 btn_area.onmouseout = "";
  2117.                 btn_area.onmouseover = "";
  2118.                 if (PLAYLIST_LOADING === false) {lainchan.hidden = false;}
  2119.                 btn_area.style.opacity = "";
  2120.                 GM.setValue("videoTheatreMode", "false");
  2121.                 VID_THEATRE_MODE = false;
  2122.             }
  2123.         });
  2124.         /* theatremode end */
  2125.         /* vid volume start */
  2126.         GM.getValue("videoVolume").then(function(videoVolumeValue) {
  2127.             if (videoVolumeValue === undefined) {
  2128.                 GM.setValue("videoVolume", 1.0);
  2129.             }
  2130.             else {
  2131.                 vid.volume = videoVolumeValue;
  2132.             }
  2133.         });
  2134.         window.onunload = function(){GM.setValue("videoVolume", vid.volume);};
  2135.         /* vid volume end */
  2136.     }
  2137.     /* global functions end */
  2138.     /* INIT END */
  2139.     /* front page start */
  2140.     if (window.location.href === "https://www.youtube.com/" || window.location.href === "https://www.youtube.com/?disable_polymer=1") {
  2141.         lainInit();
  2142.         document.title = "YouTube - Front Page";
  2143.         setupUI();
  2144.         document.getElementsByTagName("style")[0].insertAdjacentHTML("beforeend", "#buttons_area {opacity: 1 !important; background-image: none !important; border: none !important;}");
  2145.         btn_channelGo.remove();
  2146.         btn_randomMode.remove();
  2147.         btn_theatreMode.remove();
  2148.         btn_randomVid.style = "position: fixed; right: 20%; top: 40%; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 64px; cursor: pointer;";
  2149.         btn_searchGo.style = "position: fixed; right: 25%; top: 40%; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 64px; cursor: pointer;";
  2150.         btn_favoritesplaylist.style = "position: fixed; right: 30.5%; top: 40%; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 64px; cursor: pointer;";
  2151.         btn_area.onmouseout = "";
  2152.         btn_area.onmouseover = "";
  2153.         /* start trending + region button */
  2154.         /* trending start */
  2155.         u = document.createElement("div");
  2156.         u.setAttribute("style", "position: absolute; right: 11.5%; top: 60%; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2157.         u.setAttribute("class", "btn");
  2158.         u.innerText = "BROWSE TRENDING VIDEOS";
  2159.         u.addEventListener("click", function(e){
  2160.             if (e.ctrlKey) {window.open("https://www.youtube.com/?disable_polymer=1&" + regionsetting, "_blank");}
  2161.             else {window.location.href = "https://www.youtube.com/?disable_polymer=1&" + regionsetting;}
  2162.         });
  2163.         document.getElementsByTagName("body")[0].appendChild(u);
  2164.         /* trending end */
  2165.         /* region start */
  2166.         u = document.createElement("div");
  2167.         u.setAttribute("style", "position: absolute; right: 12.25%; top: 70%; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2168.         u.setAttribute("class", "btn");
  2169.         u.innerText = "CHANGE REGION SETTING";
  2170.         regionNames.forEach(function(u, i){
  2171.             regionInfo = regionInfo + "\n" + (i + 1) + " - " + u;
  2172.         });
  2173.         u.addEventListener("click", function(e){
  2174.             i = prompt("Current region: " + regionNames[regionCodes.indexOf(regionsetting)] + "\n" + regionInfo);
  2175.             if (i === null || i === undefined || i === "" || i.match(/[^ ]+/) === null) {if (i === null) {return;} else {alert("ERROR: Faulty or no input"); return;}}
  2176.             else if (i !== undefined || i !== null || i !== "") {
  2177.                 i = parseInt(i);
  2178.                 if (i >= 9000) {window.location.href = "https://www.youtube.com/watch?v=eT7u8R2d8hc";}
  2179.                 else if (isNaN(i) === true || i <= 0 || i > regionNames.length) {alert("ERROR: Faulty input");}
  2180.                 else {GM.setValue("region", regionCodes[i - 1]); regionsetting = regionCodes[i - 1]; alert("Region set to " + regionNames[i - 1]);}
  2181.             }
  2182.         });
  2183.         document.getElementsByTagName("body")[0].appendChild(u);
  2184.         /* region end */
  2185.         /* end trending + region button */
  2186.         u = document.createElement("div"); u.setAttribute("style", "position: absolute; right: 5%; top: 80%; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 24px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic;"); u.innerText = "PROTIP: PRESS F1 TO DISPLAY THE HOTKEY LIST"; document.getElementsByTagName("body")[0].appendChild(u); // info about hotkeys
  2187.         u = document.createElement("div"); u.setAttribute("style", "position: absolute; right: 14%; top: 21%; color: skyblue; text-shadow: -1px -1px 1px teal, -1px -1px 1px skyblue, 1px 1px 1px teal, 1px 1px 1px skyblue; font-weight: bold; font-size: 46px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; text-align: center;"); u.innerHTML = "FuckJewTube<br><i style='font-size: 36px; position: relative; bottom: 16px; right: 3px;'>By anon for anon</i>"; document.getElementsByTagName("body")[0].appendChild(u); // title
  2188.     }
  2189.     /* front page end */
  2190.     /* start watch pages */
  2191.     if (window.location.href.includes("youtube.com/watch") === true) {
  2192.         /* init start */
  2193.         /* collect vidtime start */
  2194.         ccInterval = setInterval( function() {
  2195.             if (vid.paused === false && VID_ERROR === false && vidtime !== vid.currentTime) {
  2196.                 vidtime = vid.currentTime;
  2197.             }
  2198.         }, 1337);
  2199.         vid.onpause = function() {vidtime = vid.currentTime;};
  2200.         vid.onseeked = function() {vidtime = vid.currentTime;};
  2201.         /* collect vidtime end */
  2202.         lainInit();
  2203.         function setupVidOnPlaying() {
  2204.             vid.onplaying = function() {
  2205.                 vid.onplaying = function() {};
  2206.                 GETdescription();
  2207.                 GETattempts = 0;
  2208.                 VID_ERROR = false;
  2209.                 if (VID_PLAYLIST_MODE === true) {
  2210.                     document.title = "YT playlist: " + ytPlaylistTitle + " | " + ytTitle;
  2211.                     currentVideo = playlistMenuEntries[playlistpos];
  2212.                     currentVideo.id = "currentvid";
  2213.                     playlistCurrent.innerText = "Playing #" + (playlistpos + 1) + ": " + ytTitle;
  2214.                     lainPlaylistPlaying();
  2215.                     vid.onplaying = function () {
  2216.                         if (PLAYLIST_LOADING === true) {
  2217.                             PLAYLIST_LOADING = false;
  2218.                             lainPlaylistPlaying();
  2219.                             vid.style.display = "";
  2220.                             GETdescription();
  2221.                             divMenuDescPos = 0;
  2222.                             GOTOdivMenuPos();
  2223.                             currentVideo.id = "";
  2224.                             currentVideo = playlistMenuEntries[playlistpos];
  2225.                             currentVideo.id = "currentvid";
  2226.                             playlistCurrent.innerText = "Playing #" + (playlistpos + 1) + ": " + ytTitle;
  2227.                             GETattempts = 0;
  2228.                             VID_ERROR = false;
  2229.                             document.title = "YT playlist: " + ytPlaylistTitle + " | " + ytTitle;
  2230.                             btn_channelGo.title = "Go to the channel of " + channelauthor;
  2231.                             btn_channelGo.replaceWith(btn_channelGo.cloneNode(true));
  2232.                             btn_channelGo = document.getElementById("btn_channel");
  2233.                             btn_channelGo.addEventListener("click", function(e){
  2234.                                 if (e.ctrlKey) {window.open("https://www.youtube.com/channel/" + channelid + "/featured?disable_polymer=1&" + regionsetting, "_blank");}
  2235.                                 else {
  2236.                                     lainLeave();
  2237.                                     window.location.href = "https://www.youtube.com/channel/" + channelid + "/featured?disable_polymer=1&" + regionsetting;
  2238.                                 }
  2239.                             });
  2240.                         }
  2241.                     };
  2242.                 }
  2243.                 else {document.title = "YT video: " + ytTitle;}
  2244.                 if (lainSFX !== "") {
  2245.                     if (VID_PLAYLIST_MODE === true) {lainSFX.pause();}
  2246.                     else {lainSFX.remove();}
  2247.                 }
  2248.                 vid.style.display = "";
  2249.                 if (btn_area.style.display === "none") {setupUI();}
  2250.                 /* start time begin */
  2251.                 if (VID_PLAYLIST_MODE === false && window.location.href.match(/&t=(\d+)s/) !== null) {
  2252.                     i = parseInt(window.location.href.match(/&t=(\d+)s/)[1]);
  2253.                     if (i > 0) {vid.fastSeek(i);}
  2254.                 }
  2255.                 else if (VID_PLAYLIST_MODE === false && window.location.href.match(/&t=(\d+)m(\d+)s/) !== null) {
  2256.                     i = parseInt(window.location.href.match(/&t=(\d+)m(\d+)s/)[1]) * 60 + parseInt(window.location.href.match(/&t=(\d+)m(\d+)s/)[2]);
  2257.                     if (i > 0) {vid.fastSeek(i);}
  2258.                 }
  2259.                 /* start time end */
  2260.                 return;
  2261.             };
  2262.         }
  2263.         setupVidOnPlaying();
  2264.         vid.onerror = function() { // if src fails loading for some reason
  2265.             console.log("VIDEO PLAYER ERROR - RETRYING SAME URL"); setupVidOnPlaying();
  2266.             if (VID_ERROR === false) {vid.src = muxstream; VID_ERROR = true; vid.fastSeek(vidtime); if (VID_PLAYLIST_MODE === false) {document.title = "YT video: " + ytTitle;} else {document.title = "YT playlist: " + ytPlaylistTitle + " | " + ytTitle;}}
  2267.             else {console.log("VIDEO PLAYER ERROR - SAME URL FAILED - RELOADING"); GETvid();}
  2268.         };
  2269.         /* start playlists */
  2270.         if (window.location.href.includes("list=") === true) {
  2271.             VID_PLAYLIST_MODE = true;
  2272.             lainLoading();
  2273.             GETplaylist();
  2274.             return;
  2275.         }
  2276.         else {console.log("LOADING VIDEO INFO"); GETvid(); return;}
  2277.         /* end playlist */
  2278.         /* init end */
  2279.     }
  2280.     /* end watch pages */
  2281.     /* start non watch pages */
  2282.     if (window.location.href.includes("youtube.com/user") === true || window.location.href.includes("youtube.com/channel") === true || window.location.href.includes("youtube.com/playlist") === true || window.location.href.includes("youtube.com/results") === true || window.location.href.includes("youtube.com/?disable_polymer=1&gl=") === true || window.location.href.includes("youtube.com/feed/") === true) {
  2283.         /* region unblock start */
  2284.         if (regionUnblockArray.some(function(pattern){return window.location.href.includes(pattern);}) && window.location.href.includes("&proxy=1") === false) {
  2285.             window.location.href = window.location.href + "&proxy=1";
  2286.         }
  2287.         /* region unblock end */
  2288.         /* trending start */
  2289.         if (window.location.href.includes("disable_polymer=1&gl=") === true) {
  2290.             i = regionCodes.indexOf(window.location.href.slice(-5));
  2291.             if (window.location.href.includes("youtube.com/feed/trending") === true) {document.title = "Most trending videos in " + regionNames[i] + " - YouTube";}
  2292.             else if (window.location.href.includes("youtube.com/feed/guide_builder") === true) {document.title = "Most trending channels globally - YouTube";}
  2293.             else if (window.location.href.slice(0, -2) === "https://www.youtube.com/?disable_polymer=1&gl=") {document.title = "Trending videos in " + regionNames[i] + " - YouTube";}
  2294.         }
  2295.         /* trending end */
  2296.         window.onload = function() {
  2297.             /* error checking start */
  2298.             function channelErrorCheck() {
  2299.                 if (GETattempts > 13.37) {document.getElementsByTagName("html")[0].innerHTML = ""; lainInit(); lainFail(); return;}
  2300.                 GM_xmlhttpRequest({
  2301.                     method: "GET",
  2302.                     url: window.location.href + "&hl=en",
  2303.                     headers: {"Accept-Language": "en"},
  2304.                     onerror: function(e) {console.log("CHANNEL ERROR CHECK XHR FAILED"); GETattempts++; channelErrorCheck();},
  2305.                     onload: function(xhrChannelCheck) {
  2306.                         if (xhrChannelCheck.status === 200) {
  2307.                             if (xhrChannelCheck.responseText.includes("This channel is not available") === true || xhrChannelCheck.responseText.includes("An error occurred") === true) { // region locked or bugged
  2308.                                 if (window.location.href.includes("&proxy=1") === false) {window.location.href = window.location.href + "&proxy=1";}
  2309.                                 else {window.location.reload();}
  2310.                             }
  2311.                             else if (xhrChannelCheck.responseText.includes("This channel does not exist") === true) { // faulty id
  2312.                                 document.getElementsByTagName("html")[0].innerHTML = ""; lainInit(); lainFail(); return;
  2313.                             }
  2314.                             else {window.location.reload();} // random error that is not consistent
  2315.                         }
  2316.                         else {console.log("CHANNEL ERROR CHECK FAILED"); GETattempts++; channelErrorCheck();}
  2317.                     }
  2318.                 });
  2319.             }
  2320.             if ((window.location.href.includes("/user/") === true || window.location.href.includes("/channel/") === true) && window.location.href.includes("&proxy=1") === false) {
  2321.                 if (document.getElementById("browse-items-primary") !== null) {if (document.getElementById("browse-items-primary").innerText === "" && document.getElementsByClassName("branded-page-related-channels")[0] !== undefined) {window.location.href = window.location.href + "&proxy=1";} else if (document.getElementById("browse-items-primary").innerText === "" && document.getElementsByClassName("branded-page-related-channels")[0] === undefined) {document.getElementById("browse-items-primary").innerHTML = "<p style='margin-left: 15px;'>THIS FAGGOT HAS NO FEATURED CONTENT</p>"; FixUpNonWatchPages();} else {FixUpNonWatchPages();}} // proxy region restricted without error message
  2322.                 else if ((document.getElementsByClassName("channel-empty-message")[0] !== undefined || document.getElementsByClassName("yt-alert-error")[0] !== undefined) && window.location.href.includes("&proxy=1") === false) {channelErrorCheck();} // check for error xhr
  2323.                 else {FixUpNonWatchPages();} // extra
  2324.             }
  2325.             else if ((window.location.href.includes("/channel/") === true || window.location.href.includes("/user/") === true) && (document.getElementsByClassName("channel-empty-message")[0] !== undefined || document.getElementsByClassName("yt-alert-error")[0] !== undefined) && window.location.href.includes("&proxy=1") === true) { // proxy fail
  2326.                 if (document.getElementsByClassName("yt-alert-error")[0].className.includes("hid") === true) {FixUpNonWatchPages();}
  2327.                 else {
  2328.                     a = confirm("Proxying region restricted channel failed. Feel free to report it to so it can be added to the PAC script.\nPress OK to try proxying it with another random proxy.\nNOTE: You will need to retry random proxies for every page on the channel until it's added to the PAC script."); if (a === true) {window.location.reload();} else {FixUpNonWatchPages();}
  2329.                 }
  2330.             }
  2331.             else {FixUpNonWatchPages();}
  2332.             /* error checking end */
  2333.             function FixUpNonWatchPages() {
  2334.                 /* channel id + author start */
  2335.                 if (window.location.href.includes("/channel") === true || window.location.href.includes("/user") === true || window.location.href.includes("/playlist") === true) { // grab channel id + author
  2336.                     if (document.getElementsByClassName("appbar-nav-menu")[0] !== undefined) {if (document.getElementsByClassName("appbar-nav-menu")[0].getElementsByTagName("a")[0].href.includes("/feed/") === true) {u = "BAGU";}} // for buggy channels
  2337.                     if (u !== "BAGU" && document.getElementsByClassName("branded-page-header-title-link")[0] !== undefined) {
  2338.                         if (window.location.href.includes("/playlist?list") === true) {channelid = document.getElementsByTagName("html")[0].innerHTML.match(/\/channel\/([^/]+)\/playlists/)[1];}
  2339.                         else {
  2340.                             try {channelid = document.getElementsByClassName("branded-page-header-title-link")[0].href.match(/channel\/[^/]+/)[0].substring(8);}
  2341.                             catch(e) {channelid = document.getElementsByTagName("html")[0].innerHTML.match(/CHANNEL_ID', "[^"]+/)[0].substring(14);}
  2342.                         }
  2343.                         channelauthor = document.getElementsByClassName("branded-page-header-title-link")[0].title;
  2344.                     }
  2345.                     else if (u !== "BAGU" && document.getElementsByTagName("html")[0].innerHTML.match(/data-external-id=\"UC[^"]+/)[0] !== undefined && document.getElementsByClassName("pl-header-details")[0].getElementsByTagName("li")[0] !== undefined) { // for the buggy RD playlists
  2346.                         channelid = document.getElementsByTagName("html")[0].innerHTML.match(/data-external-id=\"UC[^"]+/)[0].substring(18);
  2347.                         channelauthor = document.getElementsByClassName("pl-header-details")[0].getElementsByTagName("li")[0].innerText;
  2348.                         if (channelauthor.slice(0, 7) === "YouTube") {channelauthor = channelauthor.substring(7);}
  2349.                     }
  2350.                 }
  2351.                 /* channel id + author end */
  2352.                 if (document.getElementsByClassName("video-thumb")[0] !== undefined) {
  2353.                     videoThumbnails = Array.from(document.getElementsByClassName("video-thumb")); // fix video thumbnails
  2354.                     videoThumbnails.forEach(loadVideoThumbnails);
  2355.                 }
  2356.                 /* fix links start */
  2357.                 if (document.getElementsByTagName("a")[0] !== undefined) {
  2358.                     Array.from(document.getElementsByTagName("a")).forEach(function(u) {
  2359.                         if (u.href.includes("/feed/trending") === true || u.href === "https://www.youtube.com/?disable_polymer=1") { // trending pages
  2360.                             if (u.href.includes("disable_polymer=1") === true) {u.href = u.href + "&" + regionsetting;}
  2361.                             else {u.href = u.href + "?disable_polymer=1&" + regionsetting;}
  2362.                         }
  2363.                         if (u.href.includes("disable_polymer=1") === false && u.href.includes("/watch") === false && u.href.includes("/redirect") === false) { // remove cancer
  2364.                             if (u.href.includes("/results") === true) {
  2365.                                 u.href = u.href + "&disable_polymer=1&" + regionsetting;
  2366.                             }
  2367.                             if (u.href.includes("/playlist?") === true) {
  2368.                                 u.href = u.href + "&disable_polymer=1&" + regionsetting;
  2369.                             }
  2370.                             if (u.href.includes("/channel") === true || u.href.includes("/user") === true) {
  2371.                                 if (u.href.includes("/featured") === false && u.href.includes("/videos") === false && u.href.includes("/playlist") === false && u.href.includes("/community") === false && u.href.includes("/discussion") === false && u.href.includes("/channels") === false && u.href.includes("/about") === false && u.href.includes("/feed") === false) {
  2372.                                     u.href = u.href + "/featured?disable_polymer=1&" + regionsetting;
  2373.                                 }
  2374.                                 else if (u.href.includes("?") === false) {u.href = u.href + "?disable_polymer=1&" + regionsetting;}
  2375.                                 else {u.href = u.href + "&disable_polymer=1&" + regionsetting;}
  2376.                             }
  2377.                         }
  2378.                         if (u.href.includes("/redirect") === true) { // remove datamining
  2379.                             u.href = decodeURIComponent(u.href.match(/q=[^&]+/)[0].substring(2));
  2380.                             if (u.href.includes("https://www.youtube.com") === true) {
  2381.                                 u.href = u.href.replace(/https:\/\/www\.youtube\.com\/[^/]+\/[^/]+\//, "http://");
  2382.                             }
  2383.                         }
  2384.                         if (u.href.includes("view_play_list?p=") === true) { // alt playlist URLs
  2385.                             u.href = u.href.replace("view_play_list?p=", "playlist?list=");
  2386.                             if (u.href.includes("disable_polymer=1") === false) {u.href = u.href + "&disable_polymer=1&" + regionsetting;}
  2387.                         }
  2388.                         if (u.href.match(/watch_videos.+title=[^&]+/) !== null && (window.location.href.includes("/channel/") === true || window.location.href.includes("/user/") === true)) { // activity playlist and other custom playlists on channel
  2389.                             u.href = u.href.replace(/title=[^&]+/, u.href.match(/title=[^&]+/)[0] + "+by+" + channelauthor);
  2390.                         }
  2391.                         if (u.href.includes("?sub_confirmation=1") === true) {
  2392.                             u.href = u.href.replace("?sub_confirmation=1", "");
  2393.                         }
  2394.                         if (u.href.includes("feed?disable_polymer=1") === true) {
  2395.                             u.href = u.href.replace("feed?disable_polymer=1", "featured?disable_polymer=1");
  2396.                         }
  2397.                         if (u.href.includes("disable_polymer=1") === true && u.href.includes("&gl=") === false) { // add region for pre-fixed links
  2398.                             u.href = u.href + "&" + regionsetting;
  2399.                         }
  2400.                         if (u.href.includes("disable_polymer=1") === true && u.href.includes("&proxy=1") === false && window.location.href.includes("&proxy=1") === true && (u.href.includes("/user/") === true || u.href.includes("/channel/") === true)) { // fix links for proxied
  2401.                             if (window.location.href.includes("/user/") === true) {
  2402.                                 if (u.href.includes(window.location.href.match(/\/user\/[^\\/]+/)[0]) === true) {u.href = u.href + "&proxy=1";}
  2403.                             }
  2404.                             else if (window.location.href.includes("/channel/") === true) {
  2405.                                 if (u.href.includes(window.location.href.match(/\/channel\/[^\\/]+/)[0]) === true) {u.href = u.href + "&proxy=1";}
  2406.                             }
  2407.                         }
  2408.                         if (u.href.includes("/gaming") === true) { // gaming genre channel
  2409.                             u.href = "https://www.youtube.com/channel/UCOpNcN46UbXVtpKMrmU4Abg/featured?disable_polymer=1&" + regionsetting;
  2410.                         }
  2411.                     });
  2412.                 }
  2413.                 /* fix links end */
  2414.                 /* init start */
  2415.                 lainInit();
  2416.                 setupUI();
  2417.                 btn_channelGo.remove();
  2418.                 btn_randomMode.remove();
  2419.                 btn_theatreMode.remove();
  2420.                 btn_randomVid.style = "position: fixed; left: 64px; bottom: -5px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 64px; cursor: pointer; user-select: none; -moz-user-select: none; -ms-user-select: none; -khtml-user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;";
  2421.                 btn_searchGo.style = "position: fixed; left: 5px; bottom: -5px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 64px; cursor: pointer; user-select: none; -moz-user-select: none; -ms-user-select: none; -khtml-user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;";
  2422.                 btn_favoritesplaylist.style = "position: fixed; left: 5px; bottom: 59px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 64px; cursor: pointer; user-select: none; -moz-user-select: none; -ms-user-select: none; -khtml-user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;";
  2423.                 btn_area.onmouseout = "";
  2424.                 btn_area.onmouseover = "";
  2425.                 if (window.location.href.includes("/channel") === true || window.location.href.includes("/user") === true || window.location.href.includes("/playlist") === true) {
  2426.                     if (channelid !== "" && channelauthor !== "") {
  2427.                         fav_btn_addChannel.style = "position: absolute; left: 46%; color: #888; font-size: 22px;";
  2428.                         fav_btn_removeMode.style = "position: absolute; left: 50%; color: #888; font-size: 22px;";
  2429.                     }
  2430.                 }
  2431.                 if (window.location.href.includes("/playlist?list") === true) {
  2432.                     fav_btn_addChannel.style = "position: absolute; left: 44%; color: #888; font-size: 22px;";
  2433.                     fav_btn_addPlaylist.style = "position: absolute; left: 48%; color: #888; font-size: 24px; top: -2px;";
  2434.                     fav_btn_removeMode.style = "position: absolute; left: 52%; color: #888; font-size: 22px;";
  2435.                 }
  2436.                 /* init end */
  2437.                 /* button start */
  2438.                 /* start channel related buttons */
  2439.                 if (channelid !== "" && channelauthor !== "") {
  2440.                     /* play all button + sorting start */
  2441.                     if (window.location.href.includes("/videos") === true && document.getElementById("channels-browse-content-grid") !== null && document.getElementsByClassName("yt-channel-title-autogenerated")[0] === undefined) {
  2442.                         /* start play all */
  2443.                         u = document.createElement("div");
  2444.                         if (document.getElementById("appbar-nav") === null) {
  2445.                             u.setAttribute("style", "position: absolute; left: 27%; top: 20px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2446.                         }
  2447.                         else {u.setAttribute("style", "position: absolute; left: 27%; top: 60px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");}
  2448.                         u.setAttribute("class", "btn");
  2449.                         u.innerText = "PLAY ALL";
  2450.                         ytid = document.getElementById("channels-browse-content-grid").getElementsByClassName("yt-uix-sessionlink")[0].href;
  2451.                         ytid = ytid.slice(32, 43);
  2452.                         if (window.location.href.includes("view=15") === true) { // liked videos
  2453.                             u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + ytid + "&list=LL" + channelid.substring(2), "_blank");} else {window.location.href = "https://www.youtube.com/watch?v=" + ytid + "&list=LL" + channelid.substring(2);}});
  2454.                             if (document.getElementById("appbar-nav") === null) {
  2455.                                 u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 20px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2456.                             }
  2457.                             else {
  2458.                                 u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 60px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2459.                             }
  2460.                         }
  2461.                         else { // user uploads
  2462.                             u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/watch?v=" + ytid + "&list=UU" + channelid.substring(2), "_blank");} else {window.location.href = "https://www.youtube.com/watch?v=" + ytid + "&list=UU" + channelid.substring(2);}});
  2463.                         }
  2464.                         document.getElementsByTagName("body")[0].appendChild(u);
  2465.                         /* end play all */
  2466.                         /* start sorting */
  2467.                         if (document.getElementsByClassName("subnav-sort-menu")[0] !== undefined) {
  2468.                             a = ["&sort=dd", "&sort=da", "&sort=p"];
  2469.                             i = ["NEWEST", "OLDEST", "VIEWS"];
  2470.                             a.forEach(function(type, index) {
  2471.                                 u = document.createElement("div");
  2472.                                 if (document.getElementById("appbar-nav") === null) {
  2473.                                     if (index === 0) {
  2474.                                         u.setAttribute("style", "position: absolute; left: 41%; top: 20px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2475.                                     }
  2476.                                     else if (index === 1) {
  2477.                                         u.setAttribute("style", "position: absolute; left: 52%; top: 20px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2478.                                     }
  2479.                                     else {
  2480.                                         u.setAttribute("style", "position: absolute; left: 63%; top: 20px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2481.                                     }
  2482.                                 }
  2483.                                 else {
  2484.                                     if (index === 0) {
  2485.                                         u.setAttribute("style", "position: absolute; left: 41%; top: 60px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2486.                                     }
  2487.                                     else if (index === 1) {
  2488.                                         u.setAttribute("style", "position: absolute; left: 52%; top: 60px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2489.                                     }
  2490.                                     else {
  2491.                                         u.setAttribute("style", "position: absolute; left: 63%; top: 60px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2492.                                     }
  2493.                                 }
  2494.                                 u.setAttribute("class", "btn");
  2495.                                 u.innerText = i[index];
  2496.                                 u.title = "Sort by " + i[index].toLowerCase();
  2497.                                 u.addEventListener("click", function(e){if (e.ctrlKey) {window.open(window.location.href.replace(/\?sort=[^&]+&/, "?").replace(/&sort=[^&]+/, "") + type, "_blank");} else {window.location.href = window.location.href.replace(/\?sort=[^&]+&/, "?").replace(/&sort=[^&]+/, "") + type;}});
  2498.                                 document.getElementsByTagName("body")[0].appendChild(u);
  2499.                             });
  2500.                         }
  2501.                         /* end sorting */
  2502.                     }
  2503.                     /* play all button + sorting end */
  2504.                     /* channel search button start */
  2505.                     if (window.location.href.includes("/search?query") === true && document.getElementById("browse-items-primary") !== null) {
  2506.                         u = document.createElement("div");
  2507.                         if (document.getElementById("appbar-nav") === null) {
  2508.                             u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 20px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2509.                         }
  2510.                         else {u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 60px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");}
  2511.                         u.setAttribute("class", "btn");
  2512.                         u.innerText = "SEARCH CHANNEL";
  2513.                         u.addEventListener("click", function(e){searchquery = prompt("Input search query for channel search\nNOTE: The only supported search tag is intitle:\"query\""); if (searchquery === null || searchquery === undefined || searchquery === "" || searchquery.match(/[^ ]+/) === null) {if (searchquery === null) {return;} else {alert("ERROR: Faulty or no input"); return;}} else if (searchquery !== undefined || searchquery !== null || searchquery !== "") {if (e.ctrlKey) {window.open("https://www.youtube.com/channel/" + channelid + "/search?query=" + encodeURIComponent(searchquery) + "&disable_polymer=1&" + regionsetting, "_blank");} else {window.location.href = "https://www.youtube.com/channel/" + channelid + "/search?query=" + encodeURIComponent(searchquery) + "&disable_polymer=1&" + regionsetting;}}});
  2514.                         document.getElementsByTagName("body")[0].appendChild(u);
  2515.                     }
  2516.                     /* channel search button end */
  2517.                     /* RSS button + search featured page start */
  2518.                     if (window.location.href.includes("/featured") === true && document.getElementsByClassName("yt-channel-title-autogenerated")[0] === undefined) {
  2519.                         /* RSS start */
  2520.                         u = document.createElement("div");
  2521.                         if (document.getElementById("appbar-nav") === null) {
  2522.                             u.setAttribute("style", "position: absolute; left: 38%; margin-right: -38%; transform: translate(-38%, 0); top: 8px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2523.                         }
  2524.                         else {u.setAttribute("style", "position: absolute; left: 38%; margin-right: -38%; transform: translate(-38%, 0); top: 48px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");}
  2525.                         u.setAttribute("class", "btn");
  2526.                         u.innerText = "RSS FEED";
  2527.                         u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/feeds/videos.xml?channel_id=" + channelid, "_blank");} else {window.location.href = "https://www.youtube.com/feeds/videos.xml?channel_id=" + channelid;}});
  2528.                         document.getElementsByTagName("body")[0].appendChild(u);
  2529.                         /* RSS end */
  2530.                         /* search start */
  2531.                         u = document.createElement("div");
  2532.                         if (document.getElementById("appbar-nav") === null) {
  2533.                             u.setAttribute("style", "position: absolute; left: 59.5%; margin-right: -59.5%; transform: translate(-59.5%, 0); top: 8px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2534.                         }
  2535.                         else {u.setAttribute("style", "position: absolute; left: 59.5%; margin-right: -59.5%; transform: translate(-59.5%, 0); top: 48px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");}
  2536.                         u.setAttribute("class", "btn");
  2537.                         u.innerText = "SEARCH CHANNEL";
  2538.                         u.addEventListener("click", function(e){searchquery = prompt("Input search query for channel search\nNOTE: The only supported search tag is intitle:\"query\""); if (searchquery === null || searchquery === undefined || searchquery === "" || searchquery.match(/[^ ]+/) === null) {if (searchquery === null) {return;} else {alert("ERROR: Faulty or no input"); return;}} else if (searchquery !== undefined || searchquery !== null || searchquery !== "") {if (e.ctrlKey) {window.open("https://www.youtube.com/channel/" + channelid + "/search?query=" + encodeURIComponent(searchquery) + "&disable_polymer=1&" + regionsetting, "_blank");} else {window.location.href = "https://www.youtube.com/channel/" + channelid + "/search?query=" + encodeURIComponent(searchquery) + "&disable_polymer=1&" + regionsetting;}}});
  2539.                         document.getElementsByTagName("body")[0].appendChild(u);
  2540.                         /* search end */
  2541.                     }
  2542.                     /* RSS button + search featured page end */
  2543.                     /* RSS button playlist page start */
  2544.                     if (window.location.href.includes("/playlist?list") === true && window.location.href.includes("list=RD") === false && window.location.href.includes("list=TL") === false) {
  2545.                         u = document.createElement("div");
  2546.                         if (document.getElementById("appbar-nav") === null) {
  2547.                             u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 18px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2548.                         }
  2549.                         else {u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 58px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");}
  2550.                         u.setAttribute("class", "btn");
  2551.                         u.innerText = "RSS FEED";
  2552.                         u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/feeds/videos.xml?playlist_id=" + playlistid.slice(5), "_blank");} else {window.location.href = "https://www.youtube.com/feeds/videos.xml?playlist_id=" + playlistid.slice(5);}});
  2553.                         document.getElementsByTagName("body")[0].appendChild(u);
  2554.                     }
  2555.                     /* RSS button playlist page end */
  2556.                 }
  2557.                 /* end channel related buttons */
  2558.                 /* browse trending channels start */
  2559.                 if (window.location.href.includes("/feed/") === true || window.location.href.includes("youtube.com/?disable_polymer=1&gl=") === true) {
  2560.                     u = document.createElement("div");
  2561.                     if (document.getElementById("appbar-nav") === null) {
  2562.                         u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 15px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");
  2563.                     }
  2564.                     else {u.setAttribute("style", "position: absolute; left: 50%; margin-right: -50%; transform: translate(-50%, 0); top: 55px; color: #888888; text-shadow: 1.5px 1.5px #141414; font-weight: bold; font-size: 32px; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic; cursor: pointer;");}
  2565.                     u.setAttribute("class", "btn");
  2566.                     if (window.location.href.includes("/feed/guide_builder") === false) {
  2567.                         u.innerText = "BROWSE MOST TRENDING CHANNELS GLOBALLY";
  2568.                         u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/feed/guide_builder?disable_polymer=1&" + regionsetting, "_blank");} else {window.location.href = "https://www.youtube.com/feed/guide_builder?disable_polymer=1&" + regionsetting;}});
  2569.                     }
  2570.                     else {
  2571.                         i = regionCodes.indexOf(window.location.href.slice(-5));
  2572.                         u.innerText = "BACK TO TRENDING VIDEOS IN " + regionNames[i].toUpperCase();
  2573.                         u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/?disable_polymer=1&" + regionsetting, "_blank");} else {window.location.href = "https://www.youtube.com/?disable_polymer=1&" + regionsetting;}});
  2574.                     }
  2575.                     document.getElementsByTagName("body")[0].appendChild(u);
  2576.                 }
  2577.                 /* browse trending channels end */
  2578.                 /* start lainchan back to frontpage */
  2579.                 u = document.createElement("div");
  2580.                 u.setAttribute("style", "position: fixed; right: 10px; bottom: 0; width: 15%; padding-bottom: 25.5%; cursor: pointer; background-repeat: no-repeat; background-position: bottom center; background-size: contain; background-image: url(\"" + resource_img_lain_smile + "\")"); // ignore warning - is in FuckJewTubeResources.js
  2581.                 u.title = "Back to front page";
  2582.                 u.addEventListener("click", function(e){if (e.ctrlKey) {window.open("https://www.youtube.com/?disable_polymer=1", "_blank");} else {window.location.href = "https://www.youtube.com/?disable_polymer=1";}});
  2583.                 document.getElementsByTagName("body")[0].appendChild(u);
  2584.                 /* end lainchan back to frontpage */
  2585.                 /* button end */
  2586.                 /* style start */
  2587.                 document.getElementsByTagName("style")[0].innerHTML = "#div_Menu {line-height: 1.4em;} *|*:root {font-size: 13px;} html {background-color: #111 !important;} #content {width: 66% !important; margin-bottom: 50px;} #content *, #masthead-positioner * {background-color: transparent !important; color: #888 !important; font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic !important; font-weight: bold !important;} #content > * {background-color: #333 !important; color: #888 !important;} #masthead-positioner {background-color: #222 !important;} .play-all-icon-btn {opacity: 1 !important;} #content .yt-pl-thumb *, #content .yt-pl-thumb *:hover *, #content .yt-lockup-thumbnail a:hover *, #content .pl-header-thumb:hover *, #content .video-time *, #content .video-time {color: white !important; text-shadow: -1px -1px 2px #000, 1px -1px 2px #000, -1px 1px 2px #000, 1px 1px 2px #000 !important;} #content .search-pager .yt-uix-button:hover {border: solid 1px skyblue !important;} #content a:hover *, #content a:hover, #content .epic-nav-item-heading:hover, #masthead-positioner a:hover *, #masthead-positioner a:hover, #masthead-positioner .epic-nav-item-heading:hover {text-shadow: -0.5px -0.5px 0.5px teal, -0.5px -0.5px 0.5px skyblue, 0.5px 0.5px 0.5px teal, 0.5px 0.5px 0.5px skyblue !important; color: skyblue !important;} #appbar-nav a:hover {color: transparent !important; text-shadow: none !important;} .yt-lockup:hover .yt-lockup-content, #content td {cursor: default !important;} .btn {font-family: Courier New, monospace} .btn:hover {color: skyblue !important; text-shadow: -1px -1px 1px teal, -1px -1px 1px skyblue, 1px 1px 1px teal, 1px 1px 1px skyblue !important; cursor: pointer;} .favoritesEntries {margin-left: 40px} .favoritesEntries:hover {color: skyblue !important; cursor: pointer; text-shadow: -0.5px -0.5px 0.5px teal, -0.5px -0.5px 0.5px skyblue, 0.5px 0.5px 0.5px teal, 0.5px 0.5px 0.5px skyblue !important;} #favoritesplaylist_MenuBox {user-select: none; -moz-user-select: none; -ms-user-select: none; -khtml-user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;} #favoritesplaylist_MenuBox ol {counter-reset: items;} #favoritesplaylist_MenuBox li {display: block; counter-increment: items;} #favoritesplaylist_MenuBox li:before {content: '000' counter(items)': ';} #favoritesplaylist_MenuBox li:nth-child(n+10):before {content: '00' counter(items)': ';} #favoritesplaylist_MenuBox li:nth-child(n+100):before {content: '0' counter(items)': ';} #favoritesplaylist_MenuBox li:nth-child(n+1000):before {content: counter(items)': ';} .pl-video-handle {display:none;} .pl-video-index {padding: 0 20px 0 10px !important;} .search-icon {opacity: 1 !important;} .show-search:hover {border-bottom: 3px red solid !important;} #buttons_area {opacity: 1 !important; background-image: none !important; border: none !important;} .search-header {border-bottom: none !important;} .comment-renderer-image-attachment {cursor: default !important;} .yt-alert {display: none !important;} .yt-uix-slider-list, .yt-uix-shelfslider-list {white-space: normal !important; width: 105% !important;} #content .compact-shelf-view-all-card {background-color: rgb(33, 33, 33) !important; border: 2px dotted !important; width: 196px !important;} a:focus, #appbar-nav a:focus, .show-search:focus {outline: none !important; color: transparent !important;} .comment-renderer-text-content {max-height: unset !important;} #results .section-list li .item-section .branded-page-box {border: none !important;} #upsell-video a img {width: 99% !important; height: auto !important;} .video-player-view-component {padding-bottom: 80px!important}";
  2588.                 document.getElementsByTagName("html")[0].style = "background-color: rgb(33, 33, 33); color: rgb(33, 33, 33); font-family: Courier New, monospace, MS Pゴシック, MS PGothic, IPA モナー Pゴシック, IPAMonaPGothic;";
  2589.                 document.getElementsByTagName("html")[0].className = "content-snap-width";
  2590.                 document.getElementsByTagName("body")[0].style = "height: 0;";
  2591.                 /* style end */
  2592.                 /* fix video thumbnails start */
  2593.                 function loadVideoThumbnails(u) {
  2594.                     if (u.getElementsByTagName("img")[0].src.includes("youtube.com") === true) {
  2595.                         a = u.getElementsByTagName("img")[0];
  2596.                         a.src = a.getAttribute("data-thumb");
  2597.                         if (u.className.includes("yt-thumb-110") === true) {a.src = a.src.replace(/=s\d+/, "=s110").replace(/\/s\d+/, "/s110").replace(/=w\d+-h\d+-s\d+/, "=w196-h196-s196"); if (a.offsetWidth === 196) {a.src = a.src.replace(/=s\d+/, "=s196").replace(/\/s\d+/, "/s196");}} // fix low res avatars
  2598.                         a.style.display = "";
  2599.                         a.hidden = false;
  2600.                     }
  2601.                 }
  2602.                 /* fix video thumbnails end */
  2603.                 /* make the load more button auto "click" when scrolling down to bottom start */
  2604.                 if (document.getElementsByClassName("load-more-button")[0] !== undefined && window.location.href.includes("/community") === false && window.location.href.includes("/discussion") === false && window.location.href.includes("youtube.com/?disable_polymer=1&gl=") === false) {
  2605.                     document.getElementsByClassName("load-more-button")[0].style.display = "none";
  2606.                     window.onscroll = function() {
  2607.                         if (window.scrollY / window.scrollMaxY >= 0.95 && loadmoreVideosDone === false && window.location.href.includes("list=RD") === false) {
  2608.                             loadmoreVideosDone = true;
  2609.                             loadmoreVideos(); // start auto "click" load more button xhr
  2610.                         }
  2611.                     };
  2612.                 }
  2613.                 /* make the load more button auto "click" when scrolling down to bottom end */
  2614.                 /* load more button start */
  2615.                 function loadmoreVideos() {
  2616.                     if (document.getElementsByClassName("load-more-button")[0] !== undefined) {
  2617.                         loadmoreURL = "https://www.youtube.com" + document.getElementsByClassName("load-more-button")[0].getAttribute("data-uix-load-more-href");
  2618.                         document.getElementsByClassName("load-more-button")[0].remove();
  2619.                     }
  2620.                     u = new Date();
  2621.                     u = "1." + u.toISOString().substring(0, 10).replace(/[-]/g, "");
  2622.                     GM_xmlhttpRequest({
  2623.                         method: "GET",
  2624.                         url: loadmoreURL,
  2625.                         headers: {
  2626.                             "X-YouTube-Client-Name": "1", // these two headers are needed or we get don't get the JSON we want
  2627.                             "X-YouTube-Client-Version": u,
  2628.                             "Accept-Language": "en"
  2629.                         },
  2630.                         onerror: function(e) {alert("ERROR: Loadmore XHR failed - refresh page and try again."); return;},
  2631.                         onload: function(xhrlm) {
  2632.                             if (xhrlm.status === 200) {
  2633.                                 if (JSON.parse(xhrlm.responseText).load_more_widget_html !== "") {
  2634.                                     loadmoreURL = JSON.parse(xhrlm.responseText).load_more_widget_html.match(/\/browse_ajax?[^"]+/)[0];
  2635.                                 }
  2636.                                 else {loadmoreURL = "";}
  2637.                                 loadmoreContent = JSON.parse(xhrlm.responseText).content_html;
  2638.                                 /* start add loadmore */
  2639.                                 if (window.location.href.includes("playlist?list") === true) { // playlists
  2640.                                     document.getElementById("pl-load-more-destination").insertAdjacentHTML("beforeend", loadmoreContent);
  2641.                                 }
  2642.                                 else if (window.location.href.includes("/videos?") === true || window.location.href.includes("/playlists?") === true || window.location.href.includes("/channels?") === true) { // channel uploads + playlists index page + channels list
  2643.                                     document.getElementById("channels-browse-content-grid").insertAdjacentHTML("beforeend", loadmoreContent);
  2644.                                 }
  2645.                                 else if (window.location.href.includes("search?query=") === true || window.location.href.includes("/feed?") === true) { // channel search + activity feed
  2646.                                     document.getElementById("browse-items-primary").insertAdjacentHTML("beforeend", loadmoreContent);
  2647.                                 }
  2648.                                 /* end add loadmore */
  2649.                                 /* clean up start */
  2650.                                 if (window.location.href.includes("/playlist") === true) {cleanUpPaidPlaylist();}
  2651.                                 if (document.getElementsByClassName("yt-channel-title-icon-verified")[0] !== undefined) { // remove verified
  2652.                                     Array.from(document.getElementsByClassName("yt-channel-title-icon-verified")).forEach(cleanUpPage);
  2653.                                 }
  2654.                                 if (document.getElementsByClassName("yt-uix-button-subscription-container")[0] !== undefined) { // remove attentionwhore buttons
  2655.                                     Array.from(document.getElementsByClassName("yt-uix-button-subscription-container")).forEach(cleanUpPage);
  2656.                                 }
  2657.                                 if (document.getElementsByClassName("yt-thumb-110")[0] !== undefined) { // fix low res avatars
  2658.                                     Array.from(document.getElementsByClassName("yt-thumb-110")).forEach(function(u){
  2659.                                         a = u.getElementsByTagName("img")[0];
  2660.                                         a.src = a.src.replace(/=s\d+/, "=s110").replace(/\/s\d+/, "/s110").replace(/=w\d+-h\d+-s\d+/, "=w196-h196-s196");
  2661.                                         if (a.offsetWidth === 196) {a.src = a.src.replace(/=s\d+/, "=s196").replace(/\/s\d+/, "/s196");}
  2662.                                     });
  2663.                                 }
  2664.                                 videoThumbnails = Array.from(document.getElementsByClassName("video-thumb")); // fix video thumbnails
  2665.                                 videoThumbnails.forEach(loadVideoThumbnails);
  2666.                                 if (document.getElementsByClassName("localized-date")[0] !== undefined) {cleanUpStartTime();}
  2667.                                 /* clean up end */
  2668.                                 /* load more done start */
  2669.                                 if (loadmoreURL === "") {
  2670.                                     if (window.location.href.includes("/playlist?list") === true) { // playlists
  2671.                                         document.getElementById("pl-video-list").insertAdjacentHTML("beforeend", "<p style='font-size: 16px; text-align: center; padding: 7px 0 7px 0;'>That's all folks!</p>"); return;
  2672.                                     }
  2673.                                     else if (window.location.href.includes("/videos?") === true || window.location.href.includes("/playlists?") === true || window.location.href.includes("/channels?") === true) { // channel uploads + playlists index page + channels list