airaRetail custom UI

Replace specific images with base64 versions on airaTrack login page

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         airaRetail custom UI
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Replace specific images with base64 versions on airaTrack login page
// @author       Alejandrocsdev
// @match        http://127.0.0.1:8082/*
// @include      http://192.168.10.*:8082/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=0.1
// @license      MIT
// @grant        none
// ==/UserScript==

;(function () {
  'use strict'
  const { hash, pathname } = location

  const isLoginPage = () => {
    return pathname === '/' && (hash === '#/' || hash.startsWith('#/?'))
  }

  const isZonePage = () => {
    return pathname === '/' && (hash === '#/zone' || hash.startsWith('#/?'))
  }

  const replaceImgs = () => {
    if (!isLoginPage()) return

    const hairImg = document.querySelector('img[src="/images/attribute/longhair.png"]')
    if (hairImg) {
      hairImg.src =
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAAoCAYAAABjPNNTAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAKaADAAQAAAABAAAAKAAAAAD9QK3vAAADLElEQVRYCe2W/XHbMAzF7V4HcDdgJ6g3qDpB0gnqbuANok4Qb2BngqQTKJ3A7gTSBnYncH9PAe4cRZFI+eOf5N09QwSBB5Aio4xG73hDOzA+dq37/T5D4wrKBjiBwgZW8Dd8GI/HO+xloeZgAWNQEnRzsQ4pNoG30LHlIYdq2ndxxPMUzmABHSUP4azNUkANrqGg5uYxBYnTAkooKG8akzcoBvF7VQElDCkixGuBKyio0aT8qFqI3kChhIMLkOsLLaIKxwapKejIYvPa4hDRjpYmFnVc2nRe+BBcmujyxeQAB1o6o8J2QHp7CmKlFEFoj3juJU43W+fu1Z1ibg2F7Hn2gJFEailEY9KJ1dEoLUeNtt5k/LnFLPp0P/QFMO9F/vTFUjQQowshW8EJ1EUJ2CYezfG1OdEcxzQZLKlqJh+OaSRjrN0OcMNn8LOsjQvmfbG4alRmtZBOxDTpIrs2JYrrtt4ypx1U7B38BgXZRxigzqB2Va9Z49MBwRUUZq7Ksy7GHBbQofM395hDi9/Pn8cueQg2KA9jBz0j5AVkJaxmmljiCF0FNA8XUFhCjYXeJj92CbfMZfj0SvXqH+BfuIr5N4yYioY2xCcjtUkvoP8Pf/pgoNViBS24EzEXp1PgiMmzN/npiOaSU1N30s/Ul+RKTwnB8v6l5Kc2WSGuM6Sb6a8rpd6VBT+mJCU1abf4zgrcpBRiUdfET2GFzkNKblKTJrwwqz/mP2KKEReI01dJ8EU+jU7xS4EcCrnr8awGHXP3t1mCdDRKC157jPnl7v1jPmQnR7wu7eYvK3hLoQLO4EQ+WZhB7Z6aCHADv8PTg0I5FPKmOj41VsI+6HNYL8A1GAdL6t1Jz3nVIrQysVlbkBVTswX077rsGuYwvJKn3Ra2bfNJPkTua6mn21nnMtaZDElCLcGmu2+ZSnMhVJhYpkyer228TFN6GY2O7/yzo9CMjLk4LrCzZB83tYaMozRjmgxWvTLrTSZ92iy3aTbmmDYnDsedTfI61JC4s6+NcoN+QFX/HvfjCw2DZWgys/N3brPoarJzJ0ncwapL4ERzl6hxolbfZc68A/8B8faXaVneiE0AAAAASUVORK5CYII='
    }

    const pantsImg = document.querySelector('img[src="/images/attribute/longpants.png"]')
    if (pantsImg) {
      pantsImg.src =
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACkAAAAoCAYAAABjPNNTAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAKaADAAQAAAABAAAAKAAAAAD9QK3vAAACbElEQVRYCe1X7VEbMRDFDP8DFaAS6CCkEighHWAqwB14UkFKsEuggxMVABU4T8e+sU7SSjqdnB+MNSPvaj/ePu+ebuYuLs7r3IFjBw6Hw2/sU68BBe6OVafa5fSYPP1MWvsaDeAWkbwWPr9WJ1jA/iP4qqjppJr8vxyzSeLZecIesNXx5Mgjzz3jfv6HxHNiUfoskgA3QFhjO0lwqLOWI2Ow/wLP6cRxenLVkDSSaSF3oj/j8XTnlrVBksU22E/Yy5eMBuKwdT9Yw1JUYNyPSF8/O9HXzbgAGASEwjSDeYkA2xBQpOtw2wLAuwe2bkOJs4B5jT142Ns4qtLigRTHjFg3xp3kDJCPuTLw+2PvQtIUChohF4oSUY5dJVlzu0duFbf5Rf6Eu/kr6M9yfhCpib04brSALEm0hO+uDw3AszN2LzZehDsvJqUS+0fK6WxZkvCzMIE0HGefxKKZzKE9l5v1lUhmkwMnyZBc4G4/9iSZYmGdEY+NcVJZVuxG8Xcd91gEY7ZasVZ7qZMnG+EcwiWSVVjeWyCMt2IwoWPOuQtJFGTH7ZziEsuLRowIohfJCLiWQM2rqkTSSDErUhNGHOwK4z5FUbvEwJwskczlpnwhyVTMbFtvkiEBki51cozTLmCJJME5tpAEz1rcWBxB9DM+lNm4WpIECcF5Jol3GnrKEsmltawA3C4B6kXSCIm3RjKcFCcygSmRZBJBJskdD8RnvQl0L5IEZzEWsaIYGlpkiWQtpkayNj8bd5X1Hp1bvMPUD6VjWKSxs+NXYeSNDSY2lT8fXlNJis0R2gc+i7PbNSuVX5N3jvleHfgH6ZqlqhlgwRsAAAAASUVORK5CYII='
    }
  }

  const replacCounts = () => {
    if (!isZonePage()) return

    const updateStatCount = className => {
      const statDiv = document.querySelector(`.${className}`)
      if (!statDiv) return

      const valueContainer = statDiv?.children[1]
      const originalSpan = valueContainer?.firstElementChild?.firstElementChild
      if (!originalSpan || originalSpan.tagName !== 'SPAN') return

      // Hide original
      originalSpan.style.display = 'none'

      // Avoid inserting multiple times
      const existing = valueContainer.querySelector('.custom-zero-span')
      if (existing) return

      // Create new span
      const fakeSpan = document.createElement('span')
      fakeSpan.textContent = '0'
      fakeSpan.className = 'custom-zero-span'

      // Apply your desired CSS
      fakeSpan.style.lineHeight = '1'
      fakeSpan.style.fontWeight = '600'
      fakeSpan.style.color = 'rgb(127 185 122 / var(--un-text-opacity))'
      fakeSpan.style.fontSize = '4rem'

      // Insert before 'ppl' span
      const pplSpan = originalSpan.parentElement.querySelector('span:nth-child(2)')
      originalSpan.parentElement.insertBefore(fakeSpan, pplSpan)
    }

    updateStatCount('stat-1') // Incoming Traffic
    updateStatCount('stat-2') // Zone Traffic
  }

  const observer = new MutationObserver(() => {
    replaceImgs()
    replacCounts()
  })

  observer.observe(document.body, {
    childList: true,
    subtree: true
  })
})()