text injector

24/5/2023, 19:07:21

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        text injector
// @namespace   Violentmonkey Scripts
// @match       https://beta.character.ai/*
// @grant       none
// @version     1.20
// @author      -
// @description 24/5/2023, 19:07:21
// @license MIT
// ==/UserScript==
const originalFetch = window.fetch;
let customPrepend = ""
function createPrependWindow() {
    //create a floating div which can be resized, dragged, minimized, and closed (like a window) to change the custom prepend
    let customPrependDiv = document.createElement("div")
    customPrependDiv.style.position = "fixed"
    customPrependDiv.style.top = "0px"
    customPrependDiv.style.left = "0px"
    customPrependDiv.style.width = "235px"
    customPrependDiv.style.height = "200px"
    customPrependDiv.style.backgroundColor = "white"
    customPrependDiv.style.border = "1px solid black"
    customPrependDiv.style.zIndex
    customPrependDiv.style.resize = "both"
    customPrependDiv.style.overflow = "auto"
    customPrependDiv.style.display = "none"
    customPrependDiv.style.padding = "5px"
    customPrependDiv.style.fontFamily = "monospace"
    customPrependDiv.style.fontSize = "12px"
    customPrependDiv.style.userSelect = "none"
    customPrependDiv.style.cursor = "move"
    customPrependDiv.style.boxShadow = "0px 0px 10px 0px rgba(0,0,0,0.75)"
    customPrependDiv.style.borderRadius = "5px"
    customPrependDiv.style.transition = "height 0.2s ease-in-out"
    customPrependDiv.style.zIndex = 213098123

    let customPrependDivHeader = document.createElement("div")
    customPrependDivHeader.style.width = "100%"
    customPrependDivHeader.style.height = "20px"
    customPrependDivHeader.style.backgroundColor = "lightgray"
    customPrependDivHeader.style.borderBottom = "1px solid black"
    customPrependDivHeader.style.borderTopLeftRadius = "5px"
    customPrependDivHeader.style.borderTopRightRadius = "5px"
    customPrependDivHeader.style.userSelect = "none"
    customPrependDivHeader.style.cursor = "move"
    customPrependDivHeader.style.display = "flex"
    customPrependDivHeader.style.alignItems = "center"
    customPrependDivHeader.style.justifyContent = "center"

    let customPrependDivHeaderText = document.createElement("span")
    customPrependDivHeaderText.innerText = "Custom Prepend"
    customPrependDivHeaderText.style.fontWeight = "bold"
    customPrependDivHeaderText.style.fontSize = "14px"

    let customPrependDivCloseButton = document.createElement("button")
    customPrependDivCloseButton.innerText = "X"
    customPrependDivCloseButton.style.position = "absolute"
    customPrependDivCloseButton.style.right = "5px"
    customPrependDivCloseButton.style.top = "5px"
    customPrependDivCloseButton.style.width = "20px"
    customPrependDivCloseButton.style.height = "20px"
    customPrependDivCloseButton.style.backgroundColor = "transparent"
    customPrependDivCloseButton.style.border = "none"
    customPrependDivCloseButton.style.outline = "none"
    customPrependDivCloseButton.style.cursor = "pointer"
    customPrependDivCloseButton.style.userSelect = "none"
    customPrependDivCloseButton.style.fontWeight = "bold"
    customPrependDivCloseButton.style.fontSize = "14px"
    customPrependDivCloseButton.style.transition = "height 0.2s ease-in-out"

    let customPrependDivMinimizeButton = document.createElement("button")
    customPrependDivMinimizeButton.innerText = "-"
    customPrependDivMinimizeButton.style.position = "absolute"
    customPrependDivMinimizeButton.style.right = "30px"
    customPrependDivMinimizeButton.style.top = "5px"
    customPrependDivMinimizeButton.style.width = "20px"
    customPrependDivMinimizeButton.style.height = "20px"
    customPrependDivMinimizeButton.style.backgroundColor = "transparent"
    customPrependDivMinimizeButton.style.border = "none"
    customPrependDivMinimizeButton.style.outline = "none"
    customPrependDivMinimizeButton.style.cursor = "pointer"
    customPrependDivMinimizeButton.style.userSelect = "none"
    customPrependDivMinimizeButton.style.fontWeight = "bold"
    customPrependDivMinimizeButton.style.fontSize = "14px"
    customPrependDivMinimizeButton.style.transition = "height 0.2s ease-in-out"

    let customPrependDivContent = document.createElement("div")
    customPrependDivContent.style.width = "100%"
    customPrependDivContent.style.height = "100%"
    customPrependDivContent.style.padding = "5px"
    customPrependDivContent.style.boxSizing = "border-box"

    let customPrependDivTextarea = document.createElement("textarea")
    customPrependDivTextarea.style.width = "100%"
    customPrependDivTextarea.style.height = "100%"
    customPrependDivTextarea.style.resize = "none"
    customPrependDivTextarea.style.outline = "none"
    customPrependDivTextarea.style.border = "none"
    customPrependDivTextarea.style.fontFamily = "monospace"
    customPrependDivTextarea.style.fontSize = "12px"
    customPrependDivTextarea.style.userSelect = "none"
    customPrependDivTextarea.style.cursor = "text"
    customPrependDivTextarea.style.boxShadow = "none"
    customPrependDivTextarea.style.borderRadius = "0px"
    customPrependDivTextarea.style.transition = "height 0.2s ease-in-out"

    customPrependDivHeader.appendChild(customPrependDivHeaderText)
    customPrependDivHeader.appendChild(customPrependDivCloseButton)
    customPrependDivHeader.appendChild(customPrependDivMinimizeButton)
    customPrependDivContent.appendChild(customPrependDivTextarea)
    customPrependDiv.appendChild(customPrependDivHeader)
    customPrependDiv.appendChild(customPrependDivContent)
    document.body.appendChild(customPrependDiv)

    //create a buttton in the top left corner of the screen to open the custom prepend div, with a little animation and margin
    let customPrependDivOpenButton = document.createElement("button")
    customPrependDivOpenButton.innerText = "Custom Prepend"
    customPrependDivOpenButton.style.position = "fixed"
    customPrependDivOpenButton.style.top = "5px"
    customPrependDivOpenButton.style.left = "5px"
    customPrependDivOpenButton.style.border = "1px solid black"
    customPrependDivOpenButton.style.outline = "none"
    customPrependDivOpenButton.style.cursor = "pointer"
    customPrependDivOpenButton.style.userSelect = "none"
    customPrependDivOpenButton.style.fontWeight = "bold"
    customPrependDivOpenButton.style.fontSize = "12px"
    customPrependDivOpenButton.style.transition = "backgroundColor 0.2s ease-in-out"
    customPrependDivOpenButton.style.zIndex = 213098123

    document.body.appendChild(customPrependDivOpenButton)

    customPrependDivOpenButton.addEventListener("click", function () {
        if (customPrependDiv.style.display == "none") {
            customPrependDiv.style.display = "block"
            customPrependDivOpenButton.style.backgroundColor = "lightgray"
            customPrependDiv.style.top = "80px"
        } else {
            customPrependDiv.style.display = "none"
            customPrependDivOpenButton.style.backgroundColor = "transparent"
        }
    })

    customPrependDivCloseButton.addEventListener("click", function () {
        customPrependDiv.style.display = "none"
        customPrependDivOpenButton.style.backgroundColor = "transparent"
    })

    customPrependDivMinimizeButton.addEventListener("click", function () {
        if (customPrependDivMinimizeButton.innerText == "-") {
            customPrependDiv.style.height = "30px"
            customPrependDivMinimizeButton.innerText = "+"
        } else {
            customPrependDiv.style.height = "200px"
            customPrependDivMinimizeButton.innerText = "-"
        }
    })

    //remove transition while being resized
    customPrependDiv.addEventListener("mousedown", function () {
        customPrependDiv.style.transition = "none"
    })
    customPrependDiv.addEventListener("mouseup", function () {
        customPrependDiv.style.transition = "height 0.2s ease-in-out"
    })

    customPrependDivHeader.addEventListener("mousedown", function (e) {
        e.preventDefault()
        let x = e.clientX
        let y = e.clientY
        let top = customPrependDiv.offsetTop
        let left = customPrependDiv.offsetLeft
        console.log("mousedown triggered")
        document.addEventListener("mousemove", drag)
        document.addEventListener("mouseup", stopDrag)
        function drag(e) {
            let newX = e.clientX
            let newY = e.clientY
            let newTop = newY - (y - top)
            let newLeft = newX - (x - left)
            customPrependDiv.style.top = newTop + "px"
            customPrependDiv.style.left = newLeft + "px"
        }
        function stopDrag() {
            document.removeEventListener("mousemove", drag)
            document.removeEventListener("mouseup", stopDrag)
        }
    })

    customPrependDivTextarea.addEventListener("input", function () {
        customPrepend = customPrependDivTextarea.value
    })
}
/**
 * Creates a floating readonly textarea that can be dragged around the screen and resized hidden like the custom prepend div and closed, as well as having a button to open it like the custom prepend div
 */
function createResponsePreviewWindow() {
    let responsePreviewDiv = document.createElement("div")
    responsePreviewDiv.style.position = "fixed"
    responsePreviewDiv.style.top = "0px"
    responsePreviewDiv.style.left = "0px"
    responsePreviewDiv.style.width = "235px"
    responsePreviewDiv.style.height = "200px"
    responsePreviewDiv.style.backgroundColor = "white"
    responsePreviewDiv.style.border = "1px solid black"
    responsePreviewDiv.style.zIndex
    responsePreviewDiv.style.resize = "both"
    responsePreviewDiv.style.overflow = "auto"
    responsePreviewDiv.style.display = "none"
    responsePreviewDiv.style.padding = "5px"
    responsePreviewDiv.style.fontFamily = "monospace"
    responsePreviewDiv.style.fontSize = "12px"
    responsePreviewDiv.style.userSelect = "none"
    responsePreviewDiv.style.cursor = "move"
    responsePreviewDiv.style.boxShadow = "0px 0px 10px 0px rgba(0,0,0,0.75)"
    responsePreviewDiv.style.borderRadius = "5px"
    responsePreviewDiv.style.transition = "height 0.2s ease-in-out"
    responsePreviewDiv.style.zIndex = 213098123

    let responsePreviewDivHeader = document.createElement("div")
    responsePreviewDivHeader.style.width = "100%"
    responsePreviewDivHeader.style.height = "20px"
    responsePreviewDivHeader.style.backgroundColor = "lightgray"
    responsePreviewDivHeader.style.borderBottom = "1px solid black"
    responsePreviewDivHeader.style.borderTopLeftRadius = "5px"
    responsePreviewDivHeader.style.borderTopRightRadius = "5px"
    responsePreviewDivHeader.style.userSelect = "none"
    responsePreviewDivHeader.style.cursor = "move"
    responsePreviewDivHeader.style.display = "flex"
    responsePreviewDivHeader.style.alignItems = "center"
    responsePreviewDivHeader.style.justifyContent = "center"

    let responsePreviewDivHeaderText = document.createElement("span")
    responsePreviewDivHeaderText.innerText = "Response Preview"
    responsePreviewDivHeaderText.style.fontWeight = "bold"
    responsePreviewDivHeaderText.style.fontSize = "14px"

    let responsePreviewDivCloseButton = document.createElement("button")
    responsePreviewDivCloseButton.innerText = "X"
    responsePreviewDivCloseButton.style.position = "absolute"
    responsePreviewDivCloseButton.style.right = "5px"
    responsePreviewDivCloseButton.style.top = "5px"
    responsePreviewDivCloseButton.style.width = "20px"
    responsePreviewDivCloseButton.style.height = "20px"
    responsePreviewDivCloseButton.style.backgroundColor = "transparent"
    responsePreviewDivCloseButton.style.border = "none"
    responsePreviewDivCloseButton.style.outline = "none"
    responsePreviewDivCloseButton.style.cursor = "pointer"
    responsePreviewDivCloseButton.style.userSelect = "none"
    responsePreviewDivCloseButton.style.fontWeight = "bold"
    responsePreviewDivCloseButton.style.fontSize = "14px"
    responsePreviewDivCloseButton.style.transition = "height 0.2s ease-in-out"

    let responsePreviewDivMinimizeButton = document.createElement("button")
    responsePreviewDivMinimizeButton.innerText = "-"
    responsePreviewDivMinimizeButton.style.position = "absolute"
    responsePreviewDivMinimizeButton.style.right = "30px"
    responsePreviewDivMinimizeButton.style.top = "5px"
    responsePreviewDivMinimizeButton.style.width = "20px"
    responsePreviewDivMinimizeButton.style.height = "20px"
    responsePreviewDivMinimizeButton.style.backgroundColor = "transparent"
    responsePreviewDivMinimizeButton.style.border = "none"
    responsePreviewDivMinimizeButton.style.outline = "none"
    responsePreviewDivMinimizeButton.style.cursor = "pointer"
    responsePreviewDivMinimizeButton.style.userSelect = "none"
    responsePreviewDivMinimizeButton.style.fontWeight = "bold"
    responsePreviewDivMinimizeButton.style.fontSize = "14px"
    responsePreviewDivMinimizeButton.style.transition = "height 0.2s ease-in-out"

    let responsePreviewDivContent = document.createElement("div")
    responsePreviewDivContent.style.width = "100%"
    responsePreviewDivContent.style.height = "85%"
    responsePreviewDivContent.style.padding = "5px"
    responsePreviewDivContent.style.boxSizing = "border-box"

    //a colored bar which shows the status of the response preview, green for success, yellow for loading
    let responsePreviewStatusBar = document.createElement("div")
    responsePreviewStatusBar.style.width = "100%"
    responsePreviewStatusBar.style.height = "10px"
    responsePreviewStatusBar.style.backgroundColor = "yellow"
    responsePreviewStatusBar.style.borderRadius = "5px"
    responsePreviewStatusBar.style.transition = "height 0.2s ease-in-out"
    responsePreviewStatusBar.style.display = "none"
    responsePreviewStatusBar.style["--darkreader-inline-bgcolor"] = "#ffff00"

    let responsePreviewDivTextarea = document.createElement("textarea")
    responsePreviewDivTextarea.style.width = "100%"
    responsePreviewDivTextarea.style.height = "100%"
    responsePreviewDivTextarea.style.resize = "none"
    responsePreviewDivTextarea.style.outline = "none"
    responsePreviewDivTextarea.style.border = "none"
    responsePreviewDivTextarea.style.fontFamily = "monospace"
    responsePreviewDivTextarea.style.fontSize = "12px"
    responsePreviewDivTextarea.style.userSelect = "none"
    responsePreviewDivTextarea.style.cursor = "text"
    responsePreviewDivTextarea.style.boxShadow = "none"
    responsePreviewDivTextarea.style.borderRadius = "0px"
    responsePreviewDivTextarea.style.transition = "height 0.2s ease-in-out"
    responsePreviewDivTextarea.disabled = true
    responsePreviewDivTextarea.style.color = "white"

    responsePreviewDivHeader.appendChild(responsePreviewDivHeaderText)
    responsePreviewDivHeader.appendChild(responsePreviewDivCloseButton)
    responsePreviewDivHeader.appendChild(responsePreviewDivMinimizeButton)
    responsePreviewDivContent.appendChild(responsePreviewDivTextarea)
    responsePreviewDiv.appendChild(responsePreviewDivHeader)
    responsePreviewDiv.appendChild(responsePreviewDivContent)
    responsePreviewDiv.appendChild(responsePreviewStatusBar)
    document.body.appendChild(responsePreviewDiv)

    //create a buttton in the top left corner of the screen to open the custom prepend div, with a little animation and margin
    let responsePreviewDivOpenButton = document.createElement("button")
    responsePreviewDivOpenButton.innerText = "Response Preview"
    responsePreviewDivOpenButton.style.position = "fixed"
    responsePreviewDivOpenButton.style.top = "35px"
    responsePreviewDivOpenButton.style.left = "5px"
    responsePreviewDivOpenButton.style.border = "1px solid black"
    responsePreviewDivOpenButton.style.outline = "none"
    responsePreviewDivOpenButton.style.cursor = "pointer"
    responsePreviewDivOpenButton.style.userSelect = "none"
    responsePreviewDivOpenButton.style.fontWeight = "bold"
    responsePreviewDivOpenButton.style.fontSize = "12px"
    responsePreviewDivOpenButton.style.transition = "backgroundColor 0.2s ease-in-out"
    responsePreviewDivOpenButton.style.zIndex = 213098123

    document.body.appendChild(responsePreviewDivOpenButton)

    responsePreviewDivOpenButton.addEventListener("click", function () {
        if (responsePreviewDiv.style.display == "none") {
            responsePreviewDiv.style.display = "block"
            responsePreviewDivOpenButton.style.backgroundColor = "lightgray"
            responsePreviewDiv.style.top = "80px"
        } else {
            responsePreviewDiv.style.display = "none"
            responsePreviewDivOpenButton.style.backgroundColor = "transparent"
        }
    })

    responsePreviewDivCloseButton.addEventListener("click", function () {
        responsePreviewDiv.style.display = "none"
        responsePreviewDivOpenButton.style.backgroundColor = "transparent"
    })

    responsePreviewDivMinimizeButton.addEventListener("click", function () {
        if (responsePreviewDivMinimizeButton.innerText == "-") {
            responsePreviewDiv.style.height = "30px"
            responsePreviewDivMinimizeButton.innerText = "+"
        } else {
            responsePreviewDiv.style.height = "200px"
            responsePreviewDivMinimizeButton.innerText = "-"
        }
    })

    //remove transition while being resized
    responsePreviewDiv.addEventListener("mousedown", function () {
        responsePreviewDiv.style.transition = "none"
    })
    responsePreviewDiv.addEventListener("mouseup", function () {
        responsePreviewDiv.style.transition = "height 0.2s ease-in-out"
    })

    responsePreviewDivHeader.addEventListener("mousedown", function (e) {
        e.preventDefault()
        let x = e.clientX
        let y = e.clientY
        let top = responsePreviewDiv.offsetTop
        let left = responsePreviewDiv.offsetLeft
        console.log("mousedown triggered")
        document.addEventListener("mousemove", drag)
        document.addEventListener("mouseup", stopDrag)
        function drag(e) {
            let newX = e.clientX
            let newY = e.clientY
            let newTop = newY - (y - top)
            let newLeft = newX - (x - left)
            responsePreviewDiv.style.top = newTop + "px"
            responsePreviewDiv.style.left = newLeft + "px"
        }
        function stopDrag() {
            document.removeEventListener("mousemove", drag)
            document.removeEventListener("mouseup", stopDrag)
        }
    })
    let displayResponsePreviewStatusBar = function (boolean) {
        if (boolean) {
            responsePreviewStatusBar.style.display = "block"
            responsePreviewStatusBar.style.backgroundColor = "lightgray"
        } else {
            responsePreviewStatusBar.style.display = "none"
        }
    }
    let responsePreviewSetResponseFinished = function (boolean) {
        if (boolean) {
            responsePreviewStatusBar.style.backgroundColor = "lightgreen"
            responsePreviewStatusBar.style["--darkreader-inline-bgcolor"] = "#00ff00"
        } else {
            responsePreviewStatusBar.style.backgroundColor = "yellow"
            responsePreviewStatusBar.style["--darkreader-inline-bgcolor"] = "#ffff00"
        }
    }
    return { displayResponsePreviewStatusBar, responsePreviewSetResponseFinished, responsePreviewDivTextarea }
}

function createColorPickerWindow() {
    let colorPickerDiv = document.createElement("div")
    colorPickerDiv.style.position = "fixed"
    colorPickerDiv.style.top = "0px"
    colorPickerDiv.style.left = "0px"
    colorPickerDiv.style.width = "235px"
    colorPickerDiv.style.height = "200px"
    colorPickerDiv.style.backgroundColor = "white"
    colorPickerDiv.style.border = "1px solid black"
    colorPickerDiv.style.zIndex
    colorPickerDiv.style.resize = "both"
    colorPickerDiv.style.overflow = "auto"
    colorPickerDiv.style.display = "none"
    colorPickerDiv.style.padding = "5px"
    colorPickerDiv.style.fontFamily = "monospace"
    colorPickerDiv.style.fontSize = "12px"
    colorPickerDiv.style.userSelect = "none"
    colorPickerDiv.style.cursor = "move"
    colorPickerDiv.style.boxShadow = "0px 0px 10px 0px rgba(0,0,0,0.75)"
    colorPickerDiv.style.borderRadius = "5px"
    colorPickerDiv.style.transition = "height 0.2s ease-in-out"
    colorPickerDiv.style.zIndex = 213098123

    let colorPickerDivHeader = document.createElement("div")
    colorPickerDivHeader.style.width = "100%"
    colorPickerDivHeader.style.height = "20px"
    colorPickerDivHeader.style.backgroundColor = "lightgray"
    colorPickerDivHeader.style.borderBottom = "1px solid black"
    colorPickerDivHeader.style.borderTopLeftRadius = "5px"
    colorPickerDivHeader.style.borderTopRightRadius = "5px"
    colorPickerDivHeader.style.userSelect = "none"
    colorPickerDivHeader.style.cursor = "move"
    colorPickerDivHeader.style.display = "flex"
    colorPickerDivHeader.style.alignItems = "center"
    colorPickerDivHeader.style.justifyContent = "center"

    let colorPickerDivHeaderText = document.createElement("span")
    colorPickerDivHeaderText.innerText = "Color Picker"
    colorPickerDivHeaderText.style.fontWeight = "bold"
    colorPickerDivHeaderText.style.fontSize = "14px"

    let colorPickerDivCloseButton = document.createElement("button")
    colorPickerDivCloseButton.innerText = "X"
    colorPickerDivCloseButton.style.position = "absolute"
    colorPickerDivCloseButton.style.right = "5px"
    colorPickerDivCloseButton.style.top = "5px"
    colorPickerDivCloseButton.style.width = "20px"
    colorPickerDivCloseButton.style.height = "20px"
    colorPickerDivCloseButton.style.backgroundColor = "transparent"
    colorPickerDivCloseButton.style.border = "none"
    colorPickerDivCloseButton.style.outline = "none"
    colorPickerDivCloseButton.style.cursor = "pointer"
    colorPickerDivCloseButton.style.userSelect = "none"
    colorPickerDivCloseButton.style.fontWeight = "bold"
    colorPickerDivCloseButton.style.fontSize = "14px"
    colorPickerDivCloseButton.style.transition = "height 0.2s ease-in-out"

    let colorPickerDivMinimizeButton = document.createElement("button")
    colorPickerDivMinimizeButton.innerText = "-"
    colorPickerDivMinimizeButton.style.position = "absolute"
    colorPickerDivMinimizeButton.style.right = "30px"
    colorPickerDivMinimizeButton.style.top = "5px"
    colorPickerDivMinimizeButton.style.width = "20px"
    colorPickerDivMinimizeButton.style.height = "20px"
    colorPickerDivMinimizeButton.style.backgroundColor = "transparent"
    colorPickerDivMinimizeButton.style.border = "none"
    colorPickerDivMinimizeButton.style.outline = "none"
    colorPickerDivMinimizeButton.style.cursor = "pointer"
    colorPickerDivMinimizeButton.style.userSelect = "none"
    colorPickerDivMinimizeButton.style.fontWeight = "bold"
    colorPickerDivMinimizeButton.style.fontSize = "14px"
    colorPickerDivMinimizeButton.style.transition = "height 0.2s ease-in-out"

    let colorPickerDivContent = document.createElement("div")
    colorPickerDivContent.style.width = "100%"
    colorPickerDivContent.style.height = "85%"
    colorPickerDivContent.style.padding = "5px"
    colorPickerDivContent.style.boxSizing = "border-box"

    //pickers are to be shown one under the other, with labels on top, little margin between them
    let colorPickerDivContainer = document.createElement("div")
    colorPickerDivContainer.style.width = "100%"
    colorPickerDivContainer.style.height = "100%"
    colorPickerDivContainer.style.display = "flex"
    colorPickerDivContainer.style.flexDirection = "column"
    colorPickerDivContainer.style.alignItems = "center"
    colorPickerDivContainer.style.justifyContent = "center"
    
    //pickers are color pickers input type color, with a label on top
    let colorPickerDivColorPickerUser = document.createElement("input")
    colorPickerDivColorPickerUser.type = "color"
    colorPickerDivColorPickerUser.style.width = "100%"
    colorPickerDivColorPickerUser.style.height = "100%"
    colorPickerDivColorPickerUser.style.margin = "5px"
    colorPickerDivColorPickerUser.style.boxSizing = "border-box"
    colorPickerDivColorPickerUser.style.border = "1px solid black"
    colorPickerDivColorPickerUser.style.borderRadius = "5px"
    colorPickerDivColorPickerUser.style.outline = "none"
    colorPickerDivColorPickerUser.style.cursor = "pointer"
    colorPickerDivColorPickerUser.style.transition = "height 0.2s ease-in-out"

    //to be show on top of the picker
    let colorPickerDivColorPickerLaberUser = document.createElement("span")
    colorPickerDivColorPickerLaberUser.innerText = "User Color"
    colorPickerDivColorPickerLaberUser.style.fontWeight = "bold"
    colorPickerDivColorPickerLaberUser.style.fontSize = "14px"

    let colorPickerDivColorPickerBot = document.createElement("input")
    colorPickerDivColorPickerBot.type = "color"
    colorPickerDivColorPickerBot.style.width = "100%"
    colorPickerDivColorPickerBot.style.height = "100%"
    colorPickerDivColorPickerBot.style.margin = "5px"
    colorPickerDivColorPickerBot.style.boxSizing = "border-box"
    colorPickerDivColorPickerBot.style.border = "1px solid black"
    colorPickerDivColorPickerBot.style.borderRadius = "5px"
    colorPickerDivColorPickerBot.style.outline = "none"
    colorPickerDivColorPickerBot.style.cursor = "pointer"
    colorPickerDivColorPickerBot.style.transition = "height 0.2s ease-in-out"

    //to be show on top of the picker
    let colorPickerDivColorPickerLaberBot = document.createElement("span")
    colorPickerDivColorPickerLaberBot.innerText = "Bot Color"
    colorPickerDivColorPickerLaberBot.style.fontWeight = "bold"
    colorPickerDivColorPickerLaberBot.style.fontSize = "14px"


    colorPickerDivHeader.appendChild(colorPickerDivHeaderText)
    colorPickerDivHeader.appendChild(colorPickerDivCloseButton)
    colorPickerDivHeader.appendChild(colorPickerDivMinimizeButton)
    colorPickerDivContent.appendChild(colorPickerDivContainer)
    colorPickerDivContainer.appendChild(colorPickerDivColorPickerLaberUser)
    colorPickerDivContainer.appendChild(colorPickerDivColorPickerUser)
    colorPickerDivContainer.appendChild(colorPickerDivColorPickerLaberBot)
    colorPickerDivContainer.appendChild(colorPickerDivColorPickerBot)
    colorPickerDiv.appendChild(colorPickerDivHeader)
    colorPickerDiv.appendChild(colorPickerDivContent)
    document.body.appendChild(colorPickerDiv)

    //create a buttton in the top left corner of the screen to open the custom prepend div, with a little animation and margin
    let colorPickerDivOpenButton = document.createElement("button")
    colorPickerDivOpenButton.innerText = "Color Picker"
    colorPickerDivOpenButton.style.position = "fixed"
    colorPickerDivOpenButton.style.top = "65px"
    colorPickerDivOpenButton.style.left = "5px"
    colorPickerDivOpenButton.style.border = "1px solid black"
    colorPickerDivOpenButton.style.outline = "none"
    colorPickerDivOpenButton.style.cursor = "pointer"
    colorPickerDivOpenButton.style.userSelect = "none"
    colorPickerDivOpenButton.style.fontWeight = "bold"
    colorPickerDivOpenButton.style.fontSize = "12px"
    colorPickerDivOpenButton.style.transition = "backgroundColor 0.2s ease-in-out"
    colorPickerDivOpenButton.style.zIndex = 213098123

    document.body.appendChild(colorPickerDivOpenButton)

    colorPickerDivOpenButton.addEventListener("click", function () {
        if (colorPickerDiv.style.display == "none") {
            colorPickerDiv.style.display = "block"
            colorPickerDivOpenButton.style.backgroundColor = "lightgray"
            colorPickerDiv.style.top = "120px"
        } else {
            colorPickerDiv.style.display = "none"
            colorPickerDivOpenButton.style.backgroundColor = "transparent"
        }
    })

    colorPickerDivCloseButton.addEventListener("click", function () {
        colorPickerDiv.style.display = "none"
        colorPickerDivOpenButton.style.backgroundColor = "transparent"
    })

    colorPickerDivMinimizeButton.addEventListener("click", function () {
        if (colorPickerDivMinimizeButton.innerText == "-") {
            colorPickerDiv.style.height = "30px"
            colorPickerDivMinimizeButton.innerText = "+"
            //hide the color Picker Div Container if it is minimized
            colorPickerDivContainer.style.display = "none"

        } else {
            colorPickerDiv.style.height = "200px"
            colorPickerDivMinimizeButton.innerText = "-"
            //show the color Picker Div Container if it is maximized
            colorPickerDivContainer.style.display = "flex"
        }
    })

    //remove transition while being resized
    colorPickerDiv.addEventListener("mousedown", function () {
        colorPickerDiv.style.transition = "none"
    })
    colorPickerDiv.addEventListener("mouseup", function () {
        colorPickerDiv.style.transition = "height 0.2s ease-in-out"
    })

    colorPickerDivHeader.addEventListener("mousedown", function (e) {
        e.preventDefault()
        let x = e.clientX
        let y = e.clientY
        let top = colorPickerDiv.offsetTop
        let left = colorPickerDiv.offsetLeft
        console.log("mousedown triggered")
        document.addEventListener("mousemove", drag)
        document.addEventListener("mouseup", stopDrag)
        function drag(e) {
            let newX = e.clientX
            let newY = e.clientY
            let newTop = newY - (y - top)
            let newLeft = newX - (x - left)
            colorPickerDiv.style.top = newTop + "px"
            colorPickerDiv.style.left = newLeft + "px"
        }
        function stopDrag() {
            document.removeEventListener("mousemove", drag)
            document.removeEventListener("mouseup", stopDrag)
        }
    })

    colorPickerDivColorPickerUser.addEventListener("input", function () {
        document.querySelectorAll(".user-msg").forEach(function (msg) {
            msg.style.color = colorPickerDivColorPickerUser.value
            //dark reader fix
            msg.style["--darkreader-inline-color"] = colorPickerDivColorPickerUser.value
        })
    })
    colorPickerDivColorPickerBot.addEventListener("input", function () {
        document.querySelectorAll(".char-msg").forEach(function (msg) {
            msg.style.color = colorPickerDivColorPickerBot.value
            //dark reader fix
            msg.style["--darkreader-inline-color"] = colorPickerDivColorPickerBot.value
        })
    })

    let updateColors = function () {
        let currentUserColor = colorPickerDivColorPickerUser.value
        let currentBotColor = colorPickerDivColorPickerBot.value

        document.querySelectorAll(".user-msg").forEach(function (msg) {
            msg.style.color = currentUserColor
            //dark reader fix
            msg.style["--darkreader-inline-color"] = currentUserColor
        })
        document.querySelectorAll(".char-msg").forEach(function (msg) {
            msg.style.color = currentBotColor
            //dark reader fix
            msg.style["--darkreader-inline-color"] = currentBotColor
        })
    }

    return updateColors
}

createPrependWindow()

let { displayResponsePreviewStatusBar, responsePreviewSetResponseFinished, responsePreviewDivTextarea } = createResponsePreviewWindow()

let updateColors = createColorPickerWindow()

function processResponse(response) {
    if (response.body) {
        const reader = response.body.getReader();

        const workerURL = URL.createObjectURL(
            new Blob([`(${workerCode.toString()})()`], { type: 'application/javascript' })
        );

        const worker = new Worker(workerURL);

        worker.onmessage = event => {
            const { data } = event;
            updateColors()
            responsePreviewDivTextarea.value = data.text;
        };

        const processChunks = () => {
            reader.read().then(({ done, value }) => {
                if (done) {
                    // Terminate the web worker after sending the last message
                    worker.onmessage = event => {
                        const { data } = event;
                        updateColors()
                        responsePreviewDivTextarea.value = data.text;
                        if (data.is_final_chunk === true) {
                            responsePreviewSetResponseFinished(true)
                            worker.terminate();
                            updateColors()
                            //asyncronously wait 3 seconds and then hide the response preview div
                            setTimeout(function () {
                                displayResponsePreviewStatusBar(false)
                            }, 8000)
                        }
                    };
                    return;
                }
                // Send each chunk of data to the web worker for processing
                worker.postMessage(value);

                processChunks(); // Continue reading the next chunk of data
            }).catch(error => {
                console.log(error);
                worker.terminate(); // Terminate the web worker in case of error
            });
        };
        processChunks(); // Start reading the chunks of data
    }
}

window.fetch = function (url, options) {
    if (url == "https://beta.character.ai/chat/streaming/") {
        let optionsCopy = JSON.parse(options.body)
        optionsCopy.text = optionsCopy.text
        if (customPrepend != "") optionsCopy.text = customPrepend + "\n\n" + optionsCopy.text
        options.body = JSON.stringify(optionsCopy)
        const fetchPromise = originalFetch(url, options);

        fetchPromise.then(response => {
            const cloneResponse = response.clone(); // Create a clone of the response
            displayResponsePreviewStatusBar(true)
            responsePreviewSetResponseFinished(false)
            processResponse(cloneResponse); // Process the clone in the background
        }).catch(error => {
            console.log(error);
        });

        return fetchPromise;
    } else {
        return originalFetch(url, options);
    }
};

function workerCode() {
    self.onmessage = event => {
        const data = event.data;
        const decodedData = new TextDecoder().decode(data);
        let structuredData = { text: JSON.parse(decodedData).replies[0].text, is_final_chunk: JSON.parse(decodedData).is_final_chunk }
        self.postMessage(structuredData);
    };
}