- 去支持Tempermonkey的浏览器的Add-ons安装
- 代码
- https://pomodoro.pomodorotechnique.com/ 打开后刷新一次
// ==UserScript==
// @name Automated Pomodoro with Long Break
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Automated Pomodoro cycles with long breaks after user-defined intervals (e.g., every 4 pomodoros with 15 or 50 minutes break options)
// @author Syl
// @match https://pomodoro.pomodorotechnique.com/*
// @grant none
// ==/UserScript==(function () {'use strict';let isRunning = false;let timeoutHandles = [];function findButtonByText(text) {const buttons = Array.from(document.querySelectorAll('button'));return buttons.find(button => button.textContent.trim() === text);}function simulateUserClick(element) {if (!element) return console.error("Element not found.");const mouseDownEvent = new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window });const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, view: window });element.dispatchEvent(mouseDownEvent);element.dispatchEvent(clickEvent);}function waitForButton(text, callback) {const interval = setInterval(() => {if (!isRunning) {clearInterval(interval);return;}const button = findButtonByText(text);if (button) {clearInterval(interval);callback(button);}}, 500);}function startPomodoroCycles(cycles, longBreakInterval, longBreakTime) {let currentCycle = 0;function runCycle() {if (!isRunning) return;if (currentCycle >= cycles) {console.log("All Pomodoro cycles completed!");endPomodoroProcess();return;}console.log(`Starting pomodoro cycle ${currentCycle + 1}`);waitForButton("Wind Up", (windUpButton) => {console.log("Clicking Wind Up button...");simulateUserClick(windUpButton);const workTimeout = setTimeout(() => {if (!isRunning) return;console.log(`Work session for cycle ${currentCycle + 1} completed.`);if (longBreakInterval > 0 && (currentCycle + 1) % longBreakInterval === 0) {console.log(`Long break required after cycle ${currentCycle + 1}.`);waitForPageState("Take a break").then(() => {const longBreakText = longBreakTime === 15 ? "15" : "30";waitForButton(longBreakText, (longBreakButton) => {simulateUserClick(longBreakButton);const longBreakTimeout = setTimeout(() => {if (!isRunning) return;currentCycle++;runCycle();}, longBreakTime * 60 * 1000);timeoutHandles.push(longBreakTimeout);});});} else {currentCycle++;runCycle();}}, 30 * 1000 * 60);timeoutHandles.push(workTimeout);});}runCycle();}function endPomodoroProcess() {console.log("Pomodoro process ended.");isRunning = false;}function stopPomodoro() {console.log("Stopping Pomodoro...");isRunning = false;timeoutHandles.forEach(handle => clearTimeout(handle));timeoutHandles = [];}function waitForPageState(targetText, timeout = 30000) {return new Promise((resolve, reject) => {const interval = 500;let elapsedTime = 0;const checkState = setInterval(() => {elapsedTime += interval;if (elapsedTime > timeout) {clearInterval(checkState);console.error(`Timeout: Page did not reach the expected state with text "${targetText}".`);resolve(null);return;}const targetElement = Array.from(document.querySelectorAll('button, div, span')).find(el => el.textContent.trim() === targetText);if (targetElement) {clearInterval(checkState);resolve(targetElement);}}, interval);});}const inputContainer = document.createElement('div');inputContainer.style.position = 'fixed';inputContainer.style.top = '100px';inputContainer.style.right = '25px';inputContainer.style.backgroundColor = 'white';inputContainer.style.border = '2px solid grey';inputContainer.style.borderRadius = '10px'; // 添加圆角样式inputContainer.style.padding = '10px';inputContainer.style.zIndex = '1000';inputContainer.style.display = 'flex';inputContainer.style.flexDirection = 'column';inputContainer.style.gap = '10px';const cyclesRow = document.createElement('div');cyclesRow.style.display = 'flex';cyclesRow.style.alignItems = 'center';cyclesRow.style.justifyContent = 'space-between';const inputLabel1 = document.createElement('label');inputLabel1.textContent = 'Number of cycles: ';const inputBox1 = document.createElement('input');inputBox1.type = 'number';inputBox1.min = '1';inputBox1.value = '4';inputBox1.style.width = '60px';cyclesRow.appendChild(inputLabel1);cyclesRow.appendChild(inputBox1);const everyRow = document.createElement('div');everyRow.style.display = 'flex';everyRow.style.alignItems = 'center';everyRow.style.justifyContent = 'space-between';const inputLabel2 = document.createElement('label');inputLabel2.textContent = 'Long break after every: ';const inputBox2 = document.createElement('input');inputBox2.type = 'number';inputBox2.min = '0';inputBox2.value = '0';inputBox2.style.width = '60px';everyRow.appendChild(inputLabel2);everyRow.appendChild(inputBox2);const durationRow = document.createElement('div');durationRow.style.display = 'flex';durationRow.style.alignItems = 'center';durationRow.style.justifyContent = 'space-between';const inputLabel3 = document.createElement('label');inputLabel3.textContent = 'Long break duration: ';const selectBox = document.createElement('select');selectBox.style.width = '80px';const option15 = document.createElement('option');option15.value = '15';option15.textContent = '15 min';const option30 = document.createElement('option');option30.value = '30';option30.textContent = '30 min';selectBox.appendChild(option15);selectBox.appendChild(option30);durationRow.appendChild(inputLabel3);durationRow.appendChild(selectBox);const buttonRow = document.createElement('div');buttonRow.style.display = 'flex';buttonRow.style.justifyContent = 'space-between';const startButton = document.createElement('button');startButton.textContent = 'Start';const endButton = document.createElement('button');endButton.textContent = 'End';buttonRow.appendChild(startButton);buttonRow.appendChild(endButton);inputContainer.appendChild(cyclesRow);inputContainer.appendChild(everyRow);inputContainer.appendChild(durationRow);inputContainer.appendChild(buttonRow);document.body.appendChild(inputContainer);startButton.addEventListener('click', () => {const cycles = parseInt(inputBox1.value, 10);const longBreakInterval = parseInt(inputBox2.value, 10);const longBreakTime = parseInt(selectBox.value, 10);if (!isNaN(cycles) && !isNaN(longBreakInterval) && !isNaN(longBreakTime) && cycles > 0) {isRunning = true;startPomodoroCycles(cycles, longBreakInterval, longBreakTime);} else {alert('Please enter valid numbers for cycles and long break settings.');}});endButton.addEventListener('click', () => {stopPomodoro();alert("Pomodoro cycle stopped.");});
})();