tsj_lives

PoalTweaks

Dec 1st, 2025 (edited)
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name     Poal Tweaks
  3. // @author   YoureJewish
  4. // @version  0.3.7
  5. // @include  https://Poal.co/*
  6. // @grant    GM_setValue
  7. // @grant    GM_getValue
  8. // @grant    GM_addStyle
  9. // #grant    GM_deleteValue
  10. // ==/UserScript==
  11.  
  12. // **** Settings ****
  13. var settings = {
  14.     targetedDomains: ['searchvoat.co'],
  15.     blockedUsers: ['aou'],
  16.     shouldHidePoalIcons: false,
  17.     shouldNormalizeUsernames: false,
  18.     shouldForceLinksToNewTab: false,
  19.     shouldHideRightSidebar: true,
  20.     shouldMoveLeftSidebar: true
  21. };
  22.  
  23. // **** Utils ****
  24. class utilities {
  25.     constructor() {}
  26.    
  27.     // Control Helpers
  28.     getTagContainer(userName) {
  29.         if(!this.tagButton) {
  30.             // Input Toggle Button
  31.             let button = document.createElement('a');
  32.             button.id = 'buttontag';
  33.             button.classList = 'sbm-post pure-button';
  34.             button.text = 'Set User Tag';
  35.             button.setAttribute('state', 'hidden');
  36.  
  37.             // Text Input
  38.             let input = document.createElement('input');
  39.             input.setAttribute('placeholder', 'Set Custom User Tag...');
  40.             input.setAttribute('maxlength', '30');
  41.             input.style = 'background-color:#2b3447;color:#fff;border-radius:18px;box-sizing:border-box;border:solid #3a3a3a 1px;font-size:14px;padding:8px;';
  42.             input.classList = 'pure-u-1';
  43.             input.id = 'inputtag';
  44.  
  45.             // Color Input Elements
  46.             let colorInputLabel = document.createElement('label')
  47.             colorInputLabel.innerHTML = 'Tag Text Color';
  48.             colorInputLabel.style = 'color:#bdbdbd;';
  49.  
  50.             let colorInput = document.createElement('input');
  51.             colorInput.id = 'colortag';
  52.             colorInput.setAttribute('type', 'color');
  53.             colorInput.style = 'color:#bdbdbd;background-color:rgba(51,51,51,0.5);width:100%;margin:5px 0';
  54.  
  55.             // Background Color Input Elements
  56.             let backgroundColorInputLabel = document.createElement('label')
  57.             backgroundColorInputLabel.innerHTML = 'Tag Background Color';
  58.             backgroundColorInputLabel.style = 'color:#bdbdbd;';
  59.  
  60.             let backgroundColorInput = document.createElement('input');
  61.             backgroundColorInput.id = 'backgroundcolortag';
  62.             backgroundColorInput.setAttribute('type', 'color');
  63.             backgroundColorInput.style = 'color:#bdbdbd;background-color:rgba(51,51,51,0.5);width:100%;margin-top:5px';
  64.  
  65.             let colorInputContainer = document.createElement('div');
  66.             colorInputContainer.style = 'width:100%;text-align:center;padding-top:5px;margin:5px 0;border-radius:18px;border:solid #3a3a3a 1px;background-color:rgba(51,51,51,0.5);';
  67.             colorInputContainer.append(colorInputLabel);
  68.             colorInputContainer.append(colorInput);
  69.             colorInputContainer.append(backgroundColorInputLabel);
  70.             colorInputContainer.append(backgroundColorInput);
  71.  
  72.             // Input container
  73.             let inputContainer = document.createElement('div');
  74.             inputContainer.id = 'tagInputContainer';
  75.             inputContainer.style.display = 'none';
  76.             inputContainer.append(input);
  77.             inputContainer.append(colorInputContainer);
  78.  
  79.             // Final Container
  80.             let container = document.createElement('div');
  81.             container.append(button);
  82.             container.append(inputContainer);
  83.  
  84.             this.tagButton = container;
  85.         }
  86.  
  87.         let tagValues = this.getUserTag(userName);
  88.  
  89.         console.log(tagValues);
  90.  
  91.         let clone = this.tagButton.cloneNode(true);
  92.         let cloneInput = clone.querySelector('#inputtag');
  93.         cloneInput.setAttribute('username', userName);
  94.         cloneInput.value = tagValues?.text || '';
  95.         let cloneColorInput = clone.querySelector('#colortag');
  96.         cloneColorInput.value = tagValues?.color || '#dddddd';
  97.         let cloneBackgroundInput = clone.querySelector('#backgroundcolortag');
  98.         cloneBackgroundInput.value = tagValues?.background || '#4163ac';
  99.  
  100.         return clone;
  101.     }
  102.  
  103.     getNameTag(tagText) {
  104.         if(!this.tag){
  105.             let span = document.createElement('span');
  106.             span.classList = 'cstmTag';
  107.             this.tag = span;
  108.         }
  109.  
  110.         let clone = this.tag.cloneNode();
  111.         clone.innerHTML = tagText;
  112.         return clone;
  113.     }
  114.  
  115.     getRemoveButton(parentSelector) {
  116.         if(!this.removeButton) {
  117.             let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  118.             path.setAttribute('d', 'm 0,8.0189707 c 0,4.4112003 3.58880304,8.0000003 8.00000004,8.0000003 4.4111999,0 7.9999999,-3.5888 7.9999999,-8.0000003 0,-4.411197 -3.58873,-8.00000005 -7.9999999,-8.00000005 -4.411274,0 -8.00000004,3.58880305 -8.00000004,8.00000005 z m 13.16820994,0 c 0,2.8497603 -2.31845,5.1682103 -5.1682099,5.1682103 -0.91132,0 -1.767717,-0.23795 -2.511953,-0.65368 L 12.716526,5.5070177 c 0.41573,0.744236 0.65376,1.600633 0.65376,2.511953 z M 8.2020762,2.8508337 c 0.91132,0 1.76772,0.237958 2.5119498,0.653686 L 3.6877022,10.531001 C 3.2718972,9.7867607 3.0339392,8.9303707 3.0339392,8.0189707 c 0,-2.849756 2.318381,-5.168137 5.168137,-5.168137 z');
  119.  
  120.             let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  121.             svg.setAttribute('viewBox', '0 0 16 16');
  122.             svg.append(path);
  123.  
  124.             let span = document.createElement('span');
  125.             span.classList = 'icons';
  126.             span.style = 'top:0px;';
  127.             span.append(svg);
  128.  
  129.             let container = document.createElement('div');
  130.             container.style = 'float:right;cursor:pointer;margin-left:0.25em';
  131.             container.append(span);
  132.             container.setAttribute('toggle', parentSelector);
  133.             container.querySelectorAll('*').forEach(el => { el.setAttribute('toggle', parentSelector) });
  134.  
  135.             this.removeButton = container;
  136.         }
  137.  
  138.         return this.removeButton.cloneNode(true);
  139.     }
  140.  
  141.     getExpandButton(element) {
  142.         if(!element){ return; }
  143.  
  144.         if(!this.expandButton) {
  145.             let path1 = document.createElementNS("http://www.w3.org/2000/svg", "path");
  146.             path1.setAttribute('d', 'M13.5,2.5C12,1,10.1,0.2,8,0.2C5.9,0.2,4,1,2.5,2.5c-3,3-3,8,0,11C4,15,5.9,15.8,8,15.8s4-0.8,5.5-2.3 C16.6,10.5,16.6,5.5,13.5,2.5z M12.5,12.5c-1.2,1.2-2.8,1.9-4.5,1.9s-3.3-0.7-4.5-1.9C1,10,1,6,3.5,3.5C4.7,2.3,6.3,1.6,8,1.6 c1.7,0,3.3,0.7,4.5,1.9C15,6,15,10,12.5,12.5z');
  147.             let path2 = document.createElementNS("http://www.w3.org/2000/svg", "path");
  148.             path2.setAttribute('d', 'M12.3,7.3H8.7V3.7C8.7,3.4,8.4,3,8,3S7.3,3.4,7.3,3.7v3.5H3.7C3.4,7.3,3,7.6,3,8s0.3,0.7,0.7,0.7h3.5v3.5 C7.3,12.6,7.6,13,8,13s0.7-0.3,0.7-0.7V8.7h3.5C12.6,8.7,13,8.4,13,8S12.6,7.3,12.3,7.3z');
  149.  
  150.             let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  151.             svg.setAttribute('viewBox', '0 0 16 16');
  152.             svg.appendChild(path1);
  153.             svg.appendChild(path2);
  154.  
  155.             let svgSpan = document.createElement('span');
  156.             svgSpan.classList = 'icons';
  157.             svgSpan.style = 'margin-top:-1em;margin-left:0em;margin-right:0.5em;display:inline-block;';
  158.             svgSpan.appendChild(svg);
  159.  
  160.             let nameSpan = document.createElement('a');
  161.             nameSpan.id = 'name';
  162.             nameSpan.style = 'font-weight:600;font-size:small;';
  163.  
  164.             let container = document.createElement('a');
  165.             container.classList = 'pure-button';
  166.             container.style = 'background-color:transparent;color:#adadad;width:100%;text-align:center;'
  167.  
  168.             container.append(svgSpan);
  169.             container.append(nameSpan);
  170.             this.expandButton = container;
  171.         }
  172.  
  173.         let expandClone = this.expandButton.cloneNode(true);
  174.         let id = element.closest('.main').id;
  175.         expandClone.setAttribute('bodyid', element.closest('.main').id);
  176.         expandClone.querySelectorAll('*').forEach(el => { el.setAttribute('bodyid', id) });
  177.  
  178.         let name = expandClone.querySelector('#name');
  179.         if(name) {
  180.             name.classList = element.classList;
  181.             name.innerHTML = element.text.trim();
  182.         }
  183.  
  184.         return expandClone;
  185.     }
  186.    
  187.     // Location Helpers
  188.     onHomePage() {
  189.         let mainPages = ['hot', 'new', 'pop', 'top'];
  190.         let url = document.URL;
  191.         return mainPages.some(el => {
  192.             if(url.endsWith(el) && !url.includes('/s/')) {
  193.                 return true;
  194.             }
  195.         });
  196.     }
  197.  
  198.     onSubPage() {
  199.         return document.URL.includes('/s/');
  200.     }
  201.  
  202.     onUserPage() {
  203.         return document.URL.includes('/u/');
  204.     }
  205.  
  206.     onMessagesPage() {
  207.         return document.URL.includes('/messages/');
  208.     }
  209.    
  210.     // Tag Helpers
  211.     getSavedTags() {
  212.         let tags = this.tryJsonParse(GM_getValue('userTags'));
  213.         if(tags != false) {
  214.             return tags;
  215.         }
  216.         else { return {}; }
  217.     }
  218.  
  219.     getUserTag(userName) {
  220.         userName = userName.trim();
  221.         let tags = this.tryJsonParse(GM_getValue('userTags'));
  222.         if(tags != false && userName) {
  223.             if(tags != false){
  224.                 return tags[userName];
  225.             }
  226.         }
  227.         else { return ''; }
  228.     }
  229.  
  230.     saveUserTags(jTags) {
  231.         console.log(jTags);
  232.         let sTags = JSON.stringify(jTags);
  233.         GM_setValue('userTags', sTags);
  234.     }
  235.    
  236.     // General Helpers
  237.     getUsernameElements() {
  238.         return this.find('a[class*="lv"]');
  239.     }
  240.  
  241.     hide(element) {
  242.         if(element) { element.style.display = 'none'; }
  243.     }
  244.  
  245.     show(element) {
  246.         if(element) { element.style.display = 'unset'; }
  247.     }
  248.  
  249.     find(selector, single) {
  250.         if(single) { return document.querySelector(selector); }
  251.         else { return document.querySelectorAll(selector); }
  252.     }
  253.  
  254.     tryJsonParse(str) {
  255.         try { return JSON.parse(str); }
  256.         catch (e) { return false; }
  257.     }
  258.  
  259.     normalizeSettingStrings(strArray) {
  260.         strArray.forEach(function(part, index) {
  261.           this[index] = this[index].toLowerCase().replace('(', '').replace(')', '').replace('www.', '');
  262.         }, strArray);
  263.         return strArray;
  264.     }
  265. }
  266. var utils = new utilities();
  267.  
  268. // **** Username Normalization ****
  269. function hidePoalIcons() {
  270.     if(settings.shouldHidePoalIcons == true) {
  271.         GM_addStyle('.utagicon { display:none !important; }')
  272.     }
  273. }
  274.  
  275. function normalizeUsernames() {
  276.     if(settings.shouldNormalizeUsernames == true) {
  277.         GM_addStyle('.lv0, .lv2, .lv6, .lv20, .lv30, .lv50, .lv100 { background-color:transparent !important; color:#bdbdbd !important; border:none !important; }');
  278.     }
  279. }
  280.  
  281. // **** Custom User Tags ****
  282. function handleUserTags() {
  283.     GM_addStyle('.cstmTag { display:inline-block;margin-left:3px;margin:0px 5px;padding:2px 5px !important;border-radius:8px;border:1px solid #ddd; }');
  284.  
  285.     let userTags = utils.getSavedTags();
  286.     let userKeys = Object.keys(userTags);
  287.     let userElements = utils.getUsernameElements();
  288.     userElements.forEach(el => {
  289.         let userName = el.text;
  290.         if(userKeys.includes(userName)) {
  291.             let parent = el.parentElement;
  292.             let tagValues = userTags[userName];
  293.             if(!parent.querySelector('.cstmTag')) {
  294.                 let tag = utils.getNameTag(tagValues.text);
  295.                 tag.style = 'background-color:' + tagValues.background + ';color:' + tagValues.color;
  296.                 parent.insertBefore(tag, el.nextSibling);
  297.             }
  298.         }
  299.     });
  300. }
  301.  
  302. function addTagButton() {
  303.     if(utils.onUserPage()) {
  304.         let parent = document.querySelector('#tsb #innersb');
  305.         let divider = parent.querySelector('.pmessage');
  306.         let tagContainer = utils.getTagContainer(utils.find('.noshit', true).textContent.trim());
  307.  
  308.         parent.insertBefore(tagContainer, divider);
  309.  
  310.         document.addEventListener('click', function (event) {
  311.             let button = event.target;
  312.             if(button.id == 'buttontag') {
  313.                 let inputContainer = utils.find('#tagInputContainer', true);
  314.                 if(button.getAttribute('state') == 'hidden') {
  315.                     utils.show(inputContainer);
  316.                     button.setAttribute('state', 'visible');
  317.                     button.text = 'Save User Tag';
  318.                 }
  319.                 else {
  320.                     updateUserTag(utils.find('.noshit', true).textContent, utils.find('#inputtag', true).value, utils.find('#backgroundcolortag', true).value, utils.find('#colortag', true).value);
  321.                     utils.hide(inputContainer);
  322.                     button.setAttribute('state', 'hidden');
  323.                     button.text = 'Set User Tag';
  324.                 }
  325.             }
  326.         });
  327.     }
  328. }
  329.  
  330. function updateUserTag(userName, tagValue, tagBackground, tagColor) {
  331.     userName = userName.trim();
  332.     let list = utils.getSavedTags();
  333.     if(tagValue) {
  334.         let values = {};
  335.         values.text = tagValue.trim();
  336.         values.background = tagBackground;
  337.         values.color = tagColor;
  338.         list[userName.trim()] = values;
  339.     }
  340.     else {
  341.         delete list[userName.trim()];
  342.     }
  343.     utils.saveUserTags(list);
  344. }
  345.  
  346. // **** Sidebar Alterations ****
  347. function hideRightSidebar() {
  348.     if(settings.shouldHideRightSidebar == true && utils.onHomePage() == true) {
  349.         utils.find('#tsbr > #innersb > .sidebarlists, a.togglesbl').forEach(el => { el.style.display = 'none'; });
  350.     }
  351. }
  352.  
  353. function moveLeftSidebar () {
  354.     if(settings.shouldMoveLeftSidebar == true && (utils.onHomePage() == true || utils.onSubPage() == true)) {
  355.         let container = utils.find('#tsbl > #innersb > .sidebarlists', true);
  356.         if(container) {
  357.             if(utils.onSubPage() == true) {
  358.                 utils.find('#tsbr > #innersb', true).append(container);
  359.             }
  360.             else {
  361.                 utils.find('#tsbr > #innersb', true).prepend(container);
  362.             }
  363.             utils.find('#tsbr > #innersb > br, div.togglesbl').forEach(el => { el.style.display = 'none'; });
  364.         }
  365.     }
  366. }
  367.  
  368. // **** Force links to open in new tab ****
  369. function forceNewTab() {
  370.     if(settings.shouldForceLinksToNewTab == true) {
  371.         utils.find('.post-heading > a.title:not([target]), .comcombo').forEach(el => { el.setAttribute('target', '_blank'); });
  372.     }
  373. }
  374.  
  375. // **** Block Anyone ****
  376. function hideUserPosts() {
  377.     if(utils.onHomePage() == true) {
  378.         let existingPosts = utils.getUsernameElements();
  379.         existingPosts.forEach(el => {
  380.             if(settings.blockedUsers.includes(el.text.toLowerCase())) {
  381.                 utils.hide(el.closest('.post'));
  382.             }
  383.         });
  384.     }
  385.  
  386.     let postId = GM_getValue('announcementPid');
  387.     let post = utils.find('div[pid="' + postId + '"]', true);
  388.     if(postId && post) {
  389.         utils.hide(post.closest('#announcement-post'));
  390.     }
  391. }
  392.  
  393. function handleMessageCollapse() {
  394.     if(utils.onMessagesPage()) {
  395.         let attachEvent = false;
  396.         let messages = utils.getUsernameElements();
  397.         messages.forEach(el => {
  398.             if(settings.blockedUsers.includes(el.text.trim().toLowerCase())) {
  399.                 let parent = el.closest('#pmess');
  400.                 let body = parent.querySelector('.main');
  401.  
  402.                 let unread = parent.querySelector('.readmsg');
  403.                 if(unread){ unread.click(); }
  404.  
  405.                 let expand = utils.getExpandButton(el);
  406.                 parent.prepend(expand);
  407.                 expand.addEventListener('click', function (event) {
  408.                     let id = event.target.getAttribute('bodyid');
  409.                     expandMessage(id);
  410.                 });
  411.  
  412.                 utils.hide(body);
  413.                 parent.style = 'min-height:0;padding:0 0.8em 0 0.8em;';
  414.             }
  415.         });
  416.     }
  417. }
  418.  
  419. function handleCommentCollapse() {
  420.     let comments = utils.find('div.commenthead.togglecommenthead.collapse > a:nth-child(2)');
  421.     comments.forEach(el => {
  422.         if(settings.blockedUsers.includes(el.text.trim().toLowerCase())) {
  423.             let parent = el.closest('.commenthead.togglecommenthead.collapse');
  424.             parent.style.opacity = '0.2';
  425.             parent.click();
  426.         }
  427.     })
  428.  
  429.     let loadMore = utils.find('.comments-block > .loadsibling', true);
  430.     if(loadMore) {
  431.         utils.find('.comments-block > .loadsibling').forEach(el => {
  432.             el.addEventListener('click', function () {
  433.                 setTimeout(function(){
  434.                     handleCommentCollapse();
  435.                 }, 1000);
  436.             });
  437.         })
  438.     }
  439. }
  440.  
  441. function expandMessage(id) {
  442.     let body = utils.find('#' + id, true);
  443.     if(body && body.style.display == "none") {
  444.         utils.show(body);
  445.     }
  446.     else { utils.hide(body); }
  447. }
  448.  
  449. function insertAnnouncementRemove() {
  450.     if(utils.onHomePage()) {
  451.         let announcement = utils.find('#announcement-post .pbody', true);
  452.         if(announcement) {
  453.             let remove = utils.getRemoveButton('#announcement-post');
  454.  
  455.             announcement.prepend(remove);
  456.  
  457.             document.body.addEventListener('click', function (event) {
  458.                 let toggle = event.target.getAttribute('toggle');
  459.                 if(toggle) {
  460.                     utils.hide(utils.find(toggle, true));
  461.  
  462.                     let postId = utils.find('.post', true).getAttribute('pid');
  463.                     if(postId) { GM_setValue('announcementPid', postId); }
  464.                 }
  465.             });
  466.         }
  467.     }
  468. }
  469.  
  470. // **** Highlight Tagged Domains  ****
  471. function highlightDomains() {
  472.     let domains = document.querySelectorAll('.domain');
  473.     if(domains) {
  474.         domains.forEach(el => {
  475.             if(settings.targetedDomains.includes(el.innerHTML.replace('(', '').replace(')', '').replace('www.', ''))) {
  476.                 el.style = 'color:#a00;font-weight:900;font-size:0.75em;';
  477.             }
  478.         });
  479.     }
  480. }
  481.  
  482. // **** Mutation Observer for posts/links *****
  483. function createMutationObserver() {
  484.     let postsNode = document.querySelector('.alldaposts');
  485.     if(postsNode) {
  486.         const observer = new MutationObserver(function(mutations_list) {
  487.             hideUserPosts();
  488.             highlightDomains();
  489.             forceNewTab();
  490.             normalizeUsernames();
  491.             handleUserTags();
  492.             setTimeout(function() { hidePoalIcons();}, 250);
  493.         });
  494.         observer.observe(postsNode, { subtree: false, childList: true });
  495.     }
  496. }
  497.  
  498. // Init All - At one point there was a reason this existed...
  499. function initAll() {
  500.     settings.targetedDomains = utils.normalizeSettingStrings(settings.targetedDomains);
  501.     settings.blockedUsers = utils.normalizeSettingStrings(settings.blockedUsers);
  502.  
  503.     hideRightSidebar();
  504.     moveLeftSidebar();
  505.     forceNewTab();
  506.     hidePoalIcons();
  507.     normalizeUsernames();
  508.     highlightDomains();
  509.     insertAnnouncementRemove();
  510.     handleMessageCollapse();
  511.     handleCommentCollapse();
  512.     hideUserPosts();
  513.     addTagButton();
  514.     handleUserTags();
  515.     createMutationObserver();
  516. }
  517. initAll();
Advertisement
Add Comment
Please, Sign In to add comment