Enable dark mode with a toggle button and automatically based on location
当前为
// ==UserScript==
// @name Dark Mode Auto Toggle
// @version 0.0.5
// @description Enable dark mode with a toggle button and automatically based on location
// @namespace https://greasyfork.org/en/users/28298
// @author https://greasyfork.org/en/users/28298
// @homepage https://greasyfork.org/en/scripts/523690
// @license MIT
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
// @grant none
// original author: Michael Wang https://greasyfork.org/en/scripts/472251-dark-mode/code
// with help of claude ai
(function() {
'use strict';
// Create style element for dark mode
const darkStyle = document.createElement('style');
darkStyle.textContent = `
html {
filter: invert(1) hue-rotate(180deg) contrast(0.8);
}
/** reverse filter for media elements */
img, video, picture, canvas, iframe, embed {
filter: invert(1) hue-rotate(180deg);
}
`;
// Initialize based on page's current state
let darkMode = false; // Start with no filter
// Function to detect if page is already dark
function isPageDark() {
const url = window.location.hostname;
////////////////////////////////////////////////////////////////////
// manually tell domain's mode, because auto detection would fail
const domainModes = {
'claude.ai': 'bright',
'chat.openai.com': 'dark',
'duckduckgo.com': 'dark',
'greasyfork.org': 'bright',
};
///////////////////////////////////////////////////////////////////
// Check if domain is in our list
for (const domain in domainModes) {
if (url.includes(domain)) {
return domainModes[domain] === 'dark';
}
}
// easy solution, but not always accurate
return document.documentElement.classList.contains('dark')
// const bodyBg = window.getComputedStyle(document.body).backgroundColor;
// const htmlBg = window.getComputedStyle(document.documentElement).backgroundColor;
// // Convert RGB/RGBA to brightness value (0-255)
// function getBrightness(color) {
// const rgb = color.match(/\d+/g);
// if (!rgb) return 255; // Default to light if can't detect
// // Use perceived brightness formula
// return (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
// }
// const bodyBrightness = getBrightness(bodyBg);
// const htmlBrightness = getBrightness(htmlBg);
// // Use the darker of the two values
// const brightness = Math.min(bodyBrightness, htmlBrightness);
// return brightness < 128; // Consider it dark if brightness is less than middle gray
}
// Initialize darkMode based on stored preference or page state
const pageIsDark = isPageDark();
// Create toggle button
const button = document.createElement('button');
button.innerHTML = pageIsDark ? '☼' : '☽';
button.style.position = 'fixed';
button.style.top = '5px';
button.style.right = '10px';
button.style.zIndex = '1000';
button.style.background = 'none';
button.style.border = 'none';
button.style.fontSize = '24px';
button.style.cursor = 'pointer';
button.style.color = 'inherit';
// Function to get location and store it
async function setupLocation() {
let location = GM_getValue('userLocation');
if (!location) {
try {
const position = await new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
location = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
timestamp: Date.now()
};
GM_setValue('userLocation', location);
console.log('Location saved successfully');
} catch (error) {
console.error('Error getting location:', error);
// Default to a fallback location (e.g., UTC+0)
location = {
latitude: 51.5074, // London coordinates as fallback
longitude: -0.1278,
timestamp: Date.now()
};
GM_setValue('userLocation', location);
}
}
return location;
}
// Function to get sunrise/sunset times using stored location
async function getSunTimes() {
try {
const location = await setupLocation();
const response = await fetch(
`https://api.sunrise-sunset.org/json?lat=${location.latitude}&lng=${location.longitude}&formatted=0`
);
const data = await response.json();
return {
sunrise: new Date(data.results.sunrise),
sunset: new Date(data.results.sunset)
};
} catch (error) {
console.error('Error getting sun times:', error);
// Fallback to approximate times
const now = new Date();
return {
sunrise: new Date(now.setHours(6, 0, 0, 0)),
sunset: new Date(now.setHours(18, 0, 0, 0))
};
}
}
// Function to toggle dark mode
function toggleDarkMode(forceDark) {
if (forceDark !== undefined) {
// Auto dark mode (sunrise/sunset)
if (pageIsDark) {
// If page is already dark, don't change anything
return;
}
darkMode = forceDark;
} else {
// Manual toggle - always allow regardless of pageIsDark
darkMode = !darkMode;
}
if (darkMode) {
document.head.appendChild(darkStyle);
button.innerHTML = pageIsDark ? '☽' : '☼';
} else {
if (darkStyle.parentNode) {
document.head.removeChild(darkStyle);
}
button.innerHTML = pageIsDark ? '☼' : '☽';
}
}
// Function to check and update dark mode based on time
async function updateDarkMode() {
const sunTimes = await getSunTimes();
const now = new Date();
const isDark = now < sunTimes.sunrise || now > sunTimes.sunset;
toggleDarkMode(isDark);
}
// Add settings button
const settingsButton = document.createElement('button');
settingsButton.innerHTML = '⚙';
settingsButton.style.position = 'fixed';
settingsButton.style.top = '30px';
settingsButton.style.right = '15px';
settingsButton.style.zIndex = '1000';
settingsButton.style.background = 'none';
settingsButton.style.border = 'none';
settingsButton.style.fontSize = '12px';
settingsButton.style.cursor = 'pointer';
settingsButton.style.color = 'inherit';
// Settings panel to reset location
settingsButton.addEventListener('click', () => {
if (confirm('Reset location settings?')) {
GM_setValue('userLocation', null);
location.reload();
}
});
// Initial update
updateDarkMode();
// Update every hour
setInterval(updateDarkMode, 3600000);
// Manual toggle still works
button.addEventListener('click', () => toggleDarkMode());
// Add buttons to page
document.body.appendChild(button);
document.body.appendChild(settingsButton);
})();