Smart Page Auto Refresh

Smoothly refreshes web pages when changed. Press Ctrl+R to start auto refresh

  1. // ==UserScript==
  2. // @name Smart Page Auto Refresh
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.9
  5. // @description Smoothly refreshes web pages when changed. Press Ctrl+R to start auto refresh
  6. // @author kequn yang
  7. // @match *://*/*
  8. // @match file:///*
  9. // @match http://127.0.0.1:*/*
  10. // @match http://localhost:*/*
  11. // @grant GM_addStyle
  12. // @run-at document-end
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18. const REFRESH_INTERVAL = 1000;
  19. const STORAGE_KEY = 'autoRefreshEnabled';
  20. let isRefreshing = false;
  21. let refreshTimer = null;
  22. let lastContent = '';
  23. let notificationTimeout = null;
  24.  
  25. // 添加样式
  26. GM_addStyle(`
  27. .refresh-notification {
  28. position: fixed;
  29. top: 20px;
  30. right: 20px;
  31. padding: 12px 24px;
  32. background-color: rgba(33, 150, 243, 0.95);
  33. color: white;
  34. border-radius: 8px;
  35. font-family: Arial, sans-serif;
  36. font-size: 14px;
  37. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  38. z-index: 9999;
  39. opacity: 0;
  40. transform: translateX(100px);
  41. transition: all 0.3s ease-in-out;
  42. }
  43. .refresh-notification.show {
  44. opacity: 1;
  45. transform: translateX(0);
  46. }
  47. .refresh-notification.success {
  48. background-color: rgba(76, 175, 80, 0.95);
  49. }
  50. .refresh-notification.error {
  51. background-color: rgba(244, 67, 54, 0.95);
  52. }
  53. `);
  54.  
  55. // 显示通知
  56. function showNotification(message, type = 'info') {
  57. // 移除现有通知
  58. const existingNotification = document.querySelector('.refresh-notification');
  59. if (existingNotification) {
  60. existingNotification.remove();
  61. }
  62. // 清除现有计时器
  63. if (notificationTimeout) {
  64. clearTimeout(notificationTimeout);
  65. }
  66.  
  67. // 创建新通知
  68. const notification = document.createElement('div');
  69. notification.className = `refresh-notification ${type}`;
  70. notification.textContent = message;
  71. document.body.appendChild(notification);
  72.  
  73. // 触发动画
  74. setTimeout(() => {
  75. notification.classList.add('show');
  76. }, 10);
  77.  
  78. // 2秒后淡出
  79. notificationTimeout = setTimeout(() => {
  80. notification.style.opacity = '0';
  81. notification.style.transform = 'translateX(100px)';
  82. setTimeout(() => {
  83. notification.remove();
  84. }, 300);
  85. }, 2000);
  86. }
  87.  
  88. function isLocalFile() {
  89. return window.location.protocol === 'file:';
  90. }
  91.  
  92. async function checkForChanges() {
  93. if (!isRefreshing) return;
  94.  
  95. try {
  96. const response = await fetch(window.location.href, {
  97. cache: 'no-store'
  98. });
  99.  
  100. if (!response.ok) throw new Error('Network response was not ok');
  101. const newContent = await response.text();
  102.  
  103. if (newContent !== lastContent) {
  104. console.log('Content changed, refreshing...');
  105. lastContent = newContent;
  106. window.location.reload();
  107. }
  108. } catch (error) {
  109. console.error('Refresh error:', error);
  110. showNotification('Auto refresh error!', 'error');
  111. stopAutoRefresh();
  112. }
  113. }
  114.  
  115. function startAutoRefresh() {
  116. if (isRefreshing) return;
  117.  
  118. fetch(window.location.href, {
  119. cache: 'no-store'
  120. }).then(response => response.text())
  121. .then(content => {
  122. lastContent = content;
  123. isRefreshing = true;
  124. localStorage.setItem(STORAGE_KEY, 'true');
  125.  
  126. if (refreshTimer) {
  127. clearInterval(refreshTimer);
  128. }
  129.  
  130. refreshTimer = setInterval(checkForChanges, REFRESH_INTERVAL);
  131. showNotification('Auto refresh turned ON', 'success');
  132. console.log('Auto refresh started');
  133. })
  134. .catch(error => {
  135. console.error('Error starting auto refresh:', error);
  136. showNotification('Failed to start auto refresh!', 'error');
  137. });
  138. }
  139.  
  140. function stopAutoRefresh() {
  141. if (!isRefreshing) return;
  142.  
  143. isRefreshing = false;
  144. localStorage.setItem(STORAGE_KEY, 'false');
  145.  
  146. if (refreshTimer) {
  147. clearInterval(refreshTimer);
  148. refreshTimer = null;
  149. }
  150.  
  151. showNotification('Auto refresh turned OFF', 'error');
  152. console.log('Auto refresh stopped');
  153. }
  154.  
  155. function handleKeyPress(e) {
  156. if (e.ctrlKey && (e.key === 'r' || e.key === 'R')) {
  157. e.preventDefault();
  158. if (isRefreshing) {
  159. stopAutoRefresh();
  160. } else {
  161. startAutoRefresh();
  162. }
  163. }
  164. }
  165.  
  166. // 初始化
  167. function initialize() {
  168. document.addEventListener('keydown', handleKeyPress);
  169.  
  170. // 获取保存的状态
  171. const savedState = localStorage.getItem(STORAGE_KEY);
  172. if (savedState === 'true') {
  173. startAutoRefresh();
  174. }
  175. }
  176.  
  177. // 打印使用说明
  178. console.log(`%cSmart Page Auto Refresh Instructions`, 'font-size: 16px; font-weight: bold; color: #2196F3');
  179. console.log(`%cAutomatically refresh web pages. Press Ctrl+R to start/stop page refresh.`, 'color: #4CAF50');
  180. console.log(`\n%cFor CORS problem of local file, start Chrome with these parameters:`, 'color: #FF5722');
  181. console.log(`%c# MacOS`, 'color: #9C27B0');
  182. console.log(`open -a "Google Chrome" --args --allow-file-access-from-files --disable-web-security --user-data-dir="~/ChromeDevSession"`);
  183. console.log(`\n%c# Windows`, 'color: #9C27B0');
  184. console.log(`chrome.exe --allow-file-access-from-files --disable-web-security --user-data-dir=C:\\ChromeDevSession`);
  185. console.log(`\n%c# Linux`, 'color: #9C27B0');
  186. console.log(`google-chrome --allow-file-access-from-files --disable-web-security --user-data-dir="~/ChromeDevSession"`);
  187.  
  188. // 运行初始化
  189. initialize();
  190.  
  191. // 在页面卸载前清理
  192. window.addEventListener('unload', () => {
  193. if (refreshTimer) {
  194. clearInterval(refreshTimer);
  195. }
  196. });
  197. })();