Steve5451

Avatar Override 1.0.3

Nov 9th, 2016
2,044
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Avatar Override
  3. // @namespace    http://thepotato.net/
  4. // @version      1.0.3
  5. // @description  Change people's avatars.
  6. // @author       Steve5451
  7. // @include      https://forum.blockland.us*
  8. // @run-at       document-start
  9. // @grant        GM.getValue
  10. // @grant        GM.setValue
  11. // @noframes
  12. // ==/UserScript==
  13.  
  14. const SEAMLESS_MODE = true, // Run while the page is loading rather than at the end? Reduces pop-in effect.
  15.       AVATAR_STYLE = "max-width: 75px; max-height: 75px;"; // You should probably keep this the way it is unless you want big avatars.
  16.  
  17. // ------------------------------------------------ no touch --------------------------------------------------- //
  18.  
  19. var settings = {},
  20.     interval,
  21.     PaintCanvas;
  22.  
  23. Promise.resolve(GM.getValue("avatar_overrides")).then(savedSettings => {
  24.     settings = JSON.parse(savedSettings);
  25. }).catch(error => {
  26.     console.error(error + "\nCouldn't load settings.");
  27.     GM.setValue("avatar_overrides", "{}");
  28.     settings = {};
  29. });
  30.  
  31. if(window.location.href.startsWith("https://forum.blockland.us/index.php?topic=")) { // In a topic
  32.     if(SEAMLESS_MODE)
  33.         interval = setInterval(replaceAvatars, 1);
  34.  
  35.     document.addEventListener("DOMContentLoaded", SEAMLESS_MODE ? () => { // In seamless mode:
  36.         replaceAvatars(); // Run oncemore to assure all avatars are processed.
  37.         clearInterval(interval); // Kill our avatar polling interval.
  38.     } : replaceAvatars ); // Not in seamless mode, run now that the document has loaded.
  39. } else if(window.location.href.match(/^(.*\?action=profile;u=[0-9]{1,})$/)) { // On a users profile
  40.     const uIDIndex = window.location.href.indexOf(";u=");
  41.     if(uIDIndex === -1) return;
  42.  
  43.     const userID = window.location.href.substr(uIDIndex + 3).split("&")[0].split("#")[0]; // Get user ID from url and just in case remove any GET params after
  44.  
  45.     document.addEventListener("DOMContentLoaded", function() { // Page loaded
  46.         const isEdited = (settings[userID] !== undefined),
  47.               isBlocked = (settings[userID] === "block"),
  48.  
  49.               userTable = document.body.querySelector('table[border="0"][cellspacing="0"][cellpadding="2"][width="100%"]'),
  50.               firstTD = userTable.getElementsByTagName("td")[0];
  51.  
  52.         var avatar = document.getElementsByClassName("avatar")[0];
  53.  
  54.         const containerShow = document.createElement("span");
  55.         containerShow.setAttribute("style", (isEdited ? "font-size: 8pt; color: #d00;" : "font-size: 7pt;") + " cursor: pointer;");
  56.         containerShow.innerHTML = isEdited ? (isBlocked ? "[blocked]" : "[edited]") : "[edit]";
  57.         containerShow.onclick = function() {
  58.             buttonContainer.style.display = "block";
  59.             this.style.display = "none";
  60.         };
  61.  
  62.         const buttonContainer = document.createElement("div");
  63.         buttonContainer.setAttribute("style", "display: none;");
  64.  
  65.         const replaceImageURL = document.createElement("input");
  66.         replaceImageURL.type = "button";
  67.         replaceImageURL.value = "Replace avatar by URL";
  68.         replaceImageURL.onclick = function() {
  69.             let newURL = prompt("Paste url of new image");
  70.  
  71.             if(!newURL) return;
  72.             if(avatar && (newURL === avatar.src || (settings[userID] && settings[userID] === newURL))) {
  73.                 alert("That's already the current URL.");
  74.                 return;
  75.             }
  76.  
  77.             settings[userID] = newURL;
  78.             saveSettings();
  79.  
  80.             updateUserPageAvatar(userID);
  81.         };
  82.         buttonContainer.appendChild(replaceImageURL);
  83.  
  84.         const replaceImageFile = document.createElement("input");
  85.         replaceImageFile.type = "file";
  86.         replaceImageFile.accept = "image/*";
  87.         replaceImageFile.style.display = "none";
  88.         replaceImageFile.onchange = function() {
  89.             if(!this.files && this.files.length <= 0) return;
  90.             if(!this.files[0].type.startsWith("image/")) return alert("File must be an image");
  91.  
  92.             const fileReader = new FileReader();
  93.             fileReader.onloadend = function() {
  94.                 settings[userID] = fileReader.result;
  95.                 saveSettings();
  96.  
  97.                 updateUserPageAvatar(userID);
  98.             };
  99.             fileReader.readAsDataURL(this.files[0]);
  100.         };
  101.         buttonContainer.appendChild(replaceImageFile);
  102.  
  103.         const replaceImageFileHandler = document.createElement("input");
  104.         replaceImageFileHandler.type = "button";
  105.         replaceImageFileHandler.value = "Replace avatar by file";
  106.         replaceImageFileHandler.onclick = function() { replaceImageFile.click(); };
  107.         buttonContainer.appendChild(replaceImageFileHandler);
  108.  
  109.         const drawImage = document.createElement("input");
  110.         drawImage.type = "button";
  111.         drawImage.value = "Draw";
  112.         drawImage.onclick = function() {
  113.             if(PaintCanvas) return;
  114.  
  115.             Paint = new Painter(avatar, userID);
  116.             document.body.appendChild(Paint.bg);
  117.         };
  118.         buttonContainer.appendChild(drawImage);
  119.  
  120.         const resetImage = document.createElement("input");
  121.         resetImage.type = "button";
  122.         resetImage.value = "Reset image";
  123.         resetImage.onclick = function() {
  124.             if(!settings[userID]) return;
  125.  
  126.             delete settings[userID];
  127.             saveSettings();
  128.  
  129.             location.reload();
  130.         };
  131.         buttonContainer.appendChild(resetImage);
  132.  
  133.         if(settings[userID] !== "block") {
  134.             const blockImage = document.createElement("input");
  135.             blockImage.type = "button";
  136.             blockImage.value = "Block avatar";
  137.             blockImage.onclick = function() {
  138.                 settings[userID] = "block";
  139.                 saveSettings();
  140.  
  141.                 updateUserPageAvatar(userID);
  142.             };
  143.             buttonContainer.appendChild(blockImage);
  144.         }
  145.  
  146.         if(!avatar) {
  147.             firstTD.innerHTML = "";
  148.  
  149.             avatar = document.createElement("img");
  150.             avatar.setAttribute("class", "avatar");
  151.  
  152.             firstTD.appendChild(avatar);
  153.  
  154.             firstTD.appendChild(document.createElement("br"));
  155.             firstTD.appendChild(document.createElement("br"));
  156.         }
  157.  
  158.         avatar.setAttribute("style", AVATAR_STYLE);
  159.         updateUserPageAvatar(userID);
  160.  
  161.         firstTD.insertBefore(containerShow, firstTD.firstChild);
  162.         firstTD.insertBefore(document.createElement("br"), containerShow.nextSibling);
  163.         firstTD.insertBefore(buttonContainer, firstTD.firstChild);
  164.     });
  165. }
  166.  
  167. function updateUserPageAvatar(userID) {
  168.     const avatar = document.getElementsByClassName("avatar")[0];
  169.     if(!avatar) return;
  170.     if(!settings[userID]) return;
  171.  
  172.     if(settings[userID] === "block") {
  173.         avatar.src = "";
  174.         return ;
  175.     }
  176.  
  177.     avatar.src = settings[userID];
  178. }
  179.  
  180.  
  181. function replaceAvatars() {
  182.     const users = document.body.querySelectorAll('td[valign="top"][width="15%"][rowspan="2"] > b > a[href^="https://forum.blockland.us/index.php?action=profile;u="]');
  183.  
  184.     for(let i = 0; i < users.length; ++i) {
  185.         const userID = users[i].href.split(";u=")[1].split("&")[0].split("#")[0];
  186.  
  187.         if(!settings[userID]) continue;
  188.  
  189.         var avatarContainer = users[i].parentNode.nextSibling.nextSibling.nextSibling,
  190.             avatar = avatarContainer.getElementsByClassName("avatar")[0];
  191.  
  192.         if(!avatar) {
  193.             avatar = document.createElement("img");
  194.             avatar.setAttribute("class", "avatar");
  195.             avatar.setAttribute("style", AVATAR_STYLE);
  196.  
  197.             avatarContainer.appendChild(avatar);
  198.         }
  199.  
  200.         if(settings[userID] === "block") {
  201.             avatar.src = "";
  202.             avatar.display = "none";
  203.  
  204.             continue;
  205.         }
  206.  
  207.         avatar.src = settings[userID];
  208.     }
  209. }
  210.  
  211. function saveSettings() {
  212.     GM.setValue("avatar_overrides", JSON.stringify(settings));
  213. }
  214.  
  215. class Painter {
  216.     constructor(avatar, userID) {
  217.         if(avatar)
  218.             this.avatar = avatar;
  219.         if(userID)
  220.             this.userID = userID;
  221.  
  222.         this.mouseDown = false;
  223.         this.color = "#000000";
  224.         this.lastStroke = undefined;
  225.  
  226.         this.bg = document.createElement("div");
  227.         this.bg.setAttribute("style", "text-align: center; padding-top: 50px; z-index: 100; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-color: rgba(0, 0, 0, 0.5); position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;");
  228.  
  229.         this.bg.onmousedown = e => {
  230.             this.mouseDown = true;
  231.         };
  232.  
  233.         this.bg.onmouseup = e => {
  234.             this.mouseDown = false;
  235.  
  236.             if(this.ctx && this.lastStroke)
  237.                 this.ctx.stroke();
  238.  
  239.             this.lastStroke = undefined;
  240.         };
  241.  
  242.         this.toolbox = document.createElement("div");
  243.         this.toolbox.setAttribute("style", "display: inline-block; text-align: left; width: 500px; background-color: #eee; border: 1px solid #000; border-bottom: 0px solid transparent; z-index: 101;");
  244.         this.bg.appendChild(this.toolbox);
  245.  
  246.         this.colorPicker = document.createElement("input");
  247.         this.colorPicker.type = "color";
  248.         this.colorPicker.value = "#000000";
  249.         this.colorPicker.style.marginRight = "5px";
  250.         this.colorPicker.onchange = e => {
  251.             this.color = this.colorPicker.value;
  252.             if(this.ctx)
  253.                 this.ctx.strokeStyle = this.colorPicker.value;
  254.         };
  255.         this.toolbox.appendChild(this.colorPicker);
  256.  
  257.         this.importAvatar = document.createElement("input");
  258.         this.importAvatar.type = "button";
  259.         this.importAvatar.value = "Import current avatar";
  260.         this.importAvatar.onclick = e => {
  261.             if(!this.ctx || !this.avatar) return;
  262.  
  263.             this.ctx.drawImage(this.avatar, 0, 0, this.canvas.width, this.canvas.height);
  264.         };
  265.         this.toolbox.appendChild(this.importAvatar);
  266.  
  267.         this.clearCanvas = document.createElement("input");
  268.         this.clearCanvas.type = "button";
  269.         this.clearCanvas.value = "Clear";
  270.         this.clearCanvas.onclick = e => {
  271.             if(!this.ctx || !this.avatar) return;
  272.  
  273.             this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  274.         };
  275.         this.toolbox.appendChild(this.clearCanvas);
  276.  
  277.         this.cancel = document.createElement("input");
  278.         this.cancel.type = "button";
  279.         this.cancel.value = "Close";
  280.         this.cancel.style.float = "right";
  281.         this.cancel.onclick = e => {
  282.             if(!confirm("Exit painter?")) return;
  283.  
  284.             PaintCanvas = undefined;
  285.             this.bg.remove();
  286.         };
  287.         this.toolbox.appendChild(this.cancel);
  288.  
  289.         this.apply = document.createElement("input");
  290.         this.apply.type = "button";
  291.         this.apply.value = "Save";
  292.         this.apply.style.float = "right";
  293.         this.apply.onclick = e => {
  294.             let tempCanvas = document.createElement("canvas");
  295.             tempCanvas.width = 75;
  296.             tempCanvas.height = 75;
  297.  
  298.             tempCanvas.getContext("2d").drawImage(this.canvas, 0, 0, 75, 75);
  299.  
  300.             settings[this.userID] = tempCanvas.toDataURL("image/png");
  301.             saveSettings();
  302.  
  303.             updateUserPageAvatar(this.userID);
  304.         };
  305.         this.toolbox.appendChild(this.apply);
  306.  
  307.         this.bg.appendChild(document.createElement("br"));
  308.  
  309.         this.canvas = document.createElement("canvas");
  310.         this.canvas.width = this.canvas.height = 500;
  311.         this.canvas.setAttribute("style", "background-color: #fff; cursor: crosshair; background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAANElEQVQ4y2O8devWfwYigKqqKjHKGJgYqAxGDRw1cDAYyPj//3+icsrt27dHw3DUwJFrIADkIQqwsXiZKgAAAABJRU5ErkJggg==); border: 1px solid #000;");
  312.  
  313.         this.canvas.onmousemove = e => {
  314.             if(!this.mouseDown) return;
  315.  
  316.             this.strokeStyle = this.color;
  317.  
  318.             if(!this.lastStroke) {
  319.                 this.ctx.beginPath();
  320.                 this.ctx.moveTo(e.offsetX, e.offsetY);
  321.             } else {
  322.                 this.ctx.lineTo(e.offsetX, e.offsetY);
  323.                 this.ctx.stroke();
  324.             }
  325.  
  326.             this.lastStroke = {x: e.offsetX, y: e.offsetY };
  327.  
  328.         };
  329.  
  330.         this.canvas.onmouseleave = e => {
  331.             this.lastStroke = undefined;
  332.         };
  333.  
  334.         this.ctx = this.canvas.getContext("2d");
  335.         this.bg.appendChild(this.canvas);
  336.  
  337.         this.ctx.strokeStyle = this.color;
  338.         this.ctx.lineWidth = 10;
  339.     }
  340. }
  341.  
  342. /* Changelog:
  343.  
  344. 1.0   - Initial release
  345. 1.0.1 - Added clear button to painter and bugfix
  346. 1.0.2 - Fixed a bug related to user's profiles
  347. 1.0.3 - Greasemonkey compatibility fix
  348.  
  349. */
Add Comment
Please, Sign In to add comment