// ==UserScript== // @name c.ai X Swipes // @namespace c.ai X Swipes // @version 2.1 // @description A toggleable panel with the swipes of the current turn // @author Vishanka via chatGPT // @license MIT // @match https://*.character.ai/chat* // @icon https://i.imgur.com/iH2r80g.png // @grant none // @downloadURL https://update.greasyfork.icu/scripts/483188/cai%20X%20Swipes.user.js // @updateURL https://update.greasyfork.icu/scripts/483188/cai%20X%20Swipes.meta.js // ==/UserScript== (function() { 'use strict'; var original_prototype_open = XMLHttpRequest.prototype.open; const intercepted_data_object_swipes = {}; XMLHttpRequest.prototype.open = function(method, url, async) { if ( url.startsWith('https://plus.character.ai/chat/history/continue/') || url.startsWith('https://plus.character.ai/chat/character/info') || url.startsWith('https://beta.character.ai/chat/history/continue/') || url.startsWith('https://beta.character.ai/chat/character/info') ) { this.addEventListener('load', function() { let info1_swipes = JSON.parse(this.responseText); intercepted_data_object_swipes.external_id = info1_swipes.character.external_id; intercepted_data_object_swipes.name = info1_swipes.character.name; console.log("character_id:",intercepted_data_object_swipes.external_id); // Only create the toggle button and the panel once if (!document.getElementById('NeoPanelSwipes')) { createToggleButton_NeoPanelSwipes(); createNeoPanelSwipes(); } }); } else if (url.startsWith(`https://neo.character.ai/chats/recent/${intercepted_data_object_swipes.external_id}`)) { this.addEventListener('load', function() { let info2_swipes = JSON.parse(this.responseText); intercepted_data_object_swipes.chat_id = info2_swipes.chats[0].chat_id; console.log("chat_id:",intercepted_data_object_swipes.chat_id); }); } else if (url.startsWith(`https://neo.character.ai/turns/${intercepted_data_object_swipes.chat_id}`)) { this.addEventListener('load', function() { let info3_swipes = JSON.parse(this.responseText); intercepted_data_object_swipes.turn_id = info3_swipes.turns[0].turn_key.turn_id; intercepted_data_object_swipes.total_turns = info3_swipes.turns.length; console.log("turn_id:",intercepted_data_object_swipes.turn_id); console.log("total_turns:", intercepted_data_object_swipes.total_turns); // Extract data from the last turn_id if there are turns if (intercepted_data_object_swipes.total_turns > 0) { const lastTurnIndex = intercepted_data_object_swipes.total_turns - 1; const lastTurnData = info3_swipes.turns[lastTurnIndex]; intercepted_data_object_swipes.lastTurnId = lastTurnData.turn_key.turn_id; // Store lastTurnId in intercepted_data_object_swipes console.log("Last turn_id:", intercepted_data_object_swipes.lastTurnId); } // Extract candidates for "turn 0", used for fetching limit if (intercepted_data_object_swipes.total_turns > 0) { const firstTurnData = info3_swipes.turns[0]; intercepted_data_object_swipes.candidatesForTurn0 = firstTurnData.candidates; intercepted_data_object_swipes.numberOfCandidatesForTurn0 = intercepted_data_object_swipes.candidatesForTurn0.length; console.log("Number of candidates for turn 0:", intercepted_data_object_swipes.numberOfCandidatesForTurn0); intercepted_data_object_swipes.rawContents = intercepted_data_object_swipes.candidatesForTurn0.map(candidate => candidate.raw_content); console.log("Raw contents of candidates for turn 0:", intercepted_data_object_swipes.rawContents); // All Styles and Functions of the List Elements const swipes = document.createElement('div'); swipes.style.textAlign = 'left'; swipes.style.marginTop = '15px'; swipes.style.overflowWrap = 'break-word'; swipes.style.whiteSpace = 'pre-wrap'; swipes.style.maxHeight = 'calc(100% - 12px)'; // Adjust the value as needed swipes.style.overflowY = 'auto'; swipes.style.marginLeft = '-10px'; swipes.style.scrollbarWidth = '1px'; //swipes.style.scrollbarColor = 'transparent transparent'; if (intercepted_data_object_swipes.rawContents) { intercepted_data_object_swipes.rawContents.forEach((content, index) => { const contentContainer = document.createElement('div'); // Create a container for each content contentContainer.style.display = 'flex'; // Use flex layout contentContainer.style.alignItems = 'center'; // Center-align vertically contentContainer.style.marginBottom = '15px'; // Add some spacing between elements contentContainer.style.marginTop = '15px'; contentContainer.style.direction = 'ltr'; let isGreen = false; // Flag to track the background color state const candidateNumber = index + 1; // Adding 1 to index to make it 1-based const numberElement = document.createElement('span'); // Create element for candidate number numberElement.textContent = `${candidateNumber}.`; numberElement.style.marginRight = '15px'; // Add spacing between number and text numberElement.style.direction = 'ltr'; numberElement.style.marginLeft = '10px'; // numberElement.style.alignItems = 'center'; numberElement.style.marginBottom = '15px' const contentElement = document.createElement('div'); // Create element for content contentElement.innerHTML = content; contentElement.style.direction = 'ltr'; contentElement.style.color = '#878788'; // Changes the color of the text const formattedContent = content.replace(/(["“”«»].*?["“”«»])/g, '$1'); const finalContent1 = formattedContent.replace(/\*\*(.*?)\*\*/g, '$1'); const finalContent = finalContent1.replace(/\*(.*?)\*/g, '$1'); // Use regular expressions to find text within backticks and apply formatting const formattedBackticks_3 = finalContent.replace(/```([^`]*)```/g, '
$1
$1
$1