Greasy Fork

Greasy Fork is available in English.

GitHub Release Platform Filter

Filter GitHub release assets by platform

当前为 2025-02-15 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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
// ==/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();
})();