// ==UserScript== // @name GitHub Release Platform Filter // @name:en GitHub Release Platform Filter // @namespace http://tampermonkey.net/ // @version 0.1 // @description Filter GitHub release assets by platform // @description:en Filter GitHub release assets by platform and optimize release notes display // @author EEP // @match https://github.com/*/*/releases* // @grant GM_setValue // @grant GM_getValue // @license MIT // @downloadURL none // ==/UserScript== (function () { 'use strict'; // 立即注入全局样式 const style = document.createElement('style'); style.textContent = ` .markdown-body { max-height: 300px !important; overflow: hidden !important; position: relative !important; } .markdown-body[data-processed] { max-height: none; overflow: visible; } `; document.head.appendChild(style); // 平台类型定义 const PLATFORMS = { MACOS: { name: 'macOS', patterns: ['darwin', 'macos', 'mac'], }, WINDOWS: { name: 'Windows', patterns: ['win', 'windows'], }, LINUX: { name: 'Linux', patterns: ['linux'], }, ANDROID: { name: 'Android', patterns: ['android'], }, }; // 创建筛选器UI function createFilterUI() { const container = document.createElement('div'); container.style.cssText = ` position: fixed; top: 70px; right: 10px; z-index: 100; display: flex; flex-direction: column; align-items: flex-end; `; // 创建设置图标 const settingsIcon = document.createElement('div'); settingsIcon.innerHTML = ''; settingsIcon.style.cssText = ` cursor: pointer; padding: 8px; border-radius: 6px; background: white; border: 1px solid #d0d7de; box-shadow: 0 1px 3px rgba(0,0,0,0.12); transition: all 0.2s ease; &:hover { background: #f6f8fa; border-color: #afb8c1; } `; container.appendChild(settingsIcon); // 创建筛选菜单容器 const menuContainer = document.createElement('div'); menuContainer.style.cssText = ` display: none; background: white; padding: 10px; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.12); border: 1px solid #e1e4e8; margin-top: 8px; `; const title = document.createElement('div'); title.textContent = '平台筛选'; title.style.cssText = ` margin-bottom: 8px; font-weight: 600; font-size: 12px; color: #24292e; `; menuContainer.appendChild(title); // 根据 User Agent 自动识别平台 function detectPlatform() { const ua = navigator.userAgent.toLowerCase(); if (ua.includes('win')) return 'Windows'; if (ua.includes('mac')) return 'macOS'; if (ua.includes('linux')) return 'Linux'; if (ua.includes('android')) return 'Android'; return 'macOS'; // 默认返回 macOS } // 获取保存的选择,如果没有保存过则使用当前平台 const currentPlatform = detectPlatform(); const savedPlatforms = GM_getValue('selectedPlatforms', [currentPlatform]); Object.values(PLATFORMS).forEach((platform) => { const label = document.createElement('label'); label.style.display = 'block'; label.style.marginBottom = '5px'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.checked = savedPlatforms.includes(platform.name); checkbox.style.marginRight = '5px'; checkbox.addEventListener('change', () => { updateFilter(); savePreferences(); }); label.appendChild(checkbox); label.appendChild(document.createTextNode(platform.name)); menuContainer.appendChild(label); }); container.appendChild(menuContainer); document.body.appendChild(container); // 添加点击事件处理 settingsIcon.addEventListener('click', () => { const isVisible = menuContainer.style.display === 'block'; menuContainer.style.display = isVisible ? 'none' : 'block'; settingsIcon.style.background = isVisible ? 'white' : '#f6f8fa'; }); // 点击外部区域时关闭菜单 document.addEventListener('click', (event) => { if (!container.contains(event.target)) { menuContainer.style.display = 'none'; settingsIcon.style.background = 'white'; } }); } // 更新资源显示 function updateFilter() { const assetsList = document.querySelectorAll('.Box-row'); const selectedPlatforms = Array.from( document.querySelectorAll('input[type="checkbox"]:checked') ).map((cb) => cb.parentElement.textContent.trim()); assetsList.forEach((asset) => { const assetName = asset .querySelector('a[href*="/download/"]') ?.textContent.toLowerCase() || ''; // 如果没有选中任何平台,显示所有资源 if (selectedPlatforms.length === 0) { asset.style.removeProperty('display'); return; } // 检查是否匹配任何选中的平台 const shouldShow = selectedPlatforms.some((platform) => { const platformPatterns = PLATFORMS[platform.toUpperCase()]?.patterns || []; return platformPatterns.some((pattern) => assetName.includes(pattern.toLowerCase()) ); }); if (shouldShow) { asset.style.removeProperty('display'); } else { asset.style.setProperty('display', 'none', 'important'); } }); } // 保存用户选择 function savePreferences() { const selectedPlatforms = Array.from( document.querySelectorAll('input[type="checkbox"]:checked') ).map((cb) => cb.parentElement.textContent.trim()); GM_setValue('selectedPlatforms', selectedPlatforms); } // 处理单个markdown-body元素 function processMarkdownBody(body) { // 检查是否已经处理过 if (body.dataset.processed) return; body.dataset.processed = 'true'; // 立即设置初始样式 requestAnimationFrame(() => { body.style.cssText = ` max-height: 300px; overflow: hidden; position: relative; transition: max-height 0.3s ease-out; `; }); // 创建展开/收起按钮 const expandBtn = document.createElement('button'); expandBtn.textContent = '展开'; expandBtn.style.cssText = ` position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); background: linear-gradient(to bottom, transparent, white 40%); border: none; padding: 30px 20px 8px; cursor: pointer; color: #0969da; font-size: 12px; width: 100%; text-align: center; transition: background 0.3s ease; `; // 添加点击事件 expandBtn.addEventListener('click', () => { const isExpanded = body.style.maxHeight !== '300px'; body.style.maxHeight = isExpanded ? '300px' : 'none'; expandBtn.textContent = isExpanded ? '展开' : '收起'; expandBtn.style.background = isExpanded ? 'linear-gradient(to bottom, transparent, white 40%)' : 'none'; }); body.appendChild(expandBtn); } // 添加展开/收起功能 function addExpandFeature() { // 添加全局样式 const style = document.createElement('style'); style.textContent = ` .markdown-body:not([data-processed]) { max-height: 300px !important; overflow: hidden !important; position: relative !important; } `; document.head.appendChild(style); // 创建一个MutationObserver来监听DOM变化 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // 元素节点 const markdownBodies = node.classList?.contains('markdown-body') ? [node] : node.querySelectorAll('.markdown-body'); markdownBodies.forEach(processMarkdownBody); } }); }); }); // 监听整个文档的变化,使用更高优先级的配置 observer.observe(document.body, { childList: true, subtree: true, attributes: false, characterData: false, }); // 立即处理已存在的markdown内容 requestAnimationFrame(() => { document.querySelectorAll('.markdown-body').forEach(processMarkdownBody); }); } // 等待页面加载完成 function init() { if (document.querySelector('.Box-row')) { createFilterUI(); updateFilter(); addExpandFeature(); } else { setTimeout(init, 1000); } } init(); })();