Advertisement
Guest User

improved control panel fix1

a guest
Jan 12th, 2023
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 15.96 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name        Improved Control Panel
  3. // @description Sort threads by date, highlights/alerts you on unread posts, thread links go to newest unread post
  4. // @namespace   E-Hentai
  5. // @include     https://forums.e-hentai.org/index.php?*act=UserCP&CODE=26*
  6. // @version     2.2.2
  7. // @author      Superlatanium
  8. // ==/UserScript==
  9.  
  10. //If forum timezone settings are changed, uncomment the next line and reload the page once
  11. //localStorage.improvedControlPanel = ''; alert('localStorage cleared'); return;
  12.  
  13. var myForums = [7, 87, 74, 79, 72, 74, 76, 77];
  14. var interval = 180000; // updates every 5 minutes
  15. var subforumInterval = 3600000;
  16. var timeout = 4000000; // updates stop after a bit more than 1 hour of inactivity
  17.  
  18.  
  19.  
  20.  
  21. var otherUnreadThreads = [];
  22.  
  23. if (!localStorage.improvedControlPanel){
  24.   getTimeZone();
  25.   return;
  26. }
  27. var storage = JSON.parse(localStorage.improvedControlPanel);
  28. var userId = new RegExp(/showuser=\d+/.exec(document.querySelector('a[href*="showuser"]').href)[0]);
  29.  
  30. var lastClicked = Date.now();
  31. var atLeastOneHighlighted;
  32. var started = false;
  33. var doUpdate;
  34.  
  35. document.getElementById('ucpcontent').style.backgroundColor = '#4286f4';
  36.  
  37. var audio = document.createElement('audio');
  38. var source = audio.appendChild(document.createElement('source'));
  39. source.src = 'https://reasoningtheory.net/ding.mp3';
  40. source.type = 'audio/mpeg';
  41.  
  42. var skin = document.getElementById('gfooter').querySelector('option[selected="selected"]').innerHTML;
  43. if (skin == 'Fusion')
  44.   var unreadColor = '#73464E';
  45. else if (skin == 'Ambience')
  46.   var unreadColor = '#E0E0E0';
  47.  
  48. function buildCss(){
  49.   document.head.appendChild(document.createElement('style')).innerHTML = `
  50. #peekButton {padding:5px}
  51. #peekButton:hover {background-color:yellow}
  52. #peekdiv {position:fixed; top:50%; left:15%; width:70%; height:40%; border:3px solid green;}
  53. #peekdiv > img {position:fixed; top:calc(50% + 4px); left:calc(85% - 23px)}
  54. #ucpcontent .maintitle > div:nth-child(1) {float:left}
  55. #ucpcontent .maintitle > div:nth-child(3) {float:right}
  56. #ignoreBtn {margin-left:5px; margin-right:5px}
  57. iframe {width:100%; height:100%;}
  58. `;
  59. }
  60. buildCss();
  61.  
  62. var table = document.getElementsByClassName('borderwrapm')[0].children[0].children[0];
  63. var peekDiv;
  64. function cleanContent(){
  65.   //Remove email notification text
  66.   [].forEach.call(document.getElementsByClassName('desc'), function(desc){
  67.     if (desc.childNodes.length > 1){
  68.       desc.removeChild(desc.childNodes[desc.childNodes.length - 1]);
  69.       desc.removeChild(desc.childNodes[desc.childNodes.length - 1]);
  70.     }
  71.   });
  72.  
  73.  
  74.   //Sort threads by date
  75.   var trs = [];
  76.   for (var i = table.children.length - 2; i > 0; i--){
  77.     var tr = table.children[i];
  78.     if (tr.children[0].className == 'row1'){
  79.       tr.parentElement.removeChild(tr);
  80.       continue;
  81.     }
  82.     tr.threadDate = dateStringToDate(tr.children[4].childNodes[0].textContent);
  83.     trs.push(tr);
  84.     tr.parentElement.removeChild(tr);
  85.   }
  86.   trs.sort(function(a, b){
  87.     return b.threadDate - a.threadDate;
  88.   });
  89.  
  90.   atLeastOneHighlighted = false;
  91.   var displayedThreads = [];
  92.   trs.forEach(function(tr){
  93.     if (tr.children[5].textContent != 'Ignore'){
  94.       displayedThreads.push(tr.getElementsByTagName('a')[0].href.match(/(t|showtopic)=(\d+)/)[2]);
  95.     }
  96.   });
  97.   var foundSubforumThread = false;
  98.   trs.forEach(function(tr){
  99.     var a = tr.getElementsByTagName('a')[0];
  100.     var threadNumber = a.href.match(/(t|showtopic)=(\d+)/)[2];
  101.     if (!/showtopic/.test(a.href)){
  102.       //Add &view=getnewpost to the end of each subscribed thread link
  103.       a.parentElement.removeChild(a.nextSibling);
  104.       a.parentElement.removeChild(a.nextSibling);
  105.       a.parentElement.removeChild(a.nextSibling);
  106.       a.target = '_blank';
  107.       a.onclick = function(){ read(a); }; //left click
  108.       a.oncontextmenu = function(){ read(a); }; //right click
  109.       a.onmouseup = function(e) { if (e.which === 2) read(a); }; //middle click
  110.       a.href = a.href + '&view=getnewpost';
  111.     }
  112.    
  113.     //If you haven't read the latest post, highlight the thread
  114.     if (!/Ignore/.test(tr.children[5].textContent) && ((!storage.latestRead[threadNumber] || storage.latestRead[threadNumber] < tr.threadDate) && !userId.test(tr.children[4].getElementsByTagName('a')[0].href))){
  115.       if (!/auction/i.test(tr.children[1].textContent))
  116.         atLeastOneHighlighted = true;
  117.       [].forEach.call(tr.children, function(td){
  118.         td.style.backgroundColor = unreadColor;
  119.       });
  120.     } else if (/Ignore/.test(tr.children[5].textContent)){
  121.       //add new threads from subscribed forums
  122.       if (displayedThreads.indexOf(threadNumber) != -1) //don't display threads already subscribed to
  123.         return;
  124.       if (storage.seenThreads.indexOf(threadNumber) != -1) //don't display threads Ignored
  125.         return;
  126.       foundSubforumThread = true;
  127.       [].forEach.call(tr.children, function(td){
  128.         td.style.backgroundColor = unreadColor;
  129.         td.style.padding = '12px 5px 12px 5px';
  130.       });
  131.       tr.children[1].children[0].onclick = setThreadRead;
  132.       tr.children[1].children[0].oncontextmenu = setThreadRead;
  133.       tr.children[5].children[0].onclick = function(){
  134.         tr.parentElement.removeChild(tr);
  135.         if (storage.seenThreads.indexOf(threadNumber) == -1)
  136.           storage.seenThreads.push(threadNumber);
  137.         saveStorage();
  138.       };
  139.     }
  140.    
  141.    
  142.     function setThreadRead(){
  143.       [].forEach.call(tr.children, function(td){
  144.         td.style.backgroundColor = '';
  145.       });
  146.       if (storage.seenThreads.indexOf(threadNumber) == -1 && displayedThreads.indexOf(threadNumber) == -1){
  147.         storage.seenThreads.push(threadNumber); //new threads gotten from subforums only
  148.         for (var i = otherUnreadThreads.length - 1; i >= 0; i--){
  149.           if (otherUnreadThreads[i].children[1].textContent === tr.children[1].textContent)
  150.             otherUnreadThreads.splice(0, 1);
  151.         }
  152.       } else
  153.         read(a);
  154.       saveStorage();
  155.     }
  156.     var peekButton = document.createElement('img');
  157.     tr.children[0].replaceChild(peekButton, tr.children[0].children[0]);
  158.     peekButton.id = 'peekButton';
  159.     peekButton.src = 'https://reasoningtheory.net/eye.png';
  160.     peekButton.onclick = function(){
  161.       function exitDiv(){
  162.         if (peekDiv)
  163.           document.body.removeChild(peekDiv);
  164.         peekDiv = '';
  165.       }
  166.       if (peekDiv){
  167.         exitDiv();
  168.         return;
  169.       }
  170.       peekDiv = document.body.appendChild(document.createElement('div'));
  171.       peekDiv.id = 'peekdiv';
  172.       var peekIFrame = peekDiv.appendChild(document.createElement('iframe'));
  173.       peekIFrame.src = a.href;
  174.       peekIFrame.onload = function(){
  175.         setThreadRead();
  176.         [].forEach.call(peekIFrame.contentDocument.body.getElementsByClassName('borderwrap'), function(post){
  177.           if (post.children.length != 4)
  178.             return;
  179.           var userProfile = post.getElementsByClassName('postdetails')[1];
  180.           userProfile.hiddenHTML = userProfile.innerHTML;
  181.           userProfile.innerHTML = userProfile.children[0].innerHTML;
  182.           var showProfile = userProfile.appendChild(peekIFrame.contentDocument.createElement('span'));
  183.           showProfile.textContent = ' ?';
  184.           showProfile.style.textDecoration = 'underline';
  185.           showProfile.onclick = function(){
  186.             userProfile.innerHTML = userProfile.hiddenHTML;
  187.           };
  188.         });
  189.       };
  190.       var exitDivButton = peekDiv.appendChild(document.createElement('img'));
  191.       exitDivButton.src = 'https://reasoningtheory.net/x.png';
  192.       exitDivButton.onclick = exitDiv;
  193.       setThreadRead();
  194.     };
  195.     table.insertBefore(tr, table.children[table.children.length - 1]);
  196.   });
  197.   if ((atLeastOneHighlighted && started) || foundSubforumThread)
  198.     audio.play();
  199.  
  200.   function dateStringToDate(dateString){
  201.     var nowDate = new Date();
  202.     var threadDate;
  203.     if (/Today/.test(dateString))
  204.       threadDate = new Date(nowDate.getUTCFullYear(), nowDate.getUTCMonth(), nowDate.getUTCDate(), dateString.match(/(\d\d)\:/)[1], dateString.match(/\:(\d\d)/)[1]);
  205.     else if (/Yesterday/.test(dateString))
  206.       threadDate = new Date(nowDate.getUTCFullYear(), nowDate.getUTCMonth(), nowDate.getUTCDate() - 1, dateString.match(/(\d\d)\:/)[1], dateString.match(/\:(\d\d)/)[1]);
  207.     else
  208.       threadDate = new Date(dateString);
  209.     threadDate.setMinutes(threadDate.getMinutes() - threadDate.getTimezoneOffset() - storage.offset);
  210.     return threadDate;
  211.   }
  212. }
  213.  
  214. function read(a){
  215.   storage.latestRead[a.href.match(/&t=(\d+)/)[1]] = Date.now();
  216.   [].forEach.call(a.parentElement.parentElement.children, function(td){
  217.     td.style.backgroundColor = '';
  218.   });
  219.   saveStorage();
  220. }
  221.  
  222. document.body.addEventListener('click', function(){
  223.   lastClicked = Date.now() - 100; //ensure that updates get disabled after a missed thread and resume due to Date.now() - lastClicked < interval test coming out near 0
  224. });
  225. document.body.addEventListener('contextmenu', function(){
  226.   lastClicked = Date.now() - 100;
  227. });
  228.  
  229. var toggleBtn;
  230. function tryUpdate(){
  231.   function doDisable(){
  232.     toggleBtn.textContent = 'Start';
  233.     document.getElementById('ucpcontent').style.backgroundColor = 'red';
  234.     toggleBtn.onclick = doEnable;
  235.     clearTimeout(doUpdate);
  236.     function doEnable(){
  237.       lastClicked = Date.now() - 2000;
  238.       toggleBtn.textContent = 'Stop';
  239.       tryUpdate(); //will also properly set new created toggleBtn.onclick
  240.     }
  241.   }
  242.   if (Date.now() - lastClicked > timeout || (atLeastOneHighlighted === true && (Date.now() - lastClicked > interval))){
  243.     document.getElementById('ucpcontent').style.backgroundColor = 'red';
  244.     doDisable();
  245.     return;
  246.   }
  247.   document.getElementById('ucpcontent').style.backgroundColor = 'yellow';
  248.   get('https://forums.e-hentai.org/index.php?act=UserCP&CODE=26', function(data){
  249.     document.getElementById('ucpcontent').innerHTML = data.getElementById('ucpcontent').innerHTML; //threads
  250.     var tableHead = document.getElementsByClassName('maintitle')[2];
  251.     if (tableHead.textContent == 'Menu') //new PM
  252.       tableHead = document.getElementsByClassName('maintitle')[3];
  253.     table = document.getElementsByClassName('borderwrapm')[0].children[0].children[0];
  254.     var userlinks = document.getElementById('userlinks');
  255.     userlinks.innerHTML = data.getElementById('userlinks').innerHTML; //PMs
  256.     var msgA = userlinks.children[1].children[3];
  257.     if (msgA.textContent.substring(0, 1) !== '0')
  258.       userlinks.style.backgroundColor = '#3399ff';
  259.     msgA.onclick = function(){
  260.       userlinks.style.backgroundColor = '';
  261.     };
  262.     msgA.oncontextmenu = msgA.onclick;
  263.     document.getElementById('gfooter').innerHTML = data.getElementById('gfooter').innerHTML; //Time is now
  264.     if (tableHead.children.length === 0){
  265.       tableHead.id = 'tableHead';
  266.       tableHead.style.textAlign = 'center';
  267.       tableHead.innerHTML = '<div>Welcome to your control panel</div><button>Stop</button><div>' +
  268.         data.getElementById('gfooter').textContent.match(/Time\sis.+\d:\d+/)[0] + '</div>';
  269.       toggleBtn = tableHead.children[1];
  270.       toggleBtn.onclick = doDisable;
  271.     }
  272.    
  273.     if (Date.now() - storage.lastSubforumCheck > subforumInterval){
  274.       started = true;
  275.       getSubforums(false);
  276.       return;
  277.     }
  278.     otherUnreadThreads.forEach(function(otherUnreadThread){
  279.       table.insertBefore(otherUnreadThread, table.children[1]);
  280.     });
  281.     cleanContent();
  282.     started = true;
  283.     document.getElementById('ucpcontent').style.backgroundColor = '#4286f4';
  284.     doUpdate = setTimeout(tryUpdate, interval);
  285.   });
  286. }
  287. tryUpdate();
  288.  
  289. function getSubforums(ignoreAll){
  290.   var subforumIndex = 0;
  291.   storage.lastSubforumCheck = Date.now();
  292.   otherUnreadThreads = [];
  293.   getForum();
  294.   function getForum(){
  295.     get('https://forums.e-hentai.org/index.php?showforum=' + myForums[subforumIndex], function(data){
  296.       var getTable = data.getElementsByClassName('ipbtable')[1].children[0];
  297.       for (var j = getTable.children.length - 1; j > 0; j--){
  298.         var tr = getTable.children[j];
  299.         if (tr.getElementsByTagName('a').length === 0)
  300.           continue;
  301.         var threadTitleTBlock = tr.children[2]
  302.         var threadTitleContainer = threadTitleTBlock.getElementsByTagName('span')[0];
  303.         var threadHrefElement;
  304.         if (threadTitleContainer) {
  305.             // 正常,直接获取链接
  306.             threadHrefElement = threadTitleContainer.getElementsByTagName('a')[0]
  307.         } else {
  308.             // 没有span,fallback到格内第一个a元素的父元素
  309.             threadHrefElement = threadTitleTBlock.getElementsByTagName('a')[0]
  310.             threadTitleContainer = threadHrefElement.parentElement
  311.         }
  312.         var threadTitle = threadTitleContainer.textContent;
  313.         try {
  314.           var threadNumber = threadHrefElement.href.match(/showtopic=(\d+)/)[1];
  315.         } catch(err) {
  316.           continue;
  317.         }
  318.         var desc = tr.children[2].getElementsByClassName('desc');
  319.         if (storage.seenThreads.indexOf(threadNumber) != -1)
  320.           continue;
  321.         if (ignoreAll){
  322.           storage.seenThreads.push(threadNumber);
  323.           continue;
  324.         }
  325.         tr.children[2].innerHTML = '<a href=https://forums.e-hentai.org/index.php?showtopic=' + threadNumber + ' target=_blank>' + threadTitle + '</a>' + (desc ? desc[0].outerHTML : '');
  326.         tr.children[6].innerHTML = tr.children[6].children[0].innerHTML;
  327.         var dateNode = tr.children[6].childNodes[0];
  328.         var dateStr = dateNode.textContent;
  329.         if (!/Today,\s\d/.test(dateStr) && !/Yesterday,\s\d/.test(dateStr))
  330.           dateNode.textContent = dateStr.match(/\s([a-z]{3})/i)[1] + ' ' + dateStr.match(/^\d+/)[0] + ' ' + dateStr.match(/\d\d\d\d/)[0] + ', ' + dateStr.match(/\d+:\d+/)[0];
  331.         tr.removeChild(tr.children[4]);
  332.         tr.removeChild(tr.children[1]);
  333.        
  334.         tr.appendChild(document.createElement('td'));
  335.         var button = tr.children[5].appendChild(document.createElement('button'));
  336.         button.id = 'ignoreBtn';
  337.         button.textContent = 'Ignore';
  338.         [].forEach.call(tr.children, function(td){
  339.           td.className = 'row2';
  340.         });
  341.         otherUnreadThreads.push(tr);
  342.         table.insertBefore(tr, table.children[1]);
  343.       }
  344.      
  345.       subforumIndex++;
  346.       if (subforumIndex !== myForums.length){
  347.         getForum();
  348.         return;
  349.       }
  350.       saveStorage();
  351.       document.getElementById('ucpcontent').style.backgroundColor = '#4286f4';
  352.       if (!ignoreAll){
  353.         cleanContent();
  354.         doUpdate = setTimeout(tryUpdate, interval);
  355.         return;
  356.       }
  357.      
  358.       window.location.href = window.location.href;
  359.       return;
  360.     });
  361.   }
  362. }
  363.  
  364. function saveStorage(){
  365.   localStorage.improvedControlPanel = JSON.stringify(storage);
  366. }
  367.  
  368.  
  369. function getTimeZone(){
  370.   var s = '';
  371.   if (/https/.exec(window.location.href))
  372.     s = 's';
  373.   get('https://forums.e-hentai.org/index.php?act=UserCP&CODE=04', function(data){
  374.     storage = {'seenThreads': [], 'lastSubforumCheck': 0};
  375.     var timeString = data.getElementsByTagName('fieldset')[0].querySelector('option[selected="selected"]').textContent;
  376.     if (!/\d/.exec(timeString))
  377.       storage.offset = 0;
  378.     else
  379.       storage.offset = parseInt(/[+-]/.exec(timeString) + '1') * (parseInt(/\d\d?(?=\:)/.exec(timeString)) * 60 + parseInt(/\d\d?(?=\s)/.exec(timeString)));
  380.    
  381.     storage.latestRead = {};
  382.     [].forEach.call(document.querySelectorAll('a[href*="forums.e-hentai.org/index.php?act=ST"]'), function(a){
  383.       var threadNumber = a.href.match(/&t=(\d+)/)[1];
  384.       if (Object.keys(storage.latestRead).indexOf(threadNumber) == -1)
  385.         storage.latestRead[threadNumber] = Date.now();
  386.     });
  387.     getSubforums(true);
  388.   });
  389. }
  390.  
  391. function get(url, done){
  392.   var r = new XMLHttpRequest();
  393.   r.open('GET', url, true);
  394.   r.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
  395.   r.responseType = 'document';
  396.   r.onload = function () {
  397.     if (r.status >= 200 && r.status < 400){
  398.       done(r.response);
  399.     }
  400.   };
  401.   r.send();
  402. }
Tags: js
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement