GitHub Freshness

通过颜色高亮的方式,帮助你快速判断一个 GitHub 仓库是否在更新。

目前为 2025-01-22 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name GitHub Freshness
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.0.1
  5. // @description 通过颜色高亮的方式,帮助你快速判断一个 GitHub 仓库是否在更新。
  6. // @author 向前 https://rational-stars.top/
  7. // @match https://github.com/*
  8. // @grant GM_registerMenuCommand
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15.  
  16. // === 配置项 ===
  17. let HIGHLIGHT_COLOR = GM_getValue('highlightColor', '#82de82'); // 小于指定时间范围的背景色
  18. let GREY_COLOR = GM_getValue('greyColor', '#e3d711'); // 大于指定时间范围的背景色
  19. let TIME_THRESHOLD_MONTHS = GM_getValue('timeThresholdMonths', 2); // 时间阈值(月)
  20.  
  21. let isHighlighting = false; // 防止重复触发
  22. let currentURL = location.href;
  23.  
  24. // === 创建设置面板 ===
  25. function createSettingsPanel() {
  26. const panel = document.createElement('div');
  27. panel.style.position = 'fixed';
  28. panel.style.top = '10px';
  29. panel.style.right = '10px';
  30. panel.style.padding = '10px';
  31. panel.style.backgroundColor = '#fff';
  32. panel.style.border = '1px solid #ccc';
  33. panel.style.zIndex = '9999';
  34. panel.style.display = 'none'; // 初始隐藏面板
  35.  
  36. panel.innerHTML = `
  37. <h3>GitHub Freshness 设置</h3>
  38. <label for="highlightColor">背景色(小于指定时间范围):</label>
  39. <input type="color" id="highlightColor" value="${HIGHLIGHT_COLOR}" /><br><br>
  40.  
  41. <label for="greyColor">背景色(大于指定时间范围):</label>
  42. <input type="color" id="greyColor" value="${GREY_COLOR}" /><br><br>
  43.  
  44. <label for="timeThresholdMonths">时间阈值(月):</label>
  45. <input type="number" id="timeThresholdMonths" value="${TIME_THRESHOLD_MONTHS}" min="1" /><br><br>
  46.  
  47. <button id="saveSettings">保存设置</button>
  48. `;
  49.  
  50. document.body.appendChild(panel);
  51.  
  52. // 保存设置
  53. document.getElementById('saveSettings').addEventListener('click', () => {
  54. // 获取设置并保存
  55. HIGHLIGHT_COLOR = document.getElementById('highlightColor').value;
  56. GREY_COLOR = document.getElementById('greyColor').value;
  57. TIME_THRESHOLD_MONTHS = parseInt(document.getElementById('timeThresholdMonths').value, 10);
  58.  
  59. // 保存到油猴存储
  60. GM_setValue('highlightColor', HIGHLIGHT_COLOR);
  61. GM_setValue('greyColor', GREY_COLOR);
  62. GM_setValue('timeThresholdMonths', TIME_THRESHOLD_MONTHS);
  63.  
  64. // 隐藏设置面板
  65. panel.style.display = 'none';
  66.  
  67. // 应用新的设置,立即执行高亮
  68. highlightDates();
  69. });
  70. }
  71.  
  72. // === 核心函数 ===
  73. function highlightDates() {
  74. if (isHighlighting) return; // 防止重复执行
  75. isHighlighting = true; // 设置标志为正在执行
  76.  
  77. const now = new Date();
  78. const elements = document.querySelectorAll('.sc-aXZVg');
  79. if (elements.length === 0) {
  80. console.log('没有找到日期元素');
  81. isHighlighting = false;
  82. return;
  83. }
  84.  
  85. elements.forEach(element => {
  86. const datetime = element.getAttribute('datetime');
  87. if (datetime) {
  88. const date = new Date(datetime);
  89. const timeDiff = now - date;
  90. const daysDiff = timeDiff / (1000 * 3600 * 24);
  91. const monthsDiff = daysDiff / 30;
  92.  
  93. // 找到最近的祖先 td 元素
  94. const tdElement = element.closest('td');
  95. if (tdElement) {
  96. element.style.setProperty('color', '#fff', 'important');
  97. if (monthsDiff <= TIME_THRESHOLD_MONTHS) {
  98. tdElement.style.setProperty('background-color', HIGHLIGHT_COLOR, 'important');
  99. } else {
  100. tdElement.style.setProperty('background-color', GREY_COLOR, 'important');
  101. }
  102. }
  103. }
  104. });
  105.  
  106. isHighlighting = false; // 执行完毕,重置标志
  107. }
  108.  
  109. // === URL 更新后的逻辑 ===
  110. function onUrlChange() {
  111. if (currentURL !== location.href) {
  112. currentURL = location.href;
  113. console.log('URL 发生变化:', currentURL);
  114.  
  115. // 检查 URL 是否符合 https://github.com/*/*/tree/* 格式
  116. const regex = /^https:\/\/github\.com\/[^/]+\/[^/]+\/tree\/[^/]+/;
  117. if (regex.test(location.href)) {
  118. console.log('符合 GitHub 目录树页面格式');
  119.  
  120. // 检查 code-tab 是否存在且包含 selected 类名
  121. const codeTab = document.getElementById('code-tab');
  122. if (codeTab && codeTab.classList.contains('selected')) {
  123. console.log('code-tab 存在并被选中,开始执行高亮代码');
  124. setTimeout(() => {
  125. highlightDates();
  126. }, 1000); // 延迟 1 秒,等待页面加载
  127. } else {
  128. console.log('code-tab 不存在或未被选中,跳过高亮代码');
  129. }
  130. } else {
  131. console.log('不符合 GitHub 目录树页面格式,跳过高亮代码');
  132. }
  133. }
  134. }
  135.  
  136. // === 监听 URL 和 DOM 变化 ===
  137. const observer = new MutationObserver(() => {
  138. const codeTab = document.getElementById('code-tab');
  139. if (codeTab && codeTab.classList.contains('selected')) {
  140. highlightDates();
  141. }
  142. });
  143.  
  144. observer.observe(document.body, {
  145. childList: true,
  146. subtree: true,
  147. });
  148.  
  149. setInterval(onUrlChange, 1000);
  150.  
  151. setTimeout(() => {
  152. const codeTab = document.getElementById('code-tab');
  153. if (codeTab && codeTab.classList.contains('selected')) {
  154. highlightDates();
  155. }
  156. }, 1000);
  157.  
  158. // === 防止滚动时重复触发 ===
  159. let isScrolling = false;
  160. window.addEventListener('scroll', () => {
  161. if (!isScrolling) {
  162. isScrolling = true;
  163. setTimeout(() => {
  164. isScrolling = false; // 滚动结束后重新允许触发
  165. }, 100);
  166. }
  167. });
  168.  
  169. // === 初始化设置面板 ===
  170. createSettingsPanel();
  171.  
  172. // === 使用油猴菜单显示/隐藏设置面板 ===
  173. GM_registerMenuCommand('⚙️ 设置面板', () => {
  174. const panel = document.querySelector('div[style*="position: fixed"]');
  175. if (panel) {
  176. panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
  177. }
  178. });
  179.  
  180. // === 页面加载时自动执行高亮 ===
  181. highlightDates(); // 确保在初始化时执行高亮逻辑
  182. })();