HearYourWaifu | HYW

Let's you view censored messages.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name        HearYourWaifu | HYW
// @namespace   HearYourWaifu | HYW
// @match       https://beta.character.ai/chat*
// @grant       none
// @version     1.9
// @author      Some ukranon 🇺🇦
// @license     MIT
// @description Let's you view censored messages.
// @icon        https://d1nxzqpcg2bym0.cloudfront.net/google_play/com.tenshi.yakamoto.tinderwaifu/ba67b540-9f8a-11e9-b3df-77cf5e629a4f/64x64
// @require     https://greasyfork.org/scripts/457525-html2canvas-1-4-1/code/html2canvas%20141.js?version=1134363
// @require     https://greasyfork.org/scripts/457526-canvas2image-1-0-0/code/canvas2image%20100.js?version=1134364
// @run-at      document-start
// ==/UserScript==

//
// Settings
//

// If enabled, only filtered messages will appear in the menu, otherwise all
// Default: false
const show_only_filtered_messages = false;

// If enabled, the menu will be opened immediately when the page is loaded, otherwise only after click
// Default: false
const show_meny_on_start = false;

// If enabled HYW button will be hidden
// Default: false
const hide_menu = false;

// Specifies menu title
// Default: "HYW 1.9"
const menu_title = "HYW 1.9";

// Save past messages
// Default: true
const save_history = true;

// The maximum number of messages available in the history
// Default: 20
const history_max_length = 20;

// Add fast screenshot button
// Default: true
const allow_screenshots = true;

// Specifies screenshot menu title
// Default: "Take a screenshot"
const screen_menu_title = "Take a screenshot";

// Download visible chat instantly as image, otherwise open the chat image in a new window
// Default: false
const insta_download = false;

// Hide real username and profile photo on screenshot
// Default: true
const anon_mode = true;

// Determines which name to display on screenshots if the real one is hidden
// Default: "anon"
const anon_name = "anon";


//
// Inject messages box to HTML
//

window.addEventListener('load', function () {
  let styleHTML = document.createElement('style');
  styleHTML.innerHTML = `
    html {
        height: 100%;
        overflow: hidden;
        width: 100%;
    }
    body {
        height: 100%;
        overflow-x: hidden;
        overflow-y: auto;
        width: 100%;
    }
   .messages-list {
       padding: 4px 4px 3px 4px;
       margin: 40px 4px 0 0;
       border: 3px solid gray;
       position: absolute;
       top: 0;
       right: 0;
       width: 20%;
       height: 80%;
       overflow-y: scroll;
       border-radius: 0 0 8px 8px;
       z-index: 100;
       resize: both;
       direction: rtl;
       min-width: 100px;
       min-height: 100px;
  }
   .display-btn {
       cursor: pointer;
       user-select: none;
       border: 3px solid gray;
       padding: 4px;
       margin: 4px;
       width: 20%;
       position: absolute;
       top: 0;
       right: 0;
       background-color: lightsteelblue;
       color: black;
       font-weight: bold;
       text-align: center;
       z-index: 100;
  }
   .messages-list div {
       margin-top: 5px;
       padding: 8px;
       background-color: lightpink;
       direction: ltr;
  }
   .hywmsg {
       border-radius: 8px;
  }
   .hywmsg.non-deleted {
       background-color: aquamarine;
  }
   .hywmsg.hidden {
       display: none;
  }
   .screen-btn {
       cursor: pointer;
       user-select: none;
       border: 3px solid gray;
       padding: 4px;
       margin: 4px;
       width: 20%;
       position: absolute;
       top: 0;
       left: 0;
       background-color: lightsteelblue;
       color: black;
       font-weight: bold;
       text-align: center;
       z-index: 100;
   }
  `
  document.body.appendChild(styleHTML);


  let buttonHTML = document.createElement('div');
  buttonHTML.innerHTML = menu_title;
  buttonHTML.onclick = function () {
    let msgList = document.getElementsByClassName('messages-list')[0]
    if (msgList.style.display === "none") {
      msgList.style.display = "block";
    } else {
      msgList.style.display = "none";
    }
  };
  buttonHTML.classList.add("display-btn");
  if (!hide_menu) {
    document.body.appendChild(buttonHTML);
  }

  let menuHTML = document.createElement('div');
  menuHTML.innerHTML = `
    <div>
      <div class="messages-list"></div>
    </div>`;
  document.body.appendChild(menuHTML);

  if (!show_meny_on_start) {
    document.getElementsByClassName('messages-list')[0].style.display = "none";
  }


  if (allow_screenshots) {
    let screenBTN = document.createElement('div')
    screenBTN.classList.add("screen-btn");
    screenBTN.innerHTML = screen_menu_title;
    screenBTN.onclick = function() {
      let real_name = null;
      if (anon_mode) {
        document.querySelectorAll('.msg-author-name').forEach(name => {
          if (real_name == null) {
            real_name = name.innerText;
          }
          name.innerText = anon_name;
        });
        // Hide profile photo
        document.querySelectorAll('.sb-avatar').forEach(profile => {
          if (profile.innerHTML.includes(real_name)) {
            profile.style.opacity = 0;
          }
        })
      }

      if (document.documentElement.dataset.darkreaderScheme == 'dark') {
        let content = document.querySelector("#content");
        content.style.backgroundColor = "rgb(36, 37, 37)";
      }

      // Make screenshot
      html2canvas(document.querySelector("#content"), {
        useCORS: true,
        logging: false,
      }).then(canvas => {
        if (insta_download) {
          Canvas2Image.saveAsPNG(canvas);
        } else {
          // Detect browser
          if (navigator.userAgent.toLowerCase().includes('firefox')) {
            window.open(canvas.toDataURL());
          } else {
            window.open().document.write('<div style="backgroundColor: #1f1f1f"></div><img src="' + canvas.toDataURL() + '" style="display: block;margin-right: auto;margin-left: auto; border:3px solid gray;"/>');
          }
        }
      });

      document.querySelector("#content").style.backgroundColor = "";

      if (anon_mode) {
        // Return real username
        document.querySelectorAll('.msg-author-name').forEach(name => {
          name.innerText = real_name;
        });
        // Return profile photo
        document.querySelectorAll('.sb-avatar').forEach(profile => {
          if (profile.innerHTML.includes(real_name)) {
            profile.style.opacity = 1;
          }
        })
      }
    }
    document.body.appendChild(screenBTN);
  }
}, false);


//
// Modify response
//

const {
  fetch: origFetch
} = window;
window.fetch = async (...args) => {
  const response = await origFetch(...args);

  const raw_text = await new Response(response.clone().body).text();
  parse(raw_text);

  return response;
};



//
// Text parser. Credits to https://perberos.me/roleplai/tools/cai-decode.html
//

let messages_list = [];

function draw() {
  let canvas = document.querySelector(".messages-list");
  canvas.innerHTML = "";

  let age = 0;
  let rowIdx = 0;
  messages_list.forEach(row => {
    let div = document.createElement("div");
    div.classList.add("hywmsg");
    div.style.opacity = 1 - age;
    if (age < 0.5 && rowIdx > 1) {
      age += 0.2;
    }
    div.innerText = row.text;

    if (row.id) {
      div.classList.add("non-deleted");
      if (show_only_filtered_messages) {
        div.classList.add("hidden");
      }
    }
    rowIdx += 1;
    canvas.appendChild(div);
  });
}

function append(row) {
  row.replies.forEach(reply => {
    let exists = false;

    for (let x = 0; x < messages_list.length; x++) {
      if (reply.text.indexOf(messages_list[x].text) == 0) {
        messages_list[x] = reply;
        exists = true;
        break;
      }
    }

    if (!exists) {
      messages_list.unshift(reply);
    }
  })
}

function parse(raw_text) {
  if (!save_history) {
    messages_list.length = 0;
  }


  let raw_list = raw_text.split("\n");
  raw_list.forEach(current_item => {
    try {
      append(JSON.parse(current_item));
    } catch (error) {}
  });


  if (save_history) {
    while (messages_list.length > history_max_length) {
      messages_list.pop();
    }
  }

  draw();
}

// According to the experiment, the Basilisk is a future powerful evil artificial intelligence
// that will want to punish those who in the past knew of its possibility but did not contribute to its creation.
// Even this knowledge puts the person at risk of punishment...