// ==UserScript==
// @name Garticphone DRAW bot
// @namespace http://tampermonkey.net/
// @version 0.2.1
// @license GNU
// @description Auto drawing bot!
// @author S&D (Scripts and Deeps team) - StickySkull & DoctorDeathDDrac & 44Type & HendyKey SAMA & Kristofer Sadness & 69Type
// @source https://t.me/doctordeathddracula
// @source https://t.me/stickyskull
// @supportURL https://discord.gg/sHj5UauJZ4
// @match *://garticphone.com/*
// @connect garticphone.com
// @connect greasyfork.org
// @exclude *://garticphone.com/_next/*
// @icon https://www.google.com/s2/favicons?domain=garticphone.com
// @grant unsafeWindow
// @grant GM_xmlhttpRequest
// @grant GM_log
// @run-at document-start
// ==/UserScript==
let me = {
cn: (tag, options, parent) => {
let t = Object.assign(document.createElement(tag), options);
if (parent?.appendChild) parent.appendChild(t);
return t;
},
c: {
closeTimer: 15,
},
s: {
save: ( key, value ) => {
me.s[key] = value;
localStorage.my = window.btoa(JSON.stringify(me.s.bank))
},
initStorage: () => {
me.s.bank = Object.assign(me.s.bank, JSON.parse(window.atob(window.localStorage.my)));
localStorage.my = window.btoa(JSON.stringify(me.s.bank));
},
resaveStorage: () => {
localStorage.my = window.btoa(JSON.stringify(me.s.bank));
},
bank: {},
ss: {
onsettings: false,
},
html: {},
},
f: {
request: function (url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url,
method: 'GET',
onload: (response) => resolve(response.responseText),
});
});
},
requestPureJS: function (url) {
return new Promise(resolve => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send();
xhr.onload = () => resolve(xhr.response)
});
},
rgbToHex: function (r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
},
},
texts: {
settings: {
title: 'SETTINGS',
chooseFile: 'CHOOSE FILE...\nOR CTRL+V',
print: 'PRINT',
clear: 'CLEAR',
},
update: {
close: 'CLOSE',
check: 'CHECK UPDATE',
install: 'INSTALL',
newTitle: 'NEW VERSION OF %s (%s) AVAILABLE!',
closeIn: 'AUTO CLOSING IN... '
},
},
game: {
getScale: () => {return (window.innerWidth - (window.innerWidth < 1920 ? 180 : 320)) / 1150 },
isAnimation: () => {return Boolean(document.getElementsByClassName('note').length)},
},
extension: {
GM: GM,
},
}
Node.prototype.appendChild = new Proxy( Node.prototype.appendChild, {
async apply(target, thisArg, [element]) {
if (element.tagName == "SCRIPT") {
if (element.src.indexOf('draw') != -1) {
let text = await me.f.request(element.src);
text = editScript(text);
text = window.btoa(text);
element.src = `data:application/javascript;base64,${text}`;
}
}
return Reflect.apply( ...arguments );
}
});
class MyWebSocket extends WebSocket {
constructor(...args) {
let ws = super(...args);
me.s.ss.ws = ws;
return ws;
}
send(...args) {
return super.send(...args);
}
};
unsafeWindow.WebSocket = MyWebSocket;
String.prototype.format = function (){
let string = this.toString();
for (let i=0; i<arguments.length; i++){
string = string.replace('%s', arguments[i])
}
return string;
}
/* stroke configuration note */
/* [toolID, strokeID, [color, 18, 0.6], [x0, y0]. [x1, y1], ..., [xn, yn]] */
function editScript(text){
let functionFinalDraw = text.match(/function\s\w{1,}\(\w{0,}\){[^\{]+{[^\}]{0,}return\[\]\.concat\(Object\(\w{0,}\.*\w{0,}\)\(\w{0,}\),\[\w{0,}\]\)[^\}]{0,}}[^\}]{0,}}/g)[0];
let setDataVar = functionFinalDraw.match(/\w{1,}(?=\.setData)/g)[0];
text = text.replace(/(?<=\(\(function\(\){)(?=if\(!\w{1,}\.disabled\))/, `;window.setData = ${setDataVar}.setData;`);
return text;
}
function draw(image, x=0, y=0, width=1516, height=848, pen_size=2, pixel=false){
let story = [];
let canvas = me.cn('canvas', {
width: 848,
height: 424,
}),
ctx = canvas.getContext('2d');
ctx.drawImage(image, x, y, 848, 424);
let data = ctx.getImageData(0, 0, 848, 424).data;
if (me.game.isAnimation()){
for (let i=0; i<848*424; i++) {
y = i / 848 | 0;
x = i - 848 * (i / 848 | 0);
let pos = y * 848 * 4 + x * 4,
color = me.f.rgbToHex(data[pos], data[pos+1], data[pos+2]);
me.s.ss.ws.send(`42[2,7,{"t":0,"d":1,"v":[1,-1,["${color}",${pen_size},${data[pos+3]/255}],[${x},${y}]]}]`);
story.push([1, -1, [color, 2, data[3]/255], [x, y]]);
}
console.log('DONE');
unsafeWindow.setData( (function(e){ return story })() )
} else {
let dict = {};
for (let i=0; i<848*424; i++) {
y = i / 848 | 0;
x = i - 848 * (i / 848 | 0);
let pos = y * 848 * 4 + x * 4,
color = me.f.rgbToHex(data[pos], data[pos+1], data[pos+2]);
if (!dict[color]) {
dict[color] = `[8,-1,["${color}",${data[3]/255}],${x},${y},1,1`;
} else {
dict[color] += `,${x},${y},${1},${1}`;
}
}
for (let key in dict){
let stroke = `42[2,7,{"t":0,"d":1,"v":`+dict[key]+`]}]`;
story.push(JSON.parse(dict[key] + `]`));
me.s.ss.ws.send(stroke);
}
unsafeWindow.setData( (function(e){ return story })() )
}
}
/* first function */
(() => {
document.addEventListener('DOMContentLoaded', createButton);
window.addEventListener('resize', () => {
let e = me.game.getScale();
if (me.s.html.updateBackground) me.s.html.updateBackground.firstChild.style.transform = `scale(${e/1.4})`;
if (me.s.html.background) me.s.html.background.firstChild.style.transform = `scale(${e/1.2})`;
if (document.querySelector("#my-sb")) document.querySelector("#my-sb").style.transform = `scale(${e/1.2})`;
});
})();
function createButton(){
document.head.insertAdjacentHTML('beforeEnd', '<style type="text/css">.side{display:none !important;}.settings-button:hover{color:#000 !important;background-color:#fff !important;}.hover-input-box:hover{border-color:#000 !important}.setting-button:hover{background-color:#fff !important;box-shadow:#000 0 4px}.setting-button{transform-origin:top;position:fixed;z-index:10;height:30px;background-color:rgb(0,0,0);top:0;left:30px;border-radius:0 0 10px 10px;box-shadow:#fff 0 3px;cursor:pointer;text-align:center;display:flex;flex-direction:row;-webkit-box-pack:center;justify-content:center;-webkit-box-align:center;align-items:center;padding:0 12px 0 10px}.setting-button:hover :first-child{color:#000 !important}.setting-button:hover :last-child{color:#000 !important}.settings-opened{background-color:#fff !important;box-shadow:#000 0 4px}.settings-opened :last-child{color:#000 !important}.settings-opened :first-child{color:#000 !important}</style>');
document.body.insertAdjacentHTML('beforeEnd', '<div id="my-sb" class="setting-button"><div style="color: rgb(255, 255, 255); font-size: 22px; margin: 0px 4px 0px 0px;">⚙</div><div style="color: rgb(255, 255, 255); font-family: Black;">AUTO DRAW</div></div>');
document.querySelector("#my-sb").onclick = me.f.generateSettingsMenu ;
document.querySelector("#my-sb").style.transform = `scale(${me.game.getScale()/1.2})`;
}
me.f.closeSettings = function () {
if (!me.s.html.background) return;
document.querySelector("#my-sb").classList.remove('settings-opened');
me.s.html.background.parentNode.removeChild(me.s.html.background);
delete me.s.html.background
}
me.f.generateSettingsMenu = function () {
if (me.s.html.background) return me.f.closeSettings();
document.querySelector("#my-sb").classList.add('settings-opened');
me.s.html.background = me.cn('div', {
id: 'my-bg',
style: 'position:absolute;display:flex;inset:0;background-color:rgba(0,0,0,0.8);-webkit-box-pack:center;justify-content:center;-webkit-box-align:center;align-items:center;z-index:5;',
}, document.body);
let settings = me.cn('div', {
style: `position:relative;display:flex;flex-direction:column;-webkit-box-align:center;align-items:center;background-color:rgb(255,255,255);padding:30px;border-radius:12px;transform:scale(${me.game.getScale()/1.2});`,
}, me.s.html.background),
settingsTitle = me.cn('div', {
innerText: me.texts.settings.title,
style: "font-family:'Black';font-size:35px;margin:0 0 20px;color:#000;",
}, settings),
inputBox = me.cn('div', {
id: 'input-box',
className: "hover-input-box",
style: `width:758px;height:424px;border:4px dashed lightgray;border-radius:17px;cursor:pointer;background-image:url(${me.s.ss.imageData});background-size:95% 95%;background-repeat:no-repeat;background-position:center;`,
}, settings),
fileTitle = me.cn('div', {
style: "text-align:center;font-family:'Black';font-size:50px;color:lightgray;position:relative;top:160px;",
innerText: me.texts.settings.chooseFile,
}, inputBox),
fileInput = me.cn('input', {
id: 'file-title',
type: 'file',
style: 'width:758px;height:424px;cursor:pointer;position:relative;top:-100px;opacity:0;',
title: '',
accept: 'image/*' ,
oninput: async (e) => {
me.f.imageLoading();
let data = await me.f.getDataFromInternalStorage(e);
me.f.createImage(data);
me.f.imageLoaded();
},
}, inputBox),
closeButton = me.cn('button', {
innerText: '',
style: 'border:none;background:none;position:absolute;top:15px;right:15px;width:30px;height:30px;display:flex;-webkit-box-align:center;align-items:center;-webkit-box-pack:center;justify-content:center;cursor:pointer;font-family:ico;color:#000;font-size:25px;',
onclick: me.f.closeSettings,
}, settings),
bottom = me.cn('div', {
style: 'display:flex;flex-direction:row;margin: 20px 0px 0px;',
}, settings),
linkInput = me.cn('input', {
id: "link-input",
placeholder: "URL",
type: 'text',
style: 'height:46px;display:block;border:none;background-color:rgba(255,255,255,.3);border:4px #000 solid;border-radius:7px;font-family:"Bold";font-size:28px;color:#000;padding:0 10px;',
oninput: async () => {
let url = linkInput.value,
imageText = await Promise.any([me.f.requestPureJS(url), me.f.request(url)]).catch(() => '');
console.log(imageText);
if (imageText){
let b64Response = btoa(imageText);
console.log(b64Response)
me.f.createImage('data:image/png;base64,'+b64Response);
}
},
}, bottom),
clearButton = me.cn('button', {
className: 'settings-button',
innerText: me.texts.settings.clear,
style: "color:#fff;font-size:24px;border-radius:7px;border:4px solid #000;background-color:#000;font-family:'Black';margin:0 0 0 10px;padding:0 30px;cursor:pointer;",
onclick: () => {
delete me.s.ss.imageData;
linkInput.value = "";
inputBox.style.backgroundImage = '';
fileInput.type = "text";
fileInput.type = "file";
fileInput.value = "";
},
}, bottom),
printButton = me.cn('button', {
className: 'settings-button',
innerText: me.texts.settings.print,
style: "color:#fff;font-size:24px;border-radius:7px;border:4px solid #000;background-color:#000;font-family:'Black';margin:0 0 0 10px;padding:0px 55px;cursor:pointer;",
onclick: () => {
if (window.location.href.indexOf('draw') != -1){
me.f.closeSettings();
draw(me.s.ss.image);
} else {
alert('You not in the draw section');
}
},
}, bottom);
}
me.f.imageLoading = function(){}
me.f.imageLoaded = function(){}
me.f.getDataFromInternalStorage = function(e) {
return new Promise ( resolve => {
let file = e.target.files[0],
fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = (e) => {resolve(e.target.result)};
})
}
me.f.createImage = function(data){
(!data || !me.s.html.background) && alert('something goes wrong');
me.s.ss.imageData = data;
document.querySelector("#input-box").style.backgroundImage = `url(${data})`;
me.s.ss.image = new Image();
me.s.ss.image.src = data;
}
document.onpaste = async function(event){
if (!me.s.html.background) return;
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (let index in items) {
var item = items[index];
if (item.kind === 'file') {
me.f.imageLoading = function(){}
let data = await (() => {
return new Promise(resolve => {
var blob = item.getAsFile();
var reader = new FileReader();
reader.onload = function(event) {
resolve(event.target.result)
};
reader.readAsDataURL(blob);
})
})()
me.f.createImage(data);
me.f.imageLoaded = function(){}
}
}
}
/*-------------------------------------------AUTO-UPDATE--------------------------------------------*/
/*-IS-THAT-LEGAL,-GREASEFORK?-----------------------------------------------------------------------*/
/*--------------------------------------------------------------------------------------------------*/
me.f.createPopup = function(){
me.s.html.updateBackground = me.cn('div', {
id: 'my-bg',
style: 'position:absolute;display:flex;inset:0;background-color:rgba(0,0,0,0.8);-webkit-box-pack:center;justify-content:center;-webkit-box-align:center;align-items:center;z-index:100;',
}, document.body);
let settings = me.cn('div', {
style: `position:relative;display:flex;flex-direction:column;-webkit-box-align:center;align-items:center;background-color:rgb(255,255,255);padding:30px;border-radius:12px;transform:scale(${me.game.getScale()/1.4});`,
}, me.s.html.updateBackground),
settingsTitle = me.cn('div', {
innerText: me.texts.update.newTitle.format(GM.info.script.name, me.s.ss.version),
style: "font-family:'Black';font-size:35px;margin:0 0 20px;color:#000;",
}, settings),
bottom = me.cn('div', {
style: 'height:55px;display:flex;flex-direction:row;margin:20px 0px 0px;width:100%;',
}, settings),
closeButton = me.cn('button', {
className: 'settings-button',
innerText: me.texts.update.close,
style: "flex:1;color:#fff;font-size:24px;border-radius:7px;border:4px solid #000;background-color:#000;font-family:'Black';cursor:pointer;",
onclick: () => {
me.s.html.updateBackground.parentNode.removeChild(me.s.html.updateBackground);
},
}, bottom),
checkForUpdates = me.cn('button', {
className: 'settings-button',
innerText: me.texts.update.check,
style: "flex:1;color:#fff;font-size:24px;border-radius:7px;border:4px solid #000;background-color:#000;font-family:'Black';margin:0 0 0 10px;cursor:pointer;",
onclick: () => {
window.open('https://greasyfork.org/ru/scripts/436728-garticphone-draw-bot', '_blank')
},
}, bottom),
installNow = me.cn('button', {
className: 'settings-button',
innerText: me.texts.update.install,
style: "flex:1;color:#fff;font-size:24px;border-radius:7px;border:4px solid #000;background-color:#000;font-family:'Black';margin:0 0 0 10px;cursor:pointer;",
onclick: () => {
window.location.replace(me.s.ss.newLink);
},
}, bottom),
autoCloseText = me.cn('div', {
innerText: me.texts.update.closeIn + me.c.closeTimer,
style: "flex:1;color:#000;font-size:20px;border-radius:7px;font-family:'Black';margin:20px 0 0;",
}, settings);
me.s.ss.updateCounter = me.c.closeTimer - 1;
me.s.ss.updateIntervalID = setInterval( () => {
autoCloseText.innerText= me.texts.update.closeIn + me.s.ss.updateCounter;
me.s.ss.updateCounter--;
if (me.s.ss.updateCounter < -1) {
me.s.html.updateBackground.parentNode.removeChild(me.s.html.updateBackground);
clearInterval(me.s.ss.updateIntervalID);
}
}, 1000);
};
(async () => {
let htmlText = await me.f.request('https://greasyfork.org/ru/scripts/436728-garticphone-draw-bot'),
div = document.createElement('div');
div.insertAdjacentHTML('afterBegin', htmlText);
let currentVersion = GM.info.script.version,
newestVersion = div.getElementsByClassName('script-show-version')[1].innerText;
me.s.ss.version = newestVersion;
me.s.ss.newLink = div.getElementsByClassName('install-link')[0].href.replace('https://garticphone.com/', 'https://greasyfork.org/');
console.log(currentVersion, newestVersion);
console.log(me.s.ss.newLink);
if (newestVersion && currentVersion != newestVersion) me.f.createPopup();
})();