Greasy Fork is available in English.
筛选GitHub发布资源的平台,优化发布说明显示
当前为
// ==UserScript==
// @name GitHub发布平台筛选器
// @name:en GitHub Release Platform Filter
// @namespace http://tampermonkey.net/
// @version 0.2
// @description 筛选GitHub发布资源的平台,优化发布说明显示
// @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
// ==/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 =
'<svg class="octicon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="currentColor" d="M8 0a8.2 8.2 0 0 1 .701.031C9.444.095 9.99.645 10.16 1.29l.288 1.107c.018.066.079.158.212.224.231.114.454.243.668.386.123.082.233.09.299.071l1.103-.303c.644-.176 1.392.021 1.82.63.27.385.506.792.704 1.218.315.675.111 1.422-.364 1.891l-.814.806c-.049.048-.098.147-.088.294.016.257.016.515 0 .772-.01.147.038.246.088.294l.814.806c.475.469.679 1.216.364 1.891a7.977 7.977 0 0 1-.704 1.217c-.428.61-1.176.807-1.82.63l-1.102-.302c-.067-.019-.177-.011-.3.071a5.909 5.909 0 0 1-.668.386c-.133.066-.194.158-.211.224l-.29 1.106c-.168.646-.715 1.196-1.458 1.26a8.006 8.006 0 0 1-1.402 0c-.743-.064-1.289-.614-1.458-1.26l-.289-1.106c-.018-.066-.079-.158-.212-.224a5.738 5.738 0 0 1-.668-.386c-.123-.082-.233-.09-.299-.071l-1.103.303c-.644.176-1.392-.021-1.82-.63a8.12 8.12 0 0 1-.704-1.218c-.315-.675-.111-1.422.363-1.891l.815-.806c.05-.048.098-.147.088-.294a6.214 6.214 0 0 1 0-.772c.01-.147-.038-.246-.088-.294l-.815-.806C.635 6.045.431 5.298.746 4.623a7.92 7.92 0 0 1 .704-1.217c.428-.61 1.176-.807 1.82-.63l1.102.302c.067.019.177.011.3-.071.214-.143.437-.272.668-.386.133-.066.194-.158.211-.224l.29-1.106C6.009.645 6.556.095 7.299.03 7.53.01 7.764 0 8 0Zm-.571 1.525c-.036.003-.108.036-.137.146l-.289 1.105c-.147.561-.549.967-.998 1.189-.173.086-.34.183-.5.29-.417.278-.97.423-1.529.27l-1.103-.303c-.109-.03-.175.016-.195.045-.22.312-.412.644-.573.99-.014.031-.021.11.059.19l.815.806c.411.406.562.957.53 1.456a4.709 4.709 0 0 0 0 .582c.032.499-.119 1.05-.53 1.456l-.815.806c-.081.08-.073.159-.059.19.162.346.353.677.573.989.02.03.085.076.195.046l1.102-.303c.56-.153 1.113-.008 1.53.27.161.107.328.204.501.29.447.222.85.629.997 1.189l.289 1.105c.029.109.101.143.137.146a6.6 6.6 0 0 0 1.142 0c.036-.003.108-.036.137-.146l.289-1.105c.147-.561.549-.967.998-1.189.173-.086.34-.183.5-.29.417-.278.97-.423 1.529-.27l1.103.303c.109.029.175-.016.195-.045.22-.313.411-.644.573-.99.014-.031.021-.11-.059-.19l-.815-.806c-.411-.406-.562-.957-.53-1.456a4.709 4.709 0 0 0 0-.582c-.032-.499.119-1.05.53-1.456l.815-.806c.081-.08.073-.159.059-.19a6.464 6.464 0 0 0-.573-.989c-.02-.03-.085-.076-.195-.046l-1.102.303c-.56.153-1.113.008-1.53-.27a4.44 4.44 0 0 0-.501-.29c-.447-.222-.85-.629-.997-1.189l-.289-1.105c-.029-.11-.101-.143-.137-.146a6.6 6.6 0 0 0-1.142 0ZM8 11a3 3 0 1 1 0-6 3 3 0 0 1 0 6Zm0-1.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg>';
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();
})();