// ==UserScript== // @name 定时提醒工具 // @namespace http://tampermonkey.net/ // @version 1.3.3 // @description 提供定时提醒、倒计时功能,并支持自定义提醒事件。用户可以设置每日重复的提醒事件,每个事件在同一时间只会提醒一次;倒计时功能允许用户设置一个倒计时,时间到后会提醒用户。 // @author wll // @match *://*/* // @grant GM_notification // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_getValue // @grant GM_setValue // @license AGPL-3.0-or-later // @downloadURL https://update.greasyfork.icu/scripts/508670/%E5%AE%9A%E6%97%B6%E6%8F%90%E9%86%92%E5%B7%A5%E5%85%B7.user.js // @updateURL https://update.greasyfork.icu/scripts/508670/%E5%AE%9A%E6%97%B6%E6%8F%90%E9%86%92%E5%B7%A5%E5%85%B7.meta.js // ==/UserScript== (function() { 'use strict'; const defaultReminders = [ { event: '喝水', time: '09:00', type: 'daily' }, { event: '休息一下', time: '10:30', type: 'daily' }, { event: '吃午饭', time: '12:00', type: 'daily' }, { event: '喝水', time: '14:00', type: 'daily' }, { event: '休息一下', time: '15:30', type: 'daily' }, { event: '吃晚饭', time: '18:00', type: 'daily' }, { event: '运动', time: '19:00', type: 'daily' }, ]; function loadReminders() { const savedReminders = GM_getValue('reminders'); return savedReminders || defaultReminders; } function saveReminders(reminders) { GM_setValue('reminders', reminders); } function loadButtonPosition() { const position = GM_getValue('buttonPosition'); return position || { top: '10px', left: '10px' }; } function saveButtonPosition(position) { GM_setValue('buttonPosition', position); } function loadButtonVisibility() { return GM_getValue('buttonVisibility', true); } function saveButtonVisibility(visibility) { GM_setValue('buttonVisibility', visibility); } const settingsHTML = ` `; document.body.insertAdjacentHTML('beforeend', settingsHTML); const buttonPosition = loadButtonPosition(); const openSettingsButton = document.getElementById('open-settings'); openSettingsButton.style.top = buttonPosition.top; openSettingsButton.style.left = buttonPosition.left; const buttonVisibility = loadButtonVisibility(); openSettingsButton.style.display = buttonVisibility ? 'block' : 'none'; GM_addStyle(` #reminder-settings input, #reminder-settings select, #reminder-settings button { margin: 5px 0; } #reminder-list div { display: flex; align-items: center; margin-bottom: 5px; } #reminder-list div .event, #reminder-list div .time { margin-right: 10px; flex-grow: 1; } #reminder-list div .type { flex-grow: 2; margin-right: 10px; } #reminder-list div button { flex-grow: 0; } `); function loadReminderList() { const reminders = loadReminders(); const reminderList = document.getElementById('reminder-list'); reminderList.innerHTML = ''; reminders.forEach((reminder, index) => { const reminderDiv = document.createElement('div'); reminderDiv.innerHTML = ` `; reminderList.appendChild(reminderDiv); }); } function autoSaveReminder() { const reminders = []; document.querySelectorAll('#reminder-list div').forEach(div => { const event = div.querySelector('.event').value; const time = div.querySelector('.time').value; const type = div.querySelector('.type').value; if (event.trim() !== '') { reminders.push({ event, time, type }); } }); saveReminders(reminders); } function showSettings() { document.getElementById('reminder-settings').style.display = 'block'; loadReminderList(); } function hideSettings() { document.getElementById('reminder-settings').style.display = 'none'; } document.getElementById('open-settings').addEventListener('click', (e) => { e.stopPropagation(); const settingsDiv = document.getElementById('reminder-settings'); if (settingsDiv.style.display === 'none') { showSettings(); } else { hideSettings(); } }); document.getElementById('close-settings').addEventListener('click', hideSettings); window.addEventListener('click', (event) => { const settingsDiv = document.getElementById('reminder-settings'); if (settingsDiv.style.display !== 'none' && !settingsDiv.contains(event.target) && event.target !== openSettingsButton) { hideSettings(); } }); GM_registerMenuCommand('显示/隐藏提醒设置按钮', () => { const currentVisibility = openSettingsButton.style.display === 'block'; openSettingsButton.style.display = currentVisibility ? 'none' : 'block'; saveButtonVisibility(!currentVisibility); }); function makeElementDraggable(el) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; el.onmousedown = dragMouseDown; function dragMouseDown(e) { e = e || window.event; e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e = e || window.event; e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; el.style.top = (el.offsetTop - pos2) + "px"; el.style.left = (el.offsetLeft - pos1) + "px"; saveButtonPosition({ top: el.style.top, left: el.style.left }); } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; } } makeElementDraggable(openSettingsButton); document.getElementById('add-reminder').addEventListener('click', () => { const reminders = loadReminders(); const now = new Date(); const currentTime = now.toTimeString().substr(0, 5); reminders.push({ event: '', time: currentTime, type: 'daily' }); saveReminders(reminders); loadReminderList(); }); document.getElementById('reminder-list').addEventListener('input', autoSaveReminder); document.getElementById('reminder-list').addEventListener('click', (e) => { if (e.target.classList.contains('delete-reminder')) { e.stopPropagation(); const index = e.target.getAttribute('data-index'); const reminders = loadReminders(); reminders.splice(index, 1); saveReminders(reminders); loadReminderList(); } }); const notifiedTimes = new Set(); function checkAndNotify() { const now = new Date(); const currentTime = now.toTimeString().substr(0, 5); let reminders = loadReminders(); reminders.forEach(reminder => { if (currentTime === reminder.time && !notifiedTimes.has(reminder.time + reminder.event)) { if (reminder.event.trim() !== '') { GM_notification({ title: '定时提醒', text: `该${reminder.event}了!`, timeout: 10000, onclick: () => { console.log(`你点击了${reminder.event}提醒`); } }); notifiedTimes.add(reminder.time + reminder.event); } } }); // Remove entries from notifiedTimes set to avoid memory issues notifiedTimes.forEach(key => { if (!reminders.some(reminder => reminder.time + reminder.event === key && reminder.time === currentTime)) { notifiedTimes.delete(key); } }); } setInterval(() => { notifiedTimes.clear(); }, 60000); document.getElementById('start-countdown').addEventListener('click', () => { const minutes = parseInt(document.getElementById('countdown-minutes').value, 10); if (!isNaN(minutes) && minutes > 0) { GM_notification({ title: '倒计时提醒', text: `倒计时${minutes}分钟开始!`, timeout: 5000 }); hideSettings(); setTimeout(() => { GM_notification({ title: '倒计时提醒', text: `倒计时${minutes}分钟结束!`, timeout: 10000 }); }, minutes * 60000); } else { alert('请输入有效的分钟数'); } }); setInterval(checkAndNotify, 1000); checkAndNotify(); })();