Ultimate Night Mode

Change websites to pure black background with customization options

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Ultimate Night Mode
// @namespace    (link unavailable)
// @version      0.13
// @description  Change websites to pure black background with customization options
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==

(function () {
  'use strict';

  // Load settings
  const cfg = {
    bgColor: GM_getValue("bgColor", "#000000"),
    textColor: GM_getValue("textColor", "#D3D3D3"), // Light Gray
    linkColor: GM_getValue("linkColor", "#1E90FF"), // Bright Blue
    visitedLinkColor: GM_getValue("visitedLinkColor", "#551A8B"), // Purple
    imgBrightness: GM_getValue("imgBrightness", 0.8),
    imgContrast: GM_getValue("imgContrast", 1.2),
    bgTransparency: GM_getValue("bgTransparency", 1),
    disableAllExceptBg: GM_getValue("disableAllExceptBg", false) // New option to disable all except background color
  };

  // CSS styles
  const css = `
    html, body {
      background-color: ${hexToRgba(cfg.bgColor, cfg.bgTransparency)} !important;
      ${cfg.disableAllExceptBg ? '' : `color: ${cfg.textColor} !important;`}
    }
    ${cfg.disableAllExceptBg ? '' : `
      * {
        background-color: rgba(0, 0, 0, 0.5) !important;
        border-color: #444444 !important;
      }
      a {
        color: ${cfg.linkColor} !important;
      }
      a:visited {
        color: ${cfg.visitedLinkColor} !important;
      }
      img.content-image {
        filter: brightness(${cfg.imgBrightness}) contrast(${cfg.imgContrast});
      }
      video, .html5-video-container video {
        filter: none !important;
      }
    `}
  `;

  // Apply styles
  const style = document.createElement('style');
  style.type = 'text/css';
  style.appendChild(document.createTextNode(css));
  document.head.appendChild(style);

  // Mutation observer to handle dynamic content
  const observer = new MutationObserver(function () {
    document.documentElement.style.backgroundColor = hexToRgba(cfg.bgColor, cfg.bgTransparency);
    document.body.style.backgroundColor = hexToRgba(cfg.bgColor, cfg.bgTransparency);
  });

  // Limit the observer to the body to avoid performance issues
  observer.observe(document.body, { childList: true, subtree: true });

  // Create configuration window
  function openConfigWindow() {
    const div = document.createElement('div');
    div.style.position = 'fixed';
    div.style.top = '10%';
    div.style.left = '50%';
    div.style.transform = 'translateX(-50%)';
    div.style.backgroundColor = '#333';
    div.style.color = '#fff';
    div.style.padding = '20px';
    div.style.border = '1px solid #444';
    div.style.zIndex = '10000';
    div.innerHTML = `
      <h2>Customize Theme</h2>
      <label>BG Color: <input type="color" id="bgColor" value="${cfg.bgColor}"></label><br>
      <label>Text: <input type="color" id="textColor" value="${cfg.textColor}"></label><br>
      <label>Link: <input type="color" id="linkColor" value="${cfg.linkColor}"></label><br>
      <label>Visited: <input type="color" id="visitedLinkColor" value="${cfg.visitedLinkColor}"></label><br>
      <label>Brightness: <input type="range" id="imgBrightness" min="0" max="1" step="0.1" value="${cfg.imgBrightness}"></label><br>
      <label>Contrast: <input type="range" id="imgContrast" min="1" max="2" step="0.1" value="${cfg.imgContrast}"></label><br>
      <label>Transparency: <input type="range" id="bgTransparency" min="0" max="1" step="0.1" value="${cfg.bgTransparency}"></label><br>
      <label>Disable All Except BG Color: <input type="checkbox" id="disableAllExceptBg" ${cfg.disableAllExceptBg ? 'checked' : ''}></label><br>
      <button id="saveConfig">Save</button>
      <button id="closeConfig">Close</button>
    `;
    document.body.appendChild(div);

    // Save configuration
    document.getElementById('saveConfig').addEventListener('click', () => {
      GM_setValue("bgColor", document.getElementById('bgColor').value);
      GM_setValue("textColor", document.getElementById('textColor').value);
      GM_setValue("linkColor", document.getElementById('linkColor').value);
      GM_setValue("visitedLinkColor", document.getElementById('visitedLinkColor').value);
      GM_setValue("imgBrightness", parseFloat(document.getElementById('imgBrightness').value));
      GM_setValue("imgContrast", parseFloat(document.getElementById('imgContrast').value));
      GM_setValue("bgTransparency", parseFloat(document.getElementById('bgTransparency').value));
      GM_setValue("disableAllExceptBg", document.getElementById('disableAllExceptBg').checked);
      location.reload();
    });

    document.getElementById('closeConfig').addEventListener('click', () => {
      div.remove();
    });
  }

  // Convert hex to rgba
  function hexToRgba(hex, alpha) {
    let r = 0, g = 0, b = 0;
    if (hex.length === 4) {
      r = parseInt(hex[1] + hex[1], 16);
      g = parseInt(hex[2] + hex[2], 16);
      b = parseInt(hex[3] + hex[3], 16);
    } else if (hex.length === 7) {
      r = parseInt(hex.slice(1, 3), 16);
      g = parseInt(hex.slice(3, 5), 16);
      b = parseInt(hex.slice(5, 7), 16);
    }
    return `rgba(${r},${g},${b},${alpha})`;
  }

  // Menu command to open configuration window
  if (typeof GM_registerMenuCommand !== "undefined") {
    GM_registerMenuCommand("Customize Theme", openConfigWindow, "C");
  }
})();