您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
I Added a Hide Menu just press the 3 dots button!
// ==UserScript== // @name YouTubeDrawaria Engine Pro // @version 1.1 // @description I Added a Hide Menu just press the 3 dots button! // @namespace drawaria.modded.fullspec // @homepage https://drawaria.online/profile/?uid=86e33830-86ea-11ec-8553-bff27824cf71 // @author YouTubeDrawaria // @match https://drawaria.online/* // @match https://drawaria.online/room/* // @match http://*/* // @icon https://i.postimg.cc/44DLPR1F/1.png // @grant none // @license MIT // @run-at document-end // @subscribe https://www.youtube.com/@YouTubeDrawaria // ==/UserScript== (function (icon, name) { 'use strict'; /** * Utility : * CodeMaid is a collection of utility functions * it shall help with a variety of actions * creating HTML nodes with attributes and children * validate variables * clean html * cookie management */ const CodeMaid = (function loadCodeMaiden() { const CodeMaiden = { createDOM: { Element: function () { return document.createElement.apply(document, arguments); }, TextNode: function () { return document.createTextNode.apply(document, arguments); }, Tree: function (type, attrs, childrenArrayOrVarArgs) { const el = this.Element(type); let children; if (CodeMaiden.validate.isArray(childrenArrayOrVarArgs)) { children = childrenArrayOrVarArgs; } else { children = []; for (let i = 2; i < arguments.length; i++) { children.push(arguments[i]); } } for (let i = 0; i < children.length; i++) { const child = children[i]; if (typeof child === 'string') { el.appendChild(this.TextNode(child)); } else { if (child) { el.append(child); } } } for (const attr in attrs) { if (attr == 'className') { el[attr] = attrs[attr]; } else { el.setAttribute(attr, attrs[attr]); } } el.appendAll = function (...nodes) { nodes.forEach((node) => { el.append(node); }); }; return el; }, fromJSON: function (JSONDOM = { element: '', attributes: {}, children: [] }) { if (CodeMaiden.validate.isString(JSONDOM)) return CodeMaiden.createDOM.TextNode(JSONDOM); let dom = CodeMaiden.createDOM.Tree(JSONDOM.element, JSONDOM.attributes); JSONDOM.children.forEach((child) => { dom.append(this.fromJSON(child)); }); return dom; }, Button: function (content) { let btn = this.Tree('button'); btn.className = 'btn btn-outline-secondary'; btn.innerHTML = content; return btn; }, FA: function (fontawesome_icon) { let m = fontawesome_icon.match(/\".*\"/g); return this.Tree('i', { class: m[0].slice(1, m[0].length - 1) }); }, Row: function () { return this.Tree('div', { class: 'ce_row' }); }, RowList: function () { return this.Tree('div', { class: 'icon-list' }); }, }, validate: { isArray: function (value) { return this.isA('Array', value); }, isObject: function (value) { return !this.isUndefined(value) && value !== null && this.isA('Object', value); }, isString: function (value) { return this.isA('String', value); }, isNumber: function (value) { return this.isA('Number', value); }, isFunction: function (value) { return this.isA('Function', value); }, isAsyncFunction: function (value) { return this.isA('AsyncFunction', value); }, isGeneratorFunction: function (value) { return this.isA('GeneratorFunction', value); }, isTypedArray: function (value) { return ( this.isA('Float32Array', value) || this.isA('Float64Array', value) || this.isA('Int16Array', value) || this.isA('Int32Array', value) || this.isA('Int8Array', value) || this.isA('Uint16Array', value) || this.isA('Uint32Array', value) || this.isA('Uint8Array', value) || this.isA('Uint8ClampedArray', value) ); }, isA: function (typeName, value) { return this.getType(value) === '[object ' + typeName + ']'; }, isError: function (value) { if (!value) { return false; } if (value instanceof Error) { return true; } return typeof value.stack === 'string' && typeof value.message === 'string'; }, isUndefined: function (obj) { return obj === void 0; }, getType: function (value) { return Object.prototype.toString.apply(value); }, }, cookies: { set: function (name, value = '') { document.cookie = name + '=' + value + '; expires=Thu, 2 Aug 2001 20:47:11 UTC; path=/'; }, get: function (name) { var nameEQ = name + '='; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); } return null; }, clear: function (name) { document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; }, obfuscate: function () { window.Cookies = { get: function () { console.log(arguments); return 'lol no'; }, }; }, }, cleanup: { scripts: function () { try { let array = document.querySelectorAll('script[src]'); array.forEach((script) => { if (script.src != '') document.head.append(script); }); } catch (error) { console.error(error); } try { let unifiedScript = CodeMaiden.createDOM.Tree('script'); let scripts = document.querySelectorAll('script:not([src])'); let unifiedScriptContent = ''; scripts.forEach((script) => { let content = script.textContent; //.replaceAll(/\s/g, ''); unifiedScriptContent += `try{${content}}catch(e){console.warn(e);}`; script.remove(); }); unifiedScript.textContent = unifiedScriptContent; document.head.append(unifiedScript); } catch (error) { console.error(error); } }, iframes: function () { try { let array = document.querySelectorAll('iframe'); array.forEach((iframe) => { iframe.remove(); }); } catch (error) { console.error(error); } }, styles: function () { try { let unifiedStyles = CodeMaiden.createDOM.Tree('style'); unifiedStyles.textContet = ''; let styles = document.querySelectorAll('style'); styles.forEach((style) => { unifiedStyles.textContent += style.textContent; style.remove(); }); document.head.append(unifiedStyles); } catch (error) { console.error(error); } }, cursors: function () { try { let cursors = document.querySelectorAll('.brushcursor'); cursors.forEach((cursor) => { cursor.remove(); }); } catch (error) { console.error(error); } }, all: function () { this.iframes(); this.styles(); this.scripts(); this.cursors(); }, }, generate: { uuidv4: function () { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); }, }, }; return CodeMaiden; })(); /** * Utility : * help with keeping track of settings and more * Saves your settings in your local storage * may be used in future updates */ const settings = (function enableSettingsContext(prefix) { const namespace = prefix; const settings = { config: {}, save: function () { localStorage.setItem(namespace, JSON.stringify(this.config)); }, load: function () { this.config = JSON.parse(localStorage.getItem(namespace)) || {}; }, }; window.addEventListener('load', () => { settings.load(); }); window.addEventListener( 'beforeunload', () => { settings.save(); }, false ); return settings; })('Engine'); /** * Utility : * contains chromajs and custom css styles */ (function loadExternals() { let ChromaJS = CodeMaid.createDOM.Tree('script', { src: 'https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.4.2/chroma.min.js', }); let myStyleSheet = CodeMaid.createDOM.Tree('style', {}, [ `body * {margin: 0; padding: 0; box-sizing: border-box; line-height: inherit;}`, `#${icon} {--CE-bg_color: linear-gradient(90deg, rgba(131,58,180,1) 0%, rgba(253,29,29,1) 50%, rgba(252,176,69,1) 100%); --CE-color: white;}`, // Gradiente para el fondo `#${icon} {z-index: 999; background: var(--CE-bg_color); border-radius: 1rem; padding: 1rem;}`, // Bordes redondeados y gradiente `#${icon} .icon-list {display: flex; flex-flow: wrap;}`, `#${icon} .nowrap {overflow-x: scroll; padding-bottom: 12px; flex-flow: nowrap;}`, `#${icon} .icon {display: flex; flex: 0 0 auto; max-width: 2.5rem; max-height: 2.5rem; width: 2.5rem; height: 2.5rem; border-radius: 1rem; background-color: rgba(255, 255, 255, 0.2);}`, // Fondo translúcido y más redondeado `#${icon} .icon > * {margin: auto; text-align: center; max-height: 100%; max-width: 100%; color: white; text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);}`, // Texto blanco con sombra `#${icon} .ce_row {display: flex; width: 100%;}`, `#${icon} .ce_row > * {width: 100%;}`, `#${icon} .btn {padding: 0; background-color: rgba(255, 255, 255, 0.1); border-radius: 0.5rem; color: white; text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6); border: 2px solid rgba(0, 0, 255, 0.3); transition: all 0.3s ease-in-out;}`, // Botones mejorados `#${icon} .btn:active {animation: pulseEffect 1s ease-in-out; box-shadow: 0 0 15px rgba(255, 255, 255, 0.8);}`, // Efecto de pulso y brillo al presionar `#${icon} .itext {text-align: center; background-color: rgba(255, 255, 255, 0.1); color: white; text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6); -webkit-appearance: none; -moz-appearance: textfield;}`, // Inputs estilizados `input[name][hidden]:not(:checked) + * {display: none !important;}`, `hr {margin: 10px 0; border-color: rgba(255, 255, 255, 0.2);}`, `.playerlist-row::after {content: attr(data-playerid); position: relative; float: right; top: -20px; color: white; text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);}`, // Textos con sombra en lista de jugadores // Efecto de pulso suave `@keyframes pulseEffect { 0% { transform: scale(1); box-shadow: 0 0 0 rgba(255, 255, 255, 0.8); } 50% { transform: scale(1.1); /* Expansión suave */ box-shadow: 0 0 20px rgba(255, 255, 255, 0.8); } 100% { transform: scale(1); box-shadow: 0 0 0 rgba(255, 255, 255, 0.8); } }` ]); document.head.append(myStyleSheet); document.head.append(ChromaJS); })(); /** * Utility : * Easily upload an Image for your Avatar */ (function addAvatarUploader() { function uploadToAvatar(img) { fetch(window.LOGGEDIN ? 'https://i.postimg.cc/44DLPR1F/1.png' : 'https://i.postimg.cc/44DLPR1F/1.png', { method: 'POST', body: 'imagedata=' + encodeURIComponent(img) + '&fromeditor=true', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', Accept: 'text/plain, */*; q=0.01', 'X-Requested-With': 'XMLHttpRequest', }, }).then((e) => alert(e.statusText === 'OK' ? 'Avatar SUCCESSFULLY uploaded' : e.statusText)); } function avatarUploaderVisual() { document.querySelectorAll('label[for="avataruploader"]').forEach((e) => e.remove()); let input = document.createElement('input'); input.style.display = 'none'; input.id = 'avataruploader'; input.type = 'file'; input.addEventListener('change', onchange); let label = document.createElement('label'); label.style = 'display:flex; text-align: left;'; label.className = 'badge border btn-outline-primary border-primary'; label.innerHTML = '<img class="playerlist-avatar" src="https://i.postimg.cc/44DLPR1F/1.png"><div class="playerlist-name"><span>Subscribe to YouTubeDrawaria!</span><br/><sub>by YouTubeDrawaria</sub></div>'; label.setAttribute('for', input.id); label.append(input); function onchange() { if (!this.files || !this.files[0]) return; let e = new FileReader(); e.addEventListener('load', (e) => { let a = e.target.result.replace('image/gif', 'image/png'); uploadToAvatar(a); }); e.readAsDataURL(this.files[0]); } document.querySelector('#playerlist').before(label); } return avatarUploaderVisual; })()(); /** * Utility : * Apply color to your logs * @param {string} level the color you want * @returns hex color */ function logLevel(level) { let error = [5, 'err', 'error', 'danger', 'red']; let warning = [4, 'warn', 'warning', 'yellow']; let info = [3, 'help', 'info', 'blue']; let success = [2, 'ok', 'success', 'green']; let log = [0, 'log', 'normal', 'mute']; let debug = [1, 'debug', 'trace', 'purple']; if (error.includes(level)) { return '#dc3545'; } if (warning.includes(level)) { return '#ffc107'; } if (info.includes(level)) { return '#17a2b8'; } if (success.includes(level)) { return '#28a745'; } if (log.includes(level)) { return '#6c757d'; } if (debug.includes(level)) { } return '#000000'; } /** * Utility : * generate websocket connection url * @param {string} inviteLink to extract the server type ".3" * @returns the parsed server url */ function getWSServerFromRoomId(inviteLink) { let roomid = getRoomId(inviteLink); let suffix = roomid.split('.')[1] || ''; let prefix = suffix == 3 ? 'sv3.' : suffix == 2 ? 'sv2.' : suffix; return `wss://${prefix}drawaria.online/socket.io/?sid1=undefined&hostname=drawaria.online&EIO=3&transport=websocket`; } /** * Utility : * get your room id without server type * @param {string} inviteLink to extract the room * @returns room uuid */ function getRoomId(inviteLink) { let roomid = inviteLink?.split('/').pop() || '.3'; return roomid; } /** * Utility : * generate a valid user avatar url * @param {array} avatar [ uid, wt ] * @returns */ function getAvatarCacheURL(avatar = ['', '']) { if (avatar[0] == '' && avatar[1] == '') return `https://drawaria.online/avatar/cache/default.jpg`; return `https://drawaria.online/avatar/cache/${avatar.join('.')}.jpg`; } /** * Utility : * easily access the different socket events */ const emits = { chatmsg: function (message) { // 42["chatmsg","a"] let data = ['chatmsg', message]; return `${42}${JSON.stringify(data)}`; }, passturn: function () { // 42["passturn"] let data = ['passturn']; return `${42}${JSON.stringify(data)}`; }, pgdrawvote: function (playerid) { // 42["pgdrawvote",2,0] let data = ['pgdrawvote', playerid, 0]; return `${42}${JSON.stringify(data)}`; }, pgswtichroom: function () { // 42["pgswtichroom"] let data = ['pgswtichroom']; return `${42}${JSON.stringify(data)}`; }, playerafk: function () { // 42["playerafk"] let data = ['playerafk']; return `${42}${JSON.stringify(data)}`; }, playerrated: function () { // 42["playerrated"] let data = ['playerrated']; return `${42}${JSON.stringify(data)}`; }, sendgesture: function (gestureid) { // 42["sendgesture",16] let data = ['sendgesture', gestureid]; return `${42}${JSON.stringify(data)}`; }, sendvote: function () { // 42["sendvote"] let data = ['sendvote']; return `${42}${JSON.stringify(data)}`; }, sendvotekick: function (playerid) { // 42["sendvotekick",93] let data = ['sendvotekick', playerid]; return `${42}${JSON.stringify(data)}`; }, wordselected: function (wordid) { // 42["wordselected",0] let data = ['sendvotekick', wordid]; return `${42}${JSON.stringify(data)}`; }, activateitem: function (itemid, isactive) { let data = ['clientcmd', 12, [itemid, isactive]]; return `${42}${JSON.stringify(data)}`; }, buyitem: function (itemid) { let data = ['clientcmd', 11, [itemid]]; return `${42}${JSON.stringify(data)}`; }, canvasobj_changeattr: function (itemid, target, value) { // target = zindex || shared let data = ['clientcmd', 234, [itemid, target, value]]; return `${42}${JSON.stringify(data)}`; }, canvasobj_getobjects: function () { let data = ['clientcmd', 233]; return `${42}${JSON.stringify(data)}`; }, canvasobj_remove: function (itemid) { let data = ['clientcmd', 232, [itemid]]; return `${42}${JSON.stringify(data)}`; }, canvasobj_setposition: function (itemid, positionX, positionY, speed) { let data = ['clientcmd', 230, [itemid, 100 / positionX, 100 / positionY, { movespeed: speed }]]; return `${42}${JSON.stringify(data)}`; }, canvasobj_setrotation: function (itemid, rotation) { let data = ['clientcmd', 231, [itemid, rotation]]; return `${42}${JSON.stringify(data)}`; }, customvoting_setvote: function (value) { let data = ['clientcmd', 301, [value]]; return `${42}${JSON.stringify(data)}`; }, getfpid: function (value) { let data = ['clientcmd', 901, [value]]; return `${42}${JSON.stringify(data)}`; }, getinventory: function () { let data = ['clientcmd', 10, [true]]; return `${42}${JSON.stringify(data)}`; }, getspawnsstate: function () { let data = ['clientcmd', 102]; return `${42}${JSON.stringify(data)}`; }, moveavatar: function (positionX, positionY) { let data = ['clientcmd', 103, [1e4 * Math.floor((positionX / 100) * 1e4) + Math.floor((positionY / 100) * 1e4), false]]; return `${42}${JSON.stringify(data)}`; }, setavatarprop: function () { let data = ['clientcmd', 115]; return `${42}${JSON.stringify(data)}`; }, setstatusflag: function (flagid, isactive) { let data = ['clientcmd', 3, [flagid, isactive]]; return `${42}${JSON.stringify(data)}`; }, settoken: function (playerid, tokenid) { let data = ['clientcmd', 2, [playerid, tokenid]]; return `${42}${JSON.stringify(data)}`; }, snapchatmessage: function (playerid, value) { let data = ['clientcmd', 330, [playerid, value]]; return `${42}${JSON.stringify(data)}`; }, spawnavatar: function () { let data = ['clientcmd', 101]; return `${42}${JSON.stringify(data)}`; }, startrollbackvoting: function () { let data = ['clientcmd', 320]; return `${42}${JSON.stringify(data)}`; }, trackforwardvoting: function () { let data = ['clientcmd', 321]; return `${42}${JSON.stringify(data)}`; }, startplay: function (room, name, avatar) { let data = `${420}${JSON.stringify([ 'startplay', name, room.type, 'en', room.id, null, [null, 'https://drawaria.online/', 1000, 1000, [null, avatar[0], avatar[1]], null], ])}`; return data; }, votetrack: function (trackid) { let data = ['clientcmd', 1, [trackid]]; return `${42}${JSON.stringify(data)}`; }, requestcanvas: function (playerid) { let data = ['clientnotify', playerid, 10001]; return `${42}${JSON.stringify(data)}`; }, respondcanvas: function (playerid, base64) { let data = ['clientnotify', playerid, 10002, [base64]]; return `${42}${JSON.stringify(data)}`; }, galleryupload: function (playerid, imageid) { let data = ['clientnotify', playerid, 11, [imageid]]; return `${42}${JSON.stringify(data)}`; }, warning: function (playerid, type) { let data = ['clientnotify', playerid, 100, [type]]; return `${42}${JSON.stringify(data)}`; }, mute: function (playerid, targetname, mute = 0) { let data = ['clientnotify', playerid, 1, [mute, targetname]]; return `${42}${JSON.stringify(data)}`; }, hide: function (playerid, targetname, hide = 0) { let data = ['clientnotify', playerid, 3, [hide, targetname]]; return `${42}${JSON.stringify(data)}`; }, report: function (playerid, reason, targetname) { let data = ['clientnotify', playerid, 2, [targetname, reason]]; return `${42}${JSON.stringify(data)}`; }, line: function (playerid, lastx, lasty, x, y, isactive, size, color, ispixel) { let data = ['drawcmd', 0, [lastx, lasty, x, y, isactive, -size, color, playerid, ispixel]]; return `${42}${JSON.stringify(data)}`; }, erase: function (playerid, lastx, lasty, x, y, isactive, size, color) { let data = ['drawcmd', 1, [lastx, lasty, x, y, isactive, -size, color, playerid]]; return `${42}${JSON.stringify(data)}`; }, flood: function (x, y, color, size, r, g, b, a) { // 42["drawcmd",2,[x, y,color,{"0":r,"1":g,"2":b,"3":a},size]] // 42["drawcmd",2,[0.1,0.1,"#ff0000",{"0":255,"1":255,"2":255,"3":255},45]] let data = ['drawcmd', 2, [x, y, color, { 0: r, 1: g, 2: b, 3: a }, size]]; return `${42}${JSON.stringify(data)}`; }, undo: function (playerid) { // 42["drawcmd",3,[playerid]] let data = ['drawcmd', 3, [playerid]]; return `${42}${JSON.stringify(data)}`; }, clear: function () { // 42["drawcmd",4,[]] let data = ['drawcmd', 4, []]; return `${42}${JSON.stringify(data)}`; }, noop: function () { // 42["drawcmd",5,[0.44882022129015975,0.3157894736842105,0.44882022129015975,0.3157894736842105,true,-12,"#000000",playerid]] }, }; const EL = (sel) => document.querySelector(sel); const ELL = (sel) => document.querySelectorAll(sel); window.sockets = []; window.myRoom = {}; /** * Utility : * modify the default socket behaviour * adding listener for room changes to have accurate playercount */ const originalSend = WebSocket.prototype.send; WebSocket.prototype.send = function (...args) { if (window.sockets.indexOf(this) === -1) { window.sockets.push(this); if (window.sockets.indexOf(this) === 0) { this.addEventListener('message', (event) => { // console.debug(event) let message = String(event.data); if (message.startsWith('42')) { let payload = JSON.parse(message.slice(2)); if (payload[0] == 'bc_uc_freedrawsession_changedroom') { window.myRoom.players = payload[3]; } if (payload[0] == 'mc_roomplayerschange') { window.myRoom.players = payload[3]; } } else if (message.startsWith('41')) { // this.send(40) } else if (message.startsWith('430')) { let configs = JSON.parse(message.slice(3))[0]; window.myRoom.players = configs.players; window.myRoom.id = configs.roomid; } }); } } return originalSend.call(this, ...args); }; // ================================================== // // YouTube Engine --- BEGINNING // // ================================================== // /** * The YouTube Engine itself * holds all information for your User Interface * customize the location in the initialize function */ let Engine = { icon: icon, name: name, head: CodeMaid.createDOM.Tree('header', { class: 'icon-list' }), body: CodeMaid.createDOM.Tree('section', {}), chatbox: document.getElementById('chatbox_messages'), Mapper: new Map(), Active: [], initialize: function () { let active = false; let summary = CodeMaid.createDOM.Tree('summary', { class: 'btn btn-block btn-outline-primary' }, [Engine.name]); let target = document.getElementById('accountbox'); target.after(CodeMaid.createDOM.Tree('details', { id: Engine.icon }, [summary, Engine.head, Engine.body])); target.after(CodeMaid.createDOM.Tree('hr')); Cheat.Engine = Engine; summary.addEventListener('click', function () { if (active) return; active = true; console.clear(); if (Engine.Mapper.get('main')) { Engine.Mapper.get('main').forEach(function (child, index) { Engine.Active.push(new child(Engine)); }); } }); // Make the menu draggable let menu = document.getElementById(Engine.icon); menu.style.position = 'flex'; menu.style.zIndex = 1000; let isDragging = true; let offsetY; let menuRect; let rightbarRect; menu.addEventListener('mousedown', function (e) { isDragging = true; menuRect = menu.getBoundingClientRect(); rightbarRect = document.getElementById('rightbar').getBoundingClientRect(); offsetY = e.clientY - menuRect.bottom; menu.style.cursor = 'grabbing'; }); document.addEventListener('mousemove', function (e) { if (isDragging) { let newTop = e.clientY - offsetY; menu.style.bottom = `${newTop}px`; } }); document.addEventListener('mouseup', function () { isDragging = true; menu.style.cursor = 'grab'; }); }, }; /** * The base Class for all component * YouTube Engine was originally designed to be swapable * customizing your experience to your liking * Example: Wanted 2 Bots? Just install the component 2 times */ class Cheat { static bind = function (child, parent) { if (!Engine.Mapper.get(parent)) Engine.Mapper.set(parent, []); Engine.Mapper.get(parent).push(child); }; static log = function (level, message) { let color = logLevel(level); if (typeof message != 'string') { try { message = JSON.stringify(message); } catch (error) { throw error; } } Engine.chatbox.append( CodeMaid.createDOM.Tree( 'div', { class: `chatmessage systemchatmessage7`, 'data-ts': Date.now(), style: `color: ${color}`, }, [message] ) ); console.log(`%c${message}`, `color: ${color}`); }; summary; details; constructor(parentClassReference, position, callback) { this.name = this.constructor.name; this.icon = CodeMaid.createDOM.FA('<i class="fa-duotone fa-face-awesome"></i>'); this.uid = CodeMaid.generate.uuidv4(); this.initialize(parentClassReference, position); this.childReferences = []; let list = Engine.Mapper.get(this.name); if (list) { let self = this; list.forEach(function (child, index) { if (child.name != self.name) { let reference = new child(self); Engine.Active.push(reference); self.childReferences.push(reference); } }); } // this.log('info', `${this.name} loaded`); if (callback) callback(this); } initialize(parentClassReference, position = 'last_after') { if (!parentClassReference || !parentClassReference.body) parentClassReference = Engine; this.parent = parentClassReference; if (!this.parent.head) { this.parent.head = CodeMaid.createDOM.Tree('header', { class: 'icon-list' }); this.parent.body.before(this.parent.head); } this.body = CodeMaid.createDOM.Tree('section', {}); this.label = CodeMaid.createDOM.Tree('label', { for: this.uid, class: 'icon', title: this.name }, [this.icon]); this.input = CodeMaid.createDOM.Tree('input', { id: this.uid, type: 'radio', name: this.parent.name, hidden: true }); this.summary = CodeMaid.createDOM.Tree('summary', {}, [this.name]); this.details = CodeMaid.createDOM.Tree('details', { open: true }, [this.summary, this.body]); if (this.parent.head.firstChild) { switch (position) { case 'first_before': this.parent.head.firstChild.before(this.label); break; case 'first_after': this.parent.head.firstChild.after(this.label); break; case 'last_before': this.parent.head.lastChild.before(this.label); break; case 'last_after': this.parent.head.lastChild.after(this.label); break; default: break; } } else { this.parent.head.append(this.label); } this.parent.body.append(this.input); this.parent.body.append(this.details); } destroy() { this.label.remove(); this.input.remove(); this.body.remove(); this.summary.remove(); this.details.remove(); delete this; } setIcon(icon) { this.icon = icon; this.label.childNodes.forEach((n) => n.remove()); if (typeof icon == 'string') this.label.innerHTML = icon; else this.label.append(icon); } log(level, message) { Cheat.log(level, message); } } /** * Component for YouTube Engine * BypassBrushSizeLimit does exactly that * Enable this via the user interface * Bypasses the default brush size */ class BypassBrushSizeLimit extends Cheat { static dummy = Cheat.bind(this, 'main'); constructor(parentClassReference) { super(parentClassReference); this.setIcon(CodeMaid.createDOM.FA('<i class="fas fa-brush"></i>')); this.init(); } init() { this.drawwidthrangeSlider = document.querySelector('#drawwidthrange'); this.#row1(); this.enable(); } enable() { this.active = true; this.drawwidthrangeSlider.parentElement.style.display = 'flex'; this.drawwidthrangeSlider.max = 45; this.drawwidthrangeSlider.min = -1000; this.enableButton.classList.add('active'); this.enableButton.textContent = 'Active'; this.log('ok', `Liked My Videos? Yes`); } disable() { this.active = false; this.drawwidthrangeSlider.max = 45; this.drawwidthrangeSlider.min = -50; this.enableButton.classList.remove('active'); this.enableButton.textContent = 'Inactive'; this.log('warn', `Awww Like Now :(, Disabled`); } #row1() { let self = this; let row = CodeMaid.createDOM.Row(); { this.enableButton = CodeMaid.createDOM.Button('Enable'); this.enableButton.addEventListener('click', function (event) { self.active ? self.disable() : self.enable(); }); row.append(this.enableButton); } this.body.append(row); } } /** * Component for YouTube Engine * BypassStickerSizeLimit does exactly that (again) * Enable this via the user interface * Bypasses the default sticker size */ class BypassStickerSizeLimit extends Cheat { static dummy = Cheat.bind(this, 'main'); constructor(parentClassReference) { super(parentClassReference); this.active = false; this.setIcon(CodeMaid.createDOM.FA('<i class="fas fa-box-open"></i>')); this.init(); } init() { let self = this; { let target = document.querySelector('.fa-parachute-box').parentElement; let resizeObserver = new MutationObserver(function (mutations) { if (self.active) if (mutations[0].target.disabled) { mutations[0].target.disabled = ''; } }); resizeObserver.observe(target, { attributes: true, }); } this.#row1(); this.enable(); } enable() { this.active = true; this.enableButton.classList.add('active'); this.enableButton.textContent = 'Active'; this.log('ok', `Subscribed YouTubeDrawaria? Yes`); } disable() { this.active = false; this.enableButton.classList.remove('active'); this.enableButton.textContent = 'Inactive'; this.log('warn', `Awww Subscribe Now :(, Disabled`); } #row1() { let self = this; let row = CodeMaid.createDOM.Row(); { this.enableButton = CodeMaid.createDOM.Button('Enable'); this.enableButton.addEventListener('click', function (event) { self.active ? self.disable() : self.enable(); }); row.append(this.enableButton); } this.body.append(row); } } /** * Component for YouTube Engine * Player as the name suggests is a slightly updated version to Player Engine v2 * Spawn a Player you can control * Accessible through console or with the User Interface component */ class Player { static dummy = Cheat.bind(this, this.name); static emit = function (socket_id, event, data) { try { SocketSpy[socket_id]?.send(emits[event](...data)); } catch (error) { console.error(error); } }; constructor(name = '', avatar = ['', '']) { this.name = name; this.avatar = avatar; this.room = { id: null, type: 2, server: null, players: [], }; this.heart = { beatFrequency: 25000, isBeating: false, id: 0, }; this.attributes = { spawned: false, rounded: false, status: false }; this.socket = null; } connect(inviteLink = null) { if (this.socket?.readyState == 1) return this.join(inviteLink); if (!this.room.id) this.room.id = getRoomId(inviteLink); let url_ = this.room.server ? this.room.server : getWSServerFromRoomId(inviteLink); this.socket = new WebSocket(url_); this.socket.addEventListener('message', this.messageManager.bind(this)); this.socket.addEventListener('open', () => { this.heart.isBeating = true; this.stayAlive(); }); this.socket.addEventListener('close', () => { this.disconnect(); }); } disconnect() { clearInterval(this.heart.id); this.heart.isBeating = !1; this.socket?.close(); } stayAlive() { this.heart.id = setInterval(() => { if (!this.heart.isBeating) { this.disconnect(); } else { this.socket.send(2); } }, this.heart.beatFrequency); } join(inviteLink) { this.room.id = getRoomId(inviteLink); this.room.server = getWSServerFromRoomId(inviteLink); if (this.socket?.readyState != 1) return; this.socket?.send(41); this.socket?.send(40); } exit() { if (this.socket?.readyState != 1) return; this.socket?.send(41); } emit(event, ...data) { this.socket?.send(emits[event](...data)); } messageManager(data) { if (data.data.startsWith('0')) return; let pos = data.data.indexOf('['); if (!~pos) { if (data.data == 40) { this.socket.send(emits.startplay(this.room, this.name, this.avatar)); } else if (data.data == 45) { // this.disconnect(); // this.connect(); } return; } let code = data.data.slice(0, pos); let message = JSON.parse(data.data.slice(pos)); if (code == 430) { this.room.players = message[0].players; } if (message[0] == 'mc_roomplayerschange') { this.room.players = message[3]; } // console.log(code, message); } } /** * Component for YouTube Engine * PlayerControls is your UserInterface * Will automatically activate * Control your Player with the installed components */ class PlayerControls extends Cheat { static dummy = Cheat.bind(this, 'main'); constructor(parentClassReference, position) { super(parentClassReference, position); this.bot = new Player(Date.now().toString(16).slice(-6), ['', '']); this.avatar_img = CodeMaid.createDOM.Tree('img', { src: '/avatar/cache/default.jpg', style: 'height: 100%; width: 100%;', }); this.setIcon(this.avatar_img); } } /** * Component for YouTube Engine * PlayerConnect manages your Player via User Interface * connect / disconnect to server * join / exit room */ class PlayerConnect extends Cheat { static dummy = Cheat.bind(this, 'PlayerControls'); constructor(parentClassReference, position) { super(parentClassReference, position); this.setIcon(CodeMaid.createDOM.FA('<i class="fas fa-network-wired"></i>')); this.init(); } init() { this.#row1(); this.#row2(); } #row1() { let self = this; let row = CodeMaid.createDOM.Row(); // Create { } // Enter { let enterRoom_button = CodeMaid.createDOM.Button('Join'); enterRoom_button.addEventListener('click', function (event) { self.parent.bot.connect(); self.parent.bot.join(document.querySelector('#invurl').value); }); row.append(enterRoom_button); } // Switch { } // Leave { let leaveRoom_button = CodeMaid.createDOM.Button('Exit'); leaveRoom_button.addEventListener('click', function (event) { self.parent.bot.exit(); self.parent.bot.disconnect(); }); row.append(leaveRoom_button); } self.body.append(row); } #row2() { let self = this; let row = CodeMaid.createDOM.Row(); // Update Name and Avatar { const id = CodeMaid.generate.uuidv4(); let change_avatar_label = CodeMaid.createDOM.Tree('label', { for: id, class: 'icon' }, [ CodeMaid.createDOM.FA('<i class="fas fa-upload"></i>'), ]); let changeAvatar_input = CodeMaid.createDOM.Tree('input', { type: 'file', id: id, hidden: true }); function onChange() { if (!this.files || !this.files[0]) return; let myFileReader = new FileReader(); myFileReader.addEventListener('load', (e) => { let a = e.target.result.replace('image/gif', 'image/png'); fetch('https://drawaria.online/uploadavatarimage', { method: 'POST', body: 'imagedata=' + encodeURIComponent(a) + '&fromeditor=true', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, }).then((res) => res.text().then((body) => { self.parent.bot.avatar = body.split('.'); self.parent.avatar_img.src = getAvatarCacheURL(self.parent.bot.avatar); }) ); }); myFileReader.readAsDataURL(this.files[0]); } changeAvatar_input.addEventListener('change', onChange); let changeName_input = CodeMaid.createDOM.Tree('input', { type: 'text', value: self.parent.bot?.name || '', placeholder: 'Subscribe To YouTubeDrawaria😎', }); changeName_input.addEventListener('keypress', function (event) { if (event.keyCode != 13) return; self.parent.bot.name = changeName_input.value; self.parent.label.title = changeName_input.value; }); row.appendAll(change_avatar_label, changeAvatar_input, changeName_input); } self.body.append(row); } } /** * Component for YouTube Engine * PlayerSozials adds interactions to Drawaria!! 😮 * send chat messages * send Emotes * toggle player status icons * give tokkens * spawn avatar and move it around */ class PlayerSozials extends Cheat { static dummy = Cheat.bind(this, 'PlayerControls'); constructor(parentClassReference) { super(parentClassReference); this.setIcon(CodeMaid.createDOM.FA('<i class="fas fa-hand-peace"></i>')); this.init(); } init() { this.#row1(); this.#row2(); this.#row3(); this.#row4(); this.#row5(); } #row1() { let self = this; let row = CodeMaid.createDOM.Row(); { // Send Message let messageClear_button = CodeMaid.createDOM.Button('<i class="fas fa-strikethrough"></i>'); let messageSend_button = CodeMaid.createDOM.Button('<i class="fas fa-paper-plane"></i>'); let message_input = CodeMaid.createDOM.Tree('input', { type: 'text', placeholder: 'message...' }); messageClear_button.classList.add('icon'); messageSend_button.classList.add('icon'); messageClear_button.onclick = function (e) { message_input.value = ''; }; messageSend_button.onclick = function (e) { self.parent.bot.emit('chatmsg', message_input.value); }; message_input.addEventListener('keypress', function (event) { if (event.keyCode != 13) return; self.parent.bot.emit('chatmsg', message_input.value); }); row.appendAll(messageClear_button, message_input, messageSend_button); } this.body.append(row); } #row2() { let self = this; let row = CodeMaid.createDOM.RowList(); row.classList.add('nowrap'); { // Send Gesture document .querySelectorAll('#gesturespickerselector .gesturespicker-container .gesturespicker-item') .forEach(function (node, index) { let clone = node.cloneNode(true); clone.classList.add('icon'); clone.addEventListener('click', function (event) { self.parent.bot.emit('sendgesture', index); }); row.append(clone); }); } this.body.append(row); } #row3() { let self = this; let row = CodeMaid.createDOM.Row(); { // Set Status let toggleStatus_button = CodeMaid.createDOM.Button('Toggle'); toggleStatus_button.addEventListener('click', function () { self.parent.bot.attributes.status = !self.parent.bot.attributes.status; toggleStatus_button.classList[self.parent.bot.attributes.status ? 'add' : 'remove']('active'); self.parent.bot.emit('setstatusflag', 0, self.parent.bot.attributes.status); self.parent.bot.emit('setstatusflag', 1, self.parent.bot.attributes.status); self.parent.bot.emit('setstatusflag', 2, self.parent.bot.attributes.status); self.parent.bot.emit('setstatusflag', 3, self.parent.bot.attributes.status); self.parent.bot.emit('setstatusflag', 4, self.parent.bot.attributes.status); }); row.append(toggleStatus_button); } this.body.append(row); } #row4() { let self = this; let row = CodeMaid.createDOM.RowList(); row.classList.add('nowrap'); { // Send Token let listOfTokens = [ '<i class="fas fa-thumbs-up"></i>', '<i class="fas fa-heart"></i>', '<i class="fas fa-paint-brush"></i>', '<i class="fas fa-cocktail"></i>', '<i class="fas fa-hand-peace"></i>', '<i class="fas fa-feather-alt"></i>', '<i class="fas fa-trophy"></i>', '<i class="fas fa-mug-hot"></i>', '<i class="fas fa-gift"></i>', ]; listOfTokens.forEach(function (token, index) { let tokenSend_button = CodeMaid.createDOM.Button(token); tokenSend_button.classList.add('icon'); tokenSend_button.addEventListener('click', function () { self.parent.bot.room.players.forEach(function (player) { self.parent.bot.emit('settoken', player.id, index); }); }); row.append(tokenSend_button); }); } this.body.append(row); } #row5() { let self = this; let row = CodeMaid.createDOM.Row(); { // Spawn && Move Avatar let avatarPosition = { x: 0, y: 0 }; let avatarSpawn_button = CodeMaid.createDOM.Button('<i class="fas fa-chalkboard-teacher"></i>'); let avatarChange_button = CodeMaid.createDOM.Button('<i class="fas fa-retweet"></i>'); let avatarPositionX_button = CodeMaid.createDOM.Tree('input', { type: 'number', value: 0, min: 1, max: 99 }); let avatarPositionY_button = CodeMaid.createDOM.Tree('input', { type: 'number', value: 0, min: 1, max: 99 }); avatarSpawn_button.addEventListener('click', function (event) { self.parent.bot.emit('spawnavatar'); self.parent.bot.attributes.spawned = !self.parent.bot.attributes.spawned; }); avatarChange_button.addEventListener('click', function (event) { self.parent.bot.emit('setavatarprop'); self.parent.bot.attributes.rounded = !self.parent.bot.attributes.rounded; }); avatarPositionX_button.addEventListener('change', function (event) { avatarPosition.x = avatarPositionX_button.value; self.parent.bot.emit('moveavatar', avatarPosition.x, avatarPosition.y); }); avatarPositionY_button.addEventListener('change', function (event) { avatarPosition.y = avatarPositionY_button.value; self.parent.bot.emit('moveavatar', avatarPosition.x, avatarPosition.y); }); row.appendAll(avatarSpawn_button, avatarPositionX_button, avatarPositionY_button, avatarChange_button); } this.body.append(row); } } class PlayerAutoDraw extends Cheat { static dummy = Cheat.bind(this, 'PlayerControls'); constructor(parentClassReference) { super(parentClassReference); this.isdrawing = false; this.previewCanvas = document.createElement('canvas'); this.gameCanvas = document.getElementById('canvas'); this.imageDataRaw; this.canvasWidth = this.previewCanvas.width; this.canvasHeight = this.previewCanvas.height; this.executionLine = []; this.size = 4; this.fuzziness = 1; this.brushSize = 5; this.offsetX = 0; this.offsetY = 0; this.setIcon(CodeMaid.createDOM.FA('<i class="fas fa-robot"></i>')); this.init(); } init() { this.#row1(); this.#row2(); this.#row3(); } #row1() { let self = this; let row = CodeMaid.createDOM.Row(); // Update Name and Avatar { const id = CodeMaid.generate.uuidv4(); let change_avatar_label = CodeMaid.createDOM.Tree('label', { for: id, class: 'icon' }, [ CodeMaid.createDOM.FA('<i class="fas fa-upload"></i>'), ]); let changeAvatar_input = CodeMaid.createDOM.Tree('input', { type: 'file', id: id, hidden: true }); function onChange() { if (!this.files || !this.files[0]) return; let myFileReader = new FileReader(); myFileReader.addEventListener('load', (e) => { let base64 = e.target.result.replace('image/gif', 'image/png'); self.loadImage(base64); }); myFileReader.readAsDataURL(this.files[0]); } changeAvatar_input.addEventListener('change', onChange); row.appendAll(change_avatar_label, changeAvatar_input); } self.body.append(row); } #row2() { let self = this; let row = CodeMaid.createDOM.Row(); { let sizeInput = CodeMaid.createDOM.Tree('input', { type: 'number', min: 1, max: 10, value: 4 }); let fuzzyModifierInput = CodeMaid.createDOM.Tree('input', { type: 'number', min: 1, max: 10, value: 1 }); let thicknessInput = CodeMaid.createDOM.Tree('input', { type: 'number', min: 1, max: 50, value: 5 }); let offsetX = CodeMaid.createDOM.Tree('input', { type: 'number', min: 0, max: 100, value: 0 }); let offsetY = CodeMaid.createDOM.Tree('input', { type: 'number', min: 0, max: 100, value: 0 }); sizeInput.addEventListener('change', () => { self.size = sizeInput.value; }); fuzzyModifierInput.addEventListener('change', () => { self.fuzziness = fuzzyModifierInput.value; }); thicknessInput.addEventListener('change', () => { self.brushSize = thicknessInput.value; }); offsetX.addEventListener('change', () => { self.offsetX = offsetX.value; }); offsetY.addEventListener('change', () => { self.offsetY = offsetY.value; }); row.appendAll(sizeInput, fuzzyModifierInput, thicknessInput, offsetX, offsetY); } self.body.append(row); } #row3() { let self = this; let row = CodeMaid.createDOM.Row(); { let loadImageButton = CodeMaid.createDOM.Button('Load'); loadImageButton.addEventListener('click', () => { self.drawImage(self.size, self.fuzziness, self.brushSize, { x: self.offsetX, y: self.offsetY }); }); row.appendAll(loadImageButton); } { let startDrawingButton = CodeMaid.createDOM.Button('Start'); startDrawingButton.addEventListener('click', () => { self.isdrawing = true; self.execute(); }); row.appendAll(startDrawingButton); } { let stopDrawingButton = CodeMaid.createDOM.Button('Stop'); stopDrawingButton.addEventListener('click', () => { self.isdrawing = false; }); row.appendAll(stopDrawingButton); } { let resetDrawingButton = CodeMaid.createDOM.Button('Reset'); resetDrawingButton.addEventListener('click', () => { self.isdrawing = false; self.executionLine = []; }); row.appendAll(resetDrawingButton); } self.body.append(row); } loadImage(url) { // load the image var img = new Image(); img.addEventListener('load', () => { this.previewCanvas.width = this.gameCanvas.width; this.previewCanvas.height = this.gameCanvas.height; this.canvasWidth = this.previewCanvas.width; this.canvasHeight = this.previewCanvas.height; var ctx = this.previewCanvas.getContext('2d'); // center and resize image let modifier = 1; if (img.width > this.previewCanvas.width) { modifier = this.previewCanvas.width / img.width; } else { modifier = this.previewCanvas.height / img.height; } // draw the image // (this time to grab the image's pixel data ctx.drawImage(img, 0, 0, img.width * modifier, img.height * modifier); // grab the image's pixel data var imgData = ctx.getImageData(0, 0, this.previewCanvas.width, this.previewCanvas.height); this.imageDataRaw = imgData.data; // clear the canvas to draw the glow ctx.clearRect(0, 0, this.previewCanvas.width, this.previewCanvas.height); console.debug('ready'); }); img.crossOrigin = 'anonymous'; img.src = url; } drawImage(size = 4, modifier = 1, thickness = 5, offset = { x: 0, y: 0 }, ignorcolors = []) { const self = this; this.executionLine = []; for (let y = 0; y < this.canvasHeight; y += size * modifier) { let start = [0, y]; for (let x = 0; x < this.canvasHeight; x += size * modifier) { let end = [x, y]; let index = (y * this.canvasWidth + x) * 4; let a = this.imageDataRaw[index + 3]; if (a > 20) { end = [x, y]; // Is not Transparent let r = this.imageDataRaw[index + 0], g = this.imageDataRaw[index + 1], b = this.imageDataRaw[index + 2]; let color = `rgb(${r},${g},${b})`; if (!ignorcolors.includes(color)) { if (x < this.canvasWidth - 1) { let n_r = this.imageDataRaw[index + size * modifier * 4 + 4], n_g = this.imageDataRaw[index + size * modifier * 4 + 5], n_b = this.imageDataRaw[index + size * modifier * 4 + 6]; let samecolor = true; // check if the next pixel is same color as the last if ((r != n_r && g != n_g && b != n_b) || this.imageDataRaw[index + 7] < 20) { samecolor = false; } if (!samecolor) { this.executionLine.push({ pos1: self.recalculate(start, size, offset), pos2: self.recalculate(end, size, offset), color: color, thickness: thickness, }); start = [x, y]; } } else { this.executionLine.push({ pos1: self.recalculate(start, size, offset), pos2: self.recalculate(end, size, offset), color: color, thickness: thickness, }); } } } else { // Is Transparent start = [x, y]; } } } console.debug('done Loading'); } execute() { const self = this; if (!self.isdrawing) return (self.isdrawing = false); if (self.executionLine.length <= 0) return (self.isdrawing = false); const currentLine = self.executionLine.shift(); const p1 = currentLine.pos1, p2 = currentLine.pos2, color = currentLine.color, thickness = currentLine.thickness; setTimeout(() => { self.parent.bot.socket.send( `42["drawcmd",0,[${p1[0]},${p1[1]},${p2[0]},${p2[1]},false,${0 - thickness},"${color}",0,0,{}]]` ); this.execute(); }, 10); } recalculate(value, size, offset) { return [ (value[0] / (this.canvasWidth * size) + offset.x / 100).toFixed(4), (value[1] / (this.canvasHeight * size) + offset.y / 100).toFixed(4), ]; } } /** * Start the YouTube Engine! */ Engine.initialize(); // Código del botón para ocultar y mostrar el menú let toggleButton = CodeMaid.createDOM.Button('Hide/Show Menu'); toggleButton.style.position = 'absolute'; toggleButton.style.top = '10px'; toggleButton.style.right = '10px'; toggleButton.style.zIndex = 1001; toggleButton.style.background = 'linear-gradient(90deg, #ff7e5f, #feb47b, #86a8e7)'; toggleButton.style.border = 'none'; toggleButton.style.borderRadius = '5px'; toggleButton.style.color = 'white'; toggleButton.style.padding = '10px 20px'; toggleButton.style.fontSize = '16px'; toggleButton.style.cursor = 'pointer'; toggleButton.style.transition = 'background 0.3s ease-in-out, box-shadow 0.3s ease-in-out'; toggleButton.style.display = 'none'; // Inicializar el botón como oculto toggleButton.addEventListener('click', function () { let menu = document.getElementById('✅'); // Reemplaza '✅' con el ID real de tu menú if (menu.style.display === 'none') { menu.style.display = 'block'; } else { menu.style.display = 'none'; } }); toggleButton.addEventListener('mousedown', function () { toggleButton.style.background = 'linear-gradient(90deg, #ff5f6d, #feb47b, #86a8e7)'; toggleButton.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)'; }); toggleButton.addEventListener('mouseup', function () { toggleButton.style.background = 'linear-gradient(90deg, #ff7e5f, #feb47b, #86a8e7)'; toggleButton.style.boxShadow = 'none'; }); document.body.appendChild(toggleButton); // Agregar evento de clic al botón con id="roomcontrols-menu" para mostrar el botón let roomControlsMenu = document.getElementById('roomcontrols-menu'); roomControlsMenu.addEventListener('click', function () { toggleButton.style.display = 'block'; // Mostrar el botón al presionar el botón con id="roomcontrols-menu" }); })('✅', 'YouTube Engine Pro😎');