您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Replace char avatar in chats with storage, chat-specific.
当前为
// ==UserScript== // @name CAI CharPic replacer // @namespace http://tampermonkey.net/ // @version 1.0 // @description Replace char avatar in chats with storage, chat-specific. // @match https://character.ai/chat/* // @grant none // @author LuxTallis // @license MIT // ==/UserScript== (function () { 'use strict'; const TARGET_IMAGE_BASE_URL = "https://characterai.io/i/400/static/avatars/uploaded/"; const BROADER_SELECTOR = 'div.group img.object-cover'; // Broad selector for images in div.group const EXCLUDED_SELECTOR = '.flex-row-reverse img.object-cover.object-top'; // Specific selector to exclude // Get the current chat identifier from the URL function getCurrentChatId() { const match = window.location.pathname.match(/\/chat\/([^\/]+)/); return match ? match[1] : null; } // Save a custom image URL for the current chat function saveCustomImageUrlForChat(chatId, url) { const chatImages = JSON.parse(localStorage.getItem('chat_images') || '{}'); chatImages[chatId] = url; localStorage.setItem('chat_images', JSON.stringify(chatImages)); addToLibrary(url); // Add to the recent library } // Get the custom image URL for the current chat function getCustomImageUrlForChat(chatId) { const chatImages = JSON.parse(localStorage.getItem('chat_images') || '{}'); return chatImages[chatId] || ''; } // Add image to the library of recent images function addToLibrary(url) { const library = getLibrary(); if (!url || library.includes(url)) return; library.push(url); if (library.length > 10) library.shift(); // Limit library to 10 images saveLibrary(library); } // Save the image library to local storage function saveLibrary(library) { localStorage.setItem('image_library', JSON.stringify(library)); } // Get the image library from local storage function getLibrary() { return JSON.parse(localStorage.getItem('image_library') || '[]'); } // Replace images with the custom URL for the current chat, excluding unwanted elements function replaceImagesForChat(customUrl) { const images = document.querySelectorAll(BROADER_SELECTOR); images.forEach((image) => { // Skip images matching the excluded selector if (image.closest(EXCLUDED_SELECTOR)) return; if (image.src.startsWith(TARGET_IMAGE_BASE_URL)) { image.src = customUrl; } }); } // Create the button const button = document.createElement('button'); button.innerHTML = '👤'; button.style.position = 'fixed'; button.style.top = '110px'; // Positioned below the background script button button.style.right = '5px'; button.style.width = '22px'; button.style.height = '22px'; button.style.backgroundColor = '#444'; button.style.color = 'white'; button.style.border = 'none'; button.style.borderRadius = '3px'; button.style.cursor = 'pointer'; button.style.fontFamily = 'Montserrat, sans-serif'; button.style.display = 'flex'; button.style.justifyContent = 'center'; button.style.alignItems = 'center'; button.style.zIndex = '9999'; // Add the button to the document document.body.appendChild(button); // Add functionality to set a new image URL for the current chat button.addEventListener('click', () => { const chatId = getCurrentChatId(); if (!chatId) { alert('Could not determine the chat ID.'); return; } // Create popup panel const popup = document.createElement('div'); popup.id = 'imagePopup'; popup.style.position = 'fixed'; popup.style.top = '50%'; popup.style.left = '50%'; popup.style.transform = 'translate(-50%, -50%)'; popup.style.backgroundColor = '#1e1e1e'; popup.style.color = 'white'; popup.style.borderRadius = '5px'; popup.style.padding = '20px'; popup.style.zIndex = '9999'; popup.style.fontFamily = 'Montserrat, sans-serif'; popup.style.minWidth = '300px'; popup.style.maxWidth = '500px'; const label = document.createElement('label'); label.textContent = 'Enter Image URL:'; label.style.display = 'block'; label.style.marginBottom = '5px'; const input = document.createElement('input'); input.type = 'text'; input.placeholder = 'Enter image URL'; input.style.width = '100%'; input.style.marginBottom = '10px'; const applyButton = document.createElement('button'); applyButton.textContent = 'Apply Image'; applyButton.style.marginTop = '10px'; applyButton.style.padding = '5px 10px'; applyButton.style.border = 'none'; applyButton.style.borderRadius = '3px'; applyButton.style.backgroundColor = '#444'; applyButton.style.color = 'white'; applyButton.style.fontFamily = 'Montserrat, sans-serif'; applyButton.addEventListener('click', () => { const url = input.value.trim(); if (url) { saveCustomImageUrlForChat(chatId, url); replaceImagesForChat(url); popup.remove(); } }); // Default button (Revert to Default) const defaultButton = document.createElement('button'); defaultButton.textContent = 'Default'; defaultButton.style.marginTop = '10px'; defaultButton.style.padding = '5px 10px'; defaultButton.style.border = 'none'; defaultButton.style.borderRadius = '3px'; defaultButton.style.backgroundColor = '#444'; // Same as Apply button defaultButton.style.color = 'white'; defaultButton.style.fontFamily = 'Montserrat, sans-serif'; defaultButton.style.marginLeft = 'auto'; // Align to the right defaultButton.style.cursor = 'pointer'; defaultButton.addEventListener('click', () => { saveCustomImageUrlForChat(chatId, ''); // Clear the custom URL replaceImagesForChat(''); popup.remove(); }); // Library for recent images const libraryContainer = document.createElement('div'); libraryContainer.style.marginTop = '10px'; libraryContainer.style.overflowX = 'auto'; libraryContainer.style.display = 'flex'; libraryContainer.style.flexWrap = 'wrap'; // Allow wrapping into multiple lines libraryContainer.style.gap = '15px'; // Increased gap between thumbnails libraryContainer.style.paddingBottom = '10px'; libraryContainer.style.borderTop = '1px solid #555'; libraryContainer.style.paddingTop = '10px'; const library = getLibrary(); library.forEach((url) => { const imgContainer = document.createElement('div'); imgContainer.style.position = 'relative'; imgContainer.style.flex = '0 0 auto'; // Ensures the thumbnail stays at its natural width const img = document.createElement('img'); img.src = url; img.alt = 'Preview'; img.style.width = '100px'; // Twice the size of the previous thumbnails img.style.height = '100px'; img.style.objectFit = 'cover'; img.style.border = '1px solid #fff'; img.style.borderRadius = '3px'; img.style.cursor = 'pointer'; img.title = url; img.addEventListener('click', () => { saveCustomImageUrlForChat(chatId, url); replaceImagesForChat(url); popup.remove(); }); // Red remove button in the top-right corner const removeButton = document.createElement('button'); removeButton.textContent = '×'; removeButton.style.position = 'absolute'; removeButton.style.top = '5px'; removeButton.style.right = '5px'; removeButton.style.backgroundColor = 'red'; removeButton.style.color = 'white'; removeButton.style.border = 'none'; removeButton.style.borderRadius = '50%'; removeButton.style.cursor = 'pointer'; removeButton.style.width = '20px'; removeButton.style.height = '20px'; removeButton.style.textAlign = 'center'; removeButton.style.fontSize = '12px'; removeButton.addEventListener('click', (e) => { e.stopPropagation(); // Prevents bubbling up to img's click event removeFromLibrary(url); renderLibrary(); // Refresh the library after removal }); imgContainer.appendChild(img); imgContainer.appendChild(removeButton); libraryContainer.appendChild(imgContainer); }); // Function to remove an image from the library function removeFromLibrary(url) { const library = getLibrary().filter((item) => item !== url); saveLibrary(library); } // Function to render the updated library view function renderLibrary() { libraryContainer.innerHTML = ''; // Clear current library const library = getLibrary(); library.forEach((url) => { const imgContainer = document.createElement('div'); imgContainer.style.position = 'relative'; imgContainer.style.flex = '0 0 auto'; const img = document.createElement('img'); img.src = url; img.alt = 'Preview'; img.style.width = '100px'; img.style.height = '100px'; img.style.objectFit = 'cover'; img.style.border = '1px solid #fff'; img.style.borderRadius = '3px'; img.style.cursor = 'pointer'; img.title = url; img.addEventListener('click', () => { saveCustomImageUrlForChat(chatId, url); replaceImagesForChat(url); popup.remove(); }); const removeButton = document.createElement('button'); removeButton.textContent = '×'; removeButton.style.position = 'absolute'; removeButton.style.top = '5px'; removeButton.style.right = '5px'; removeButton.style.backgroundColor = 'red'; removeButton.style.color = 'white'; removeButton.style.border = 'none'; removeButton.style.borderRadius = '50%'; removeButton.style.cursor = 'pointer'; removeButton.style.width = '20px'; removeButton.style.height = '20px'; removeButton.style.textAlign = 'center'; removeButton.style.fontSize = '12px'; removeButton.addEventListener('click', (e) => { e.stopPropagation(); removeFromLibrary(url); renderLibrary(); }); imgContainer.appendChild(img); imgContainer.appendChild(removeButton); libraryContainer.appendChild(imgContainer); }); } popup.appendChild(label); popup.appendChild(input); popup.appendChild(applyButton); popup.appendChild(defaultButton); popup.appendChild(libraryContainer); document.body.appendChild(popup); // Close the popup if clicked outside document.addEventListener('click', function closeOnOutsideClick(event) { if (!popup.contains(event.target) && !button.contains(event.target)) { popup.remove(); document.removeEventListener('click', closeOnOutsideClick); } }); }); // Load and apply custom image for the current chat const chatId = getCurrentChatId(); const savedImageUrl = getCustomImageUrlForChat(chatId); if (savedImageUrl) { replaceImagesForChat(savedImageUrl); } })();