Pekora Reborn Script

Part 2 of Pekora Reborn

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         Pekora Reborn Script
// @namespace    pekora reborn
// @version      1.0
// @author       1547
// @description  Part 2 of Pekora Reborn
// @match        https://pekora.zip/*
// @match        https://www.pekora.zip/*
// @run-at       document-start
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  console.log("loading PekoraReborn", location.href);

  const OLD_RE = /Korone/gi;
  const NEW = "Pekora";
  const FAVICON = "https://web.archive.org/web/20250826011158if_/https://www.pekora.zip/favicon.ico";

 // allowed
const allowedSelectors = [
  "title",
  ".navbar", ".navbar-brand", "header", "nav", ".topbar", ".menu", ".nav",
  ".downloadText-0-2-269", ".download", ".card-0-2-268", ".image-0-2-267", ".subTitle-0-2-266",
  ".profile", ".account", ".form-group", "label",
  "h1", "h3", "h5", "p", "button", ".btn", ".pageTitle-0-2-388", ".subTitle-0-2-590",
  ".modalHeaderText-0-2-340", ".modalBody-0-2-341", ".modalContent-0-2-337", ".modalDialog-0-2-336",
  ".newBuyButton-0-2-87", ".button2-0-2-358",

  // allow footer
  ".footerNote-0-2-36",
  ".footerNote-d2-0-2-39",
  ".footerLink-0-2-359"
];



  // blocked
  const blockedSelectors = [
    ".userStatus", ".user-status", ".status", ".profile-status",
    ".userStatus-0-2-195", // User status (specific Korone class)
    ".alertBg-0-2-25",     // Emergency banner (specific Korone class)
    ".body-0-2-141", ".about", ".profile-about",
    ".gameCard", ".gameCardTitle", ".gameCardContainer-0-2-140",
    ".item", ".inventory", ".catalog", ".store",
    ".alert", ".alertText", ".alertLink", ".banner",
    ".chat", ".message", ".messages"
  ];



  function ensureFavicon() {
    try {
      const setHref = (link) => {
        if (!link) return;
        if (link.getAttribute('href') !== FAVICON) link.setAttribute('href', FAVICON);
      };
      let link = document.querySelector('link[rel="icon"]') || document.querySelector('link[href$=".ico"]');
      if (!link) {
        link = document.createElement('link'); link.rel = 'icon'; document.head.appendChild(link);
      }
      setHref(link);
      let shortcut = document.querySelector('link[rel="shortcut icon"]');
      if (!shortcut) {
        shortcut = document.createElement('link'); shortcut.rel = 'shortcut icon'; document.head.appendChild(shortcut);
      }
      setHref(shortcut);
    } catch (e) { console.warn("[PekoraReborn] favicon err", e); }
  }

  function nodeInsideAny(node, selectors) {
    if (!node || !node.parentElement) return false;
    return selectors.some(sel => {
      try { return node.parentElement.closest(sel); } catch (e) { return false; }
    });
  }

  // decides whether a TextNode should be replaced
  function canReplace(textNode) {
    if (!textNode || textNode.nodeType !== Node.TEXT_NODE) return false;
    const txt = textNode.nodeValue;
    if (!txt || !OLD_RE.test(txt)) return false;

    // if its in a prohibited block = dont allow
    if (nodeInsideAny(textNode, blockedSelectors)) return false;

    // if its allowed = allow
    if (nodeInsideAny(textNode, allowedSelectors)) return true;

    // detect loading or button messages with Korone
if (/Korone is now loading|Download and Install Korone|Featured Items on Korone/i.test(txt)) {
  return true;
}


    // if are on .card-body = only allow if are in /download or /setup
    const cardBodyAncestor = textNode.parentElement && textNode.parentElement.closest('.card-body, .card-0-2-268');
    if (cardBodyAncestor) {
      const p = location.pathname || '';
      if (p.includes('/download') || p.includes('/setup')) return true;
      return false;
    }
   // allow change copyright text
  // prevents breaking other rules, but ensures that Footer always changes
  if (/^©/.test(txt.trim())) {
  return true;
}

    // dont replace (for defect)
    return false;
  }

  function replacePreserveCase(str) {
    return str.replace(/Korone|KORONE|korone/gi, match => {
      if (match === match.toUpperCase()) return NEW.toUpperCase();
      if (match[0] === match[0].toUpperCase()) return NEW;
      return NEW.toLowerCase();
    });
  }

  function processTextNode(tn) {
    try {
      if (canReplace(tn)) {
        const original = tn.nodeValue;
        const replaced = replacePreserveCase(original);
        if (replaced !== original) tn.nodeValue = replaced;
      }
    } catch (e) { /* no romper página */ }
  }

  function scanRoot(root) {
    if (!root) return 0;
    const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
    let count = 0;
    let n;
    while ((n = walker.nextNode())) {
      processTextNode(n);
      count++;
    }
    return count;
  }

  function applyAll() {
    try {
      // Prioritize header/nav/footer
      ['header', 'nav', '.navbar', '.topbar', '.menu', '.footer'].forEach(sel => {
        const el = document.querySelector(sel);
        if (el) scanRoot(el);
      });
      // scan downloads/account containers specifically
      const downloadRoot = document.querySelector('.download, .downloadText-0-2-269, .card-0-2-268');
      if (downloadRoot) scanRoot(downloadRoot);
      const accountRoot = document.querySelector('.profile, .account, .form-group');
      if (accountRoot) scanRoot(accountRoot);

      // fallback: scan body but our canReplace prevents changing content
      scanRoot(document.body);

      // title & favicon
      if (OLD_RE.test(document.title)) document.title = replacePreserveCase(document.title);
      ensureFavicon();
    } catch (e) { console.warn("PekoraReborn applyAll err", e); }
  }

  // Observer: process added nodes and characterData
  const mo = new MutationObserver((mutations) => {
    for (const m of mutations) {
      if (m.type === 'characterData' && m.target && m.target.nodeType === Node.TEXT_NODE) {
        processTextNode(m.target);
      }
      if (m.addedNodes && m.addedNodes.length) {
        m.addedNodes.forEach(node => {
          if (node.nodeType === Node.TEXT_NODE) processTextNode(node);
          else if (node.nodeType === Node.ELEMENT_NODE) scanRoot(node);
        });
      }
    }
  });

  function hookHistory() {
    const wrap = (orig) => function() {
      const res = orig.apply(this, arguments);
      setTimeout(applyAll, 120);
      return res;
    };
    history.pushState = wrap(history.pushState);
    history.replaceState = wrap(history.replaceState);
    window.addEventListener('popstate', () => setTimeout(applyAll, 120));
  }

  // Safe init
  function init() {
    console.log("PekoraReborn init");
    try {
      applyAll();
      try { mo.observe(document.documentElement || document.body, { childList: true, subtree: true, characterData: true }); } catch(e) { mo.observe(document.body, { childList: true, subtree: true, characterData: true }); }
      hookHistory();
      // fallback: run again a little later if something prevents observer
      setTimeout(applyAll, 800);
      // extra safety: if VM didn't get DOMContentLoaded, run periodically a couple times
      let tries = 0;
      const t = setInterval(() => { if (tries++ > 5) return clearInterval(t); applyAll(); }, 1000);
    } catch(e) { console.error("[PekoraReborn] init error", e); }
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
    // also try early
    setTimeout(() => { if (document.readyState !== 'complete') init(); }, 200);
  } else init();

})();