您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a download button, hides edited tags, auto-clicks "Try Again," and enables widescreen mode.
当前为
- // ==UserScript==
- // @name Chat Enhancements
- // @namespace http://tampermonkey.net/
- // @version 0.5
- // @description Adds a download button, hides edited tags, auto-clicks "Try Again," and enables widescreen mode.
- // @author InariOkami
- // @match https://character.ai/*
- // @grant none
- // @icon https://www.google.com/s2/favicons?sz=64&domain=character.ai
- // ==/UserScript==
- (async function() {
- 'use strict';
- (function() {
- function loop() {
- let elements = document.querySelectorAll("div, p");
- elements.forEach(function(val) {
- if (val.innerText === "(edited)" || val.innerText === "Edited") {
- val.style.display = 'none';
- }
- });
- requestAnimationFrame(loop);
- }
- loop();
- })();
- (function() {
- function WideScreen() {
- var Chat = document.getElementsByClassName("overflow-x-hidden overflow-y-scroll px-1 flex flex-col-reverse min-w-full hide-scrollbar").item(0).children;
- for (var i = 0; i < Chat.length; i++) {
- Chat.item(i).style = "min-width:100%";
- document.getElementsByClassName("flex w-full flex-col max-w-2xl").item(0).style = "min-width:100%";
- }
- }
- setTimeout(() => { setInterval(WideScreen, 100); }, 1000);
- })();
- function createSaveButton() {
- const saveChatButton = document.createElement('button');
- saveChatButton.innerHTML = 'Chat Options ▼';
- saveChatButton.style.position = 'fixed';
- saveChatButton.style.top = localStorage.getItem('buttonTop') || '10px';
- saveChatButton.style.left = localStorage.getItem('buttonLeft') || '10px';
- saveChatButton.style.backgroundColor = '#ff0000';
- saveChatButton.style.color = '#ffffff';
- saveChatButton.style.padding = '10px';
- saveChatButton.style.borderRadius = '5px';
- saveChatButton.style.cursor = 'pointer';
- saveChatButton.style.zIndex = '1000';
- saveChatButton.style.border = 'none';
- saveChatButton.style.boxShadow = '0px 2px 5px rgba(0,0,0,0.2)';
- document.body.appendChild(saveChatButton);
- const dropdown = document.createElement('div');
- dropdown.style.display = 'none';
- dropdown.style.position = 'absolute';
- dropdown.style.top = '100%';
- dropdown.style.left = '0';
- dropdown.style.backgroundColor = '#333';
- dropdown.style.border = '1px solid #ccc';
- dropdown.style.boxShadow = '0px 2px 5px rgba(0,0,0,0.2)';
- dropdown.style.zIndex = '1001';
- dropdown.style.color = '#ffffff';
- dropdown.style.fontFamily = 'sans-serif';
- dropdown.style.fontSize = '14px';
- dropdown.style.padding = '5px';
- dropdown.style.cursor = 'pointer';
- dropdown.style.maxWidth = '200px';
- dropdown.style.borderRadius = '5px';
- saveChatButton.appendChild(dropdown);
- const downloadButton = document.createElement('button');
- downloadButton.innerHTML = 'Download Chat';
- downloadButton.style.display = 'block';
- downloadButton.style.width = '100%';
- downloadButton.style.border = 'none';
- downloadButton.style.padding = '10px';
- downloadButton.style.cursor = 'pointer';
- downloadButton.style.backgroundColor = '#444';
- downloadButton.style.color = '#ffffff';
- downloadButton.style.borderRadius = '5px';
- dropdown.appendChild(downloadButton);
- saveChatButton.onclick = function() {
- dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
- };
- let offsetX, offsetY;
- let isDragging = false;
- saveChatButton.addEventListener('mousedown', function(e) {
- isDragging = true;
- offsetX = e.clientX - saveChatButton.getBoundingClientRect().left;
- offsetY = e.clientY - saveChatButton.getBoundingClientRect().top;
- });
- document.addEventListener('mousemove', function(e) {
- if (isDragging) {
- saveChatButton.style.left = e.clientX - offsetX + 'px';
- saveChatButton.style.top = e.clientY - offsetY + 'px';
- localStorage.setItem('buttonTop', saveChatButton.style.top);
- localStorage.setItem('buttonLeft', saveChatButton.style.left);
- }
- });
- document.addEventListener('mouseup', function() {
- isDragging = false;
- });
- return { saveChatButton, dropdown, downloadButton };
- }
- async function fetchAndDownloadChat() {
- var token = JSON.parse(document.getElementById("__NEXT_DATA__").innerHTML).props.pageProps.token;
- var _cache;
- async function _fetchchats(charid) {
- if (!_cache) {
- let url = 'https://neo.character.ai/chats/recent/' + charid;
- let response = await fetch(url, { headers: { "Authorization": `Token ${token}` } });
- let json = await response.json();
- _cache = json['chats'];
- }
- return _cache;
- }
- async function getChats(charid) {
- let json = await _fetchchats(charid);
- return json.map(chat => chat.chat_id);
- }
- async function getMessages(chat, format) {
- let url = 'https://neo.character.ai/turns/' + chat + '/';
- let next_token = null;
- let turns = [];
- do {
- let url2 = url;
- if (next_token) url2 += "?next_token=" + encodeURIComponent(next_token);
- let response = await fetch(url2, { headers: { "Authorization": `Token ${token}` } });
- let json = await response.json();
- for (let turn of json['turns']) {
- let o = {};
- o.author = format === "definition" ? (turn.author.is_human ? "{{user}}" : "{{char}}") : turn.author.name;
- o.message = turn.candidates.find(x => x.candidate_id === turn.primary_candidate_id).raw_content || "";
- turns.push(o);
- }
- next_token = json['meta']['next_token'];
- } while (next_token);
- return turns.reverse();
- }
- async function downloadChat(format) {
- let charid = prompt('Enter character ID:');
- let chats = await getChats(charid);
- let messages = await getMessages(chats[0], format);
- let content = messages.map(msg => `${msg.author}: ${msg.message}`).join('\n');
- let blob = new Blob([content], { type: 'text/plain' });
- let link = document.createElement('a');
- link.href = URL.createObjectURL(blob);
- link.download = `chat_${charid}.txt`;
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- }
- const dialog = document.createElement('dialog');
- dialog.innerHTML = `
- <form method="dialog">
- <p>Select format:</p>
- <label><input type="radio" name="format" value="definition" checked> Definition ({{user}}/{{char}})</label><br>
- <label><input type="radio" name="format" value="names"> Names (You/Bot)</label><br>
- <button type="submit">Download</button>
- </form>
- `;
- dialog.addEventListener('close', () => {
- const format = dialog.querySelector('input[name="format"]:checked').value;
- downloadChat(format);
- });
- document.body.appendChild(dialog);
- let { downloadButton } = createSaveButton();
- downloadButton.onclick = function() {
- dialog.showModal();
- };
- }
- fetchAndDownloadChat();
- })();