您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds new custom emojis to Drawaria.online avatar builder and attempts to save them to the profile when clicked.
// ==UserScript== // @name Drawaria.online Custom Emojis! :3 // @namespace http://tampermonkey.net/ // @version 1.0 // @description Adds new custom emojis to Drawaria.online avatar builder and attempts to save them to the profile when clicked. // @author YouTubeDrawaria // @match *://drawaria.online/* // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // @grant none // @license MIT // ==/UserScript== (function($, undefined) { // jQuery noConflict wrapper 'use strict'; // --- CONFIGURATION --- const newCustomEmojis = [ // Emojis anteriores que se conservan (Mono original eliminado) { name: 'Ghost', id: 'custom_face_ghost', url: 'https://i.ibb.co/G4rcDxtr/5b17de15-3964-46ec-8af9-f5980940123b-removebg-preview.png' }, { name: 'Dog', id: 'custom_face_dog', url: 'https://i.ibb.co/3mJvGWng/dog-face-removebg-preview.png' }, // Nuevos emojis agregados { name: 'Monkey', id: 'custom_face_monkey_new', url: 'https://i.postimg.cc/mDkXk9Rs/monkey-face-removebg-preview.png' }, { name: 'Demon', id: 'custom_face_demon', url: 'https://i.postimg.cc/7Y3ppgZs/smiling-face-with-horns-removebg-preview.png' }, { name: 'Exploding Head', id: 'custom_face_exploding_head', url: 'https://emojiisland.com/cdn/shop/products/7_large.png' }, { name: 'OMG Face', id: 'custom_face_omg', url: 'https://emojiisland.com/cdn/shop/products/OMG_Emoji_Icon_0cda9b05-20a8-47f0-b80f-df5c982e0963_large.png' }, { name: 'Tears Face', id: 'custom_face_tears', url: 'https://emojiisland.com/cdn/shop/products/Tears_Emoji_Icon_2_large.png?v=1571606092' }, { name: 'Pumpkin', id: 'custom_face_pumpkin', url: 'https://emojiisland.com/cdn/shop/products/Pumpkin_Emoji_Icon_169be5a5-3354-4573-b327-5d69e23e8458_large.png' }, { name: 'Cold Face', id: 'custom_face_cold', url: 'https://emojiisland.com/cdn/shop/products/9_large.png' }, { name: 'Hot Face', id: 'custom_face_hot', url: 'https://emojiisland.com/cdn/shop/products/8_large.png' }, { name: 'Raised Eyebrow', id: 'custom_face_raised_eyebrow', url: 'https://i.ibb.co/v6xdzRnm/original-removebg-preview.png' }, { name: 'Nerd Face', id: 'custom_face_nerd', url: 'https://emojiisland.com/cdn/shop/products/Nerd_Emoji_Icon_4ab932f8-9ec9-4180-8420-c74b84546f57_large.png' }, { name: 'Poop Face', id: 'custom_face_poop', url: 'https://emojiisland.com/cdn/shop/products/Poop_Emoji_2_large.png?v=1571606092' } ]; const customCategoryName = "Custom Faces"; const knownExistingCategoryText = "FACE"; // O "EYE", "MOUTH". Se usa como ancla. const customCategoryMarkerAttribute = "data-custom-category-scripted"; const customEmojiMarkerAttribute = "data-custom-emoji-scripted"; // --- END CONFIGURATION --- let customCategoryAdded = false; let observer = null; function log(message, data) { console.log(`[Drawaria Custom Emojis v0.9.1] ${message}`, data || ''); } function warn(message, data) { console.warn(`[Drawaria Custom Emojis v0.9.1] ${message}`, data || ''); } function error(message, data) { console.error(`[Drawaria Custom Emojis v0.9.1] ${message}`, data || ''); } function cloneAndModifyAssetLi(emojiData, templateAssetLi) { if (!templateAssetLi) { error('No templateAssetLi provided for cloning!'); const newItem = document.createElement('li'); const img = document.createElement('img'); newItem.title = emojiData.name; img.src = emojiData.url; img.alt = emojiData.name; img.className = 'asset'; img.draggable = false; img.style.objectFit = 'contain'; newItem.appendChild(img); newItem.setAttribute(customEmojiMarkerAttribute, 'true'); newItem.setAttribute('data-custom-emoji-id', emojiData.id); newItem.addEventListener('click', (event) => { event.stopPropagation(); event.preventDefault(); handleCustomEmojiClick(emojiData, newItem); }); return newItem; } const newItem = templateAssetLi.cloneNode(true); newItem.title = emojiData.name; const img = newItem.querySelector('img'); if (img) { img.src = emojiData.url; img.alt = emojiData.name; if (!img.style.objectFit) img.style.objectFit = 'contain'; if (img.draggable === undefined) img.draggable = false; if (img.srcset) img.srcset = ''; } else { warn('Template asset li did not contain an img. Creating one.'); const newImg = document.createElement('img'); newImg.src = emojiData.url; newImg.alt = emojiData.name; newImg.className = 'asset'; newImg.draggable = false; newImg.style.objectFit = 'contain'; newItem.innerHTML = ''; newItem.appendChild(newImg); } newItem.id = ''; newItem.setAttribute(customEmojiMarkerAttribute, 'true'); newItem.setAttribute('data-custom-emoji-id', emojiData.id); newItem.onclick = null; newItem.addEventListener('click', (event) => { event.stopPropagation(); event.preventDefault(); handleCustomEmojiClick(emojiData, newItem); }); return newItem; } function cloneAndModifyCategoryHeaderLi(categoryName, templateCategoryLi) { if (!templateCategoryLi) { error('No templateCategoryLi provided for cloning!'); const newHeader = document.createElement('li'); newHeader.className = 'category'; newHeader.textContent = categoryName; newHeader.setAttribute(customCategoryMarkerAttribute, 'true'); return newHeader; } const newHeader = templateCategoryLi.cloneNode(true); newHeader.textContent = categoryName; newHeader.id = ''; newHeader.setAttribute(customCategoryMarkerAttribute, 'true'); return newHeader; } function handleCustomEmojiClick(emojiData, clickedLiElement) { log(`Clicked ${emojiData.name}, URL: ${emojiData.url}`); const avatarPreviewImg = document.querySelector('.Panel.preview img.AvatarImage, .Panel.preview img'); if (avatarPreviewImg) { avatarPreviewImg.src = emojiData.url; log('Avatar preview image updated.'); } else { warn('Avatar preview image element not found.'); } if (window.ACCOUNT_AVATARSAVE && typeof window.ACCOUNT_AVATARSAVE === 'object') { window.ACCOUNT_AVATARSAVE.face = emojiData.id; log('Attempted to update ACCOUNT_AVATARSAVE.face to:', window.ACCOUNT_AVATARSAVE.face); log('Current ACCOUNT_AVATARSAVE:', JSON.stringify(window.ACCOUNT_AVATARSAVE)); } else { warn('window.ACCOUNT_AVATARSAVE not found or not an object. Saving might fail or use default face.'); if (!window.ACCOUNT_AVATARSAVE) { window.ACCOUNT_AVATARSAVE = { face: emojiData.id, eye: 0, mouth: 0, acc: 0 }; warn('Initialized a basic ACCOUNT_AVATARSAVE. This might be incorrect.'); } } const parentUl = clickedLiElement.closest('ul'); if (parentUl) { parentUl.querySelectorAll('li.active').forEach(activeLi => activeLi.classList.remove('active')); } clickedLiElement.classList.add('active'); log('Fetching image data to prepare for save...'); fetch(emojiData.url) .then(response => { if (!response.ok) { throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`); } return response.blob(); }) .then(blob => { const reader = new FileReader(); reader.onloadend = function() { let base64ImageData = reader.result; if (blob.type && blob.type !== 'image/jpeg') { log(`Image type is ${blob.type}. Using as is or converting for backend if needed.`); } else { base64ImageData = reader.result.replace(/^data:[^;]+;/, 'data:image/jpeg;'); } log('Image data fetched and converted to base64. Triggering save.'); triggerSaveWithImageData(base64ImageData); }; reader.onerror = function() { error('FileReader failed to read image blob.'); alert('Error preparing image for save. Could not read image data.'); }; reader.readAsDataURL(blob); }) .catch(err => { error('Failed to fetch or process custom emoji image for saving.', err); alert(`Error fetching image: ${err.message}`); }); } function triggerSaveWithImageData(base64ImageData) { if (!window.LOGGEDIN) { alert("Error: You must be logged in to save your avatar."); warn("Save attempt aborted: User not logged in."); return; } if (!window.ACCOUNT_AVATARSAVE) { alert("Error: Avatar configuration is missing. Cannot save."); warn("Save attempt aborted: ACCOUNT_AVATARSAVE is null/undefined."); return; } log('Saving avatar with custom image data...'); const console_log_save_status = (text) => log(`Save Status: ${text}`); console_log_save_status('Uploading...'); $.ajax({ url: LOGGEDIN ? '/saveavatar' : '/uploadavatarimage', type: 'POST', data: { 'avatarsave_builder': JSON.stringify(ACCOUNT_AVATARSAVE), 'imagedata': base64ImageData, 'fromeditor': true }, xhr: ()=> { var xhr = new window.XMLHttpRequest(); xhr.upload.addEventListener('progress', evt => { if (evt.lengthComputable) { var percentComplete = (evt.loaded / evt.total) * 100; log(`Upload Progress: ${percentComplete.toFixed(0)}%`); } }, false); return xhr; } }).done(data => { console_log_save_status('Saving...'); log('Avatar data sent, server responded with cache key:', data); fetch(`${location.origin}/avatar/cache/${data}.jpg`, { method: 'GET', mode: 'cors', cache: 'reload' }) .then(response => { if (!response.ok) throw new Error(`Failed to fetch cached avatar: ${response.statusText}`); return response.blob(); }) .then(() => { console_log_save_status('Save OK!'); log('Avatar saved and cache confirmed! Redirecting to origin.'); location.href = new URL(location.href).origin; }) .catch(err => { error('Error confirming saved avatar from cache.', err); console_log_save_status('Save attempt finished, but cache confirmation failed.'); alert(`Avatar might be saved, but confirmation failed: ${err.message}. Please check your profile.`); }); }).fail((jqXHR, textStatus, errorThrown) => { error('$.ajax save request failed.', { status: textStatus, error: errorThrown, response: jqXHR.responseText }); console_log_save_status('Upload Image'); alert(`Failed to save avatar: ${errorThrown || textStatus}. Server response: ${jqXHR.responseText}`); }); } function findTargetListAndTemplates() { const allElements = document.querySelectorAll('body *'); let knownCategoryElement = null; for (let el of allElements) { if (el.childNodes.length === 1 && el.firstChild.nodeType === Node.TEXT_NODE && el.firstChild.textContent.trim().toUpperCase() === knownExistingCategoryText) { knownCategoryElement = el; break; } if (el.textContent.trim().toUpperCase() === knownExistingCategoryText && el.children.length < 2) { if (['LI', 'DIV', 'SPAN', 'H3', 'H4', 'P'].includes(el.tagName)) { knownCategoryElement = el; break; } } } if (!knownCategoryElement) return null; log(`Found element containing "${knownExistingCategoryText}":`, knownCategoryElement); let targetListElement = knownCategoryElement.closest('ul'); if (!targetListElement) { if (knownCategoryElement.tagName === 'LI' && knownCategoryElement.parentElement.tagName === 'UL') { targetListElement = knownCategoryElement.parentElement; } else { let parentCandidate = knownCategoryElement.parentElement; let searchDepth = 0; while (parentCandidate && searchDepth < 5 && !targetListElement) { targetListElement = parentCandidate.querySelector('ul'); if(targetListElement && targetListElement.querySelector('li.category')) break; targetListElement = null; parentCandidate = parentCandidate.parentElement; searchDepth++; } } } if (!targetListElement) { warn('Could not find the main <ul> list.'); return null; } log('Found target <ul> list element:', targetListElement); const templateCategoryLi = targetListElement.querySelector('li.category'); const templateAssetLi = targetListElement.querySelector('li:not(.category)'); if (!templateCategoryLi) { warn('Template for category header (li.category) not found.'); return null; } if (!templateAssetLi) { warn('Template for asset item (li:not(.category)) not found.'); return null; } log('Found templates: Category LI, Asset LI', { templateCategoryLi, templateAssetLi }); return { targetListElement, templateCategoryLi, templateAssetLi }; } function attemptToAddCustomEmojis() { if (customCategoryAdded) { if (observer) observer.disconnect(); log('Custom category already added. Observer disconnected.'); return true; } const result = findTargetListAndTemplates(); if (!result) return false; const { targetListElement, templateCategoryLi, templateAssetLi } = result; if (targetListElement.querySelector(`li[${customCategoryMarkerAttribute}="true"]`)) { log('Custom category already exists in the list. Finalizing.'); customCategoryAdded = true; if (observer) observer.disconnect(); return true; } log('Adding new category and emojis to the list.'); const newHeader = cloneAndModifyCategoryHeaderLi(customCategoryName, templateCategoryLi); targetListElement.appendChild(newHeader); newCustomEmojis.forEach(emoji => { const newLi = cloneAndModifyAssetLi(emoji, templateAssetLi); targetListElement.appendChild(newLi); }); log(`Successfully added "${customCategoryName}" category with ${newCustomEmojis.length} emojis.`); customCategoryAdded = true; if (observer) observer.disconnect(); return true; } function startObserver() { if (observer) observer.disconnect(); observer = new MutationObserver((mutationsList, obs) => { if (attemptToAddCustomEmojis()) { obs.disconnect(); observer = null; } }); observer.observe(document.documentElement, { childList: true, subtree: true }); log('MutationObserver started.'); setTimeout(() => { if (!customCategoryAdded) { log("Initial attempt to add emojis after a longer delay."); // Increased delay for initial attempt attemptToAddCustomEmojis(); } }, 2500); // Increased delay for initial attempt } function onPageReady(callback) { if (document.readyState === 'complete' || (document.readyState !== 'loading' && !document.documentElement.doScroll)) { setTimeout(callback, 750); } else { document.addEventListener('DOMContentLoaded', () => setTimeout(callback, 1000)); window.addEventListener('load', () => setTimeout(callback, 2000)); } } if (typeof $ === 'undefined') { error("jQuery is not loaded. Script will not function correctly. Ensure @require is working."); return; } $(() => { log("jQuery ready. Script starting main logic."); onPageReady(() => { if (window.location.pathname.includes('/avatar/builder')) { log('Avatar builder page detected. Initializing script.'); if (typeof window.LOGGEDIN === 'undefined') { warn('window.LOGGEDIN is undefined. Saving will likely fail or be treated as guest.'); } if (typeof window.ACCOUNT_AVATARSAVE === 'undefined') { warn('window.ACCOUNT_AVATARSAVE is undefined. This variable is needed for saving existing avatar parts.'); } startObserver(); } else { log('Not on avatar builder page. Script will not actively modify DOM.'); } }); }); })(window.jQuery);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址