// ==UserScript==
// @name Komica 定時功能與鎖定畫面
// @namespace http://komica.org
// @version 1.0
// @description 提供懸浮計時功能,並在超時後鎖定畫面提示休息。
// @author Yun
// @match https://gita.komica1.org/*
// @icon https://i.ibb.co/bscXhHh/icon.png
// @license GNU GPLv3
// ==/UserScript==
(function() {
'use strict';
// 插入CSS樣式
const style = document.createElement('style');
style.textContent = `
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.fade-in {
animation: fadeIn 0.5s ease-in-out forwards;
}
.fade-out {
animation: fadeOut 0.5s ease-in-out forwards;
}
.timer-button {
width: 24px;
height: 24px;
background: rgba(68, 68, 68, 0.5);
border: none;
border-radius: 50%;
color: #fff;
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
margin-left: 4px;
transition: background 0.3s ease;
}
.timer-button:hover {
background: rgba(85, 85, 85, 0.7);
}
`;
document.head.appendChild(style);
// 計時相關變數
const TIMER_KEY = 'komica-timer-seconds';
const WARNING_INDEX_KEY = 'komica-warning-index';
const LOCK_STATE_KEY = 'komica-lock-state';
const INITIAL_TIME = 600; // 10分鐘 = 600秒
let seconds = parseInt(localStorage.getItem(TIMER_KEY), 10) || INITIAL_TIME;
let timerInterval = null;
let isPaused = false;
// 插入懸浮計時器
const container = document.createElement('div');
Object.assign(container.style, {
position: 'fixed',
top: '40px',
right: '10px',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
background: 'rgba(30, 30, 30, 0.4)',
padding: '6px 10px',
borderRadius: '8px',
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.2)',
zIndex: '10000',
color: '#ffffff',
fontFamily: 'Arial, sans-serif',
fontSize: '12px',
backdropFilter: 'blur(5px)'
});
const timerDiv = document.createElement('div');
timerDiv.id = 'komica-timer';
Object.assign(timerDiv.style, {
fontWeight: 'bold',
marginRight: '6px'
});
// 更新計時器顯示
const updateTimerDisplay = () => {
const minutes = Math.floor(seconds / 60).toString().padStart(2, '0');
const secs = (seconds % 60).toString().padStart(2, '0');
timerDiv.textContent = `${minutes}:${secs}`;
};
// 計時器核心邏輯
const tick = () => {
if (seconds <= 0) {
clearInterval(timerInterval);
triggerSiteblock();
return;
}
seconds--;
localStorage.setItem(TIMER_KEY, seconds);
updateTimerDisplay();
};
const startTimer = () => {
if (timerInterval) clearInterval(timerInterval);
timerInterval = setInterval(tick, 1000);
};
const stopTimer = () => {
if (timerInterval) {
clearInterval(timerInterval);
timerInterval = null;
}
};
// 重置按鈕
const resetButton = document.createElement('button');
resetButton.innerHTML = '⟳';
resetButton.className = 'timer-button';
resetButton.title = '重置你無謂的人生';
// 播放/暫停按鈕
const playPauseButton = document.createElement('button');
playPauseButton.innerHTML = '⏸︎';
playPauseButton.className = 'timer-button';
playPauseButton.title = '暫停你的墮落時光';
resetButton.addEventListener('click', () => {
if (confirm('真的要重置?反正你的人生也就這樣了!')) {
seconds = INITIAL_TIME;
localStorage.setItem(TIMER_KEY, seconds);
updateTimerDisplay();
if (!isPaused) {
startTimer();
}
}
});
playPauseButton.addEventListener('click', () => {
isPaused = !isPaused;
if (isPaused) {
playPauseButton.innerHTML = '▶︎';
playPauseButton.title = '繼續你可悲的瀏覽';
stopTimer();
} else {
playPauseButton.innerHTML = '⏸︎';
playPauseButton.title = '暫停你的墮落時光';
startTimer();
}
});
container.appendChild(timerDiv);
container.appendChild(playPauseButton);
container.appendChild(resetButton);
document.body.appendChild(container);
// 警告訊息
const warningMessages = [
'哈!又在這裡浪費生命?真有你的!',
'媽媽知道你在這邊當廢物嗎?',
'看來你是打算繼續當個魯蛇了?',
'這就是你的人生價值?在這裡虛度光陰?',
'你以為躲在這裡就能逃避現實?',
'真替你感到可悲,繼續宅下去吧!',
'又在這裡當個失敗者了?',
'外面的世界很可怕?還是你太廢了?',
'這就是你的極限了?真可憐!',
'看來你是打算一輩子當個廢物了!'
];
const getNextWarning = () => {
let currentIndex = parseInt(localStorage.getItem(WARNING_INDEX_KEY), 10) || 0;
const warning = warningMessages[currentIndex];
currentIndex = (currentIndex + 1) % warningMessages.length;
localStorage.setItem(WARNING_INDEX_KEY, currentIndex);
return warning;
};
// 鎖定畫面處理
const triggerSiteblock = () => {
localStorage.setItem(LOCK_STATE_KEY, 'locked');
stopTimer();
const oldOverlay = document.getElementById('komica-siteblock');
if (oldOverlay) {
oldOverlay.remove();
}
const overlay = document.createElement('div');
overlay.id = 'komica-siteblock';
overlay.classList.add('fade-in');
Object.assign(overlay.style, {
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '100%',
background: 'rgba(0, 0, 0, 0.85)',
backdropFilter: 'blur(12px)',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
color: '#ffffff',
zIndex: '10001',
fontFamily: 'Arial, sans-serif'
});
const warningText = document.createElement('div');
warningText.textContent = getNextWarning();
Object.assign(warningText.style, {
fontSize: '24px',
fontWeight: 'bold',
marginBottom: '20px',
textAlign: 'center',
padding: '0 20px'
});
const unlockButton = document.createElement('button');
Object.assign(unlockButton.style, {
padding: '12px 24px',
fontSize: '18px',
background: '#ffffff',
color: '#000000',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
fontWeight: 'bold',
position: 'relative',
overflow: 'hidden'
});
const progressIndicator = document.createElement('div');
Object.assign(progressIndicator.style, {
position: 'absolute',
top: '0',
left: '0',
height: '100%',
width: '0%',
background: 'rgba(0, 128, 0, 0.5)',
borderRadius: '8px',
zIndex: '1',
transition: 'width 0.1s linear'
});
const buttonText = document.createElement('span');
buttonText.textContent = '堅持要繼續浪費生命?按住 5 秒!';
Object.assign(buttonText.style, {
position: 'relative',
zIndex: '2'
});
unlockButton.appendChild(progressIndicator);
unlockButton.appendChild(buttonText);
let pressStartTime = 0;
let isPressed = false;
let progressInterval;
const startUnlockProcess = () => {
isPressed = true;
pressStartTime = Date.now();
progressInterval = setInterval(() => {
if (!isPressed) return;
const progress = Math.min((Date.now() - pressStartTime) / 5000 * 100, 100);
progressIndicator.style.width = `${progress}%`;
if (progress >= 100) {
clearInterval(progressInterval);
overlay.classList.add('fade-out');
setTimeout(() => {
overlay.remove();
localStorage.removeItem(LOCK_STATE_KEY);
seconds = INITIAL_TIME;
localStorage.setItem(TIMER_KEY, seconds);
updateTimerDisplay();
if (!isPaused) {
startTimer();
}
}, 500);
}
}, 100);
};
const stopUnlockProcess = () => {
isPressed = false;
clearInterval(progressInterval);
progressIndicator.style.width = '0%';
};
unlockButton.addEventListener('mousedown', startUnlockProcess);
unlockButton.addEventListener('mouseup', stopUnlockProcess);
unlockButton.addEventListener('mouseleave', stopUnlockProcess);
unlockButton.addEventListener('touchstart', startUnlockProcess);
unlockButton.addEventListener('touchend', stopUnlockProcess);
overlay.appendChild(warningText);
overlay.appendChild(unlockButton);
document.body.appendChild(overlay);
};
// 初始化
updateTimerDisplay();
if (localStorage.getItem(LOCK_STATE_KEY) === 'locked') {
triggerSiteblock();
} else {
startTimer();
}
})();