您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Replaces GitHub's code language icons with Material Design Icons.
当前为
// ==UserScript== // @name GitHub Code Language Icons // @description Replaces GitHub's code language icons with Material Design Icons. // @icon https://github.githubassets.com/favicons/favicon-dark.svg // @version 1.1 // @author afkarxyz // @namespace https://github.com/afkarxyz/misc-scripts/ // @supportURL https://github.com/afkarxyz/misc-scripts/issues // @license MIT // @match https://github.com/* // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; const BASE_URL = 'https://raw.githubusercontent.com/afkarxyz/misc-scripts/refs/heads/main/'; const ICON_BASE_URL = `${BASE_URL}icons/`; async function fetchLanguageMappings() { const cacheKey = 'githubLanguageRemapCache'; const currentTime = Date.now(); const cachedData = JSON.parse(GM_getValue(cacheKey, '{}')); if (cachedData.timestamp && (currentTime - cachedData.timestamp < 7 * 24 * 60 * 60 * 1000)) { return cachedData.mappings; } try { const response = await fetch(`${BASE_URL}remap.json`); const data = await response.json(); GM_setValue(cacheKey, JSON.stringify({ mappings: data.iconRemap, timestamp: currentTime })); return data.iconRemap; } catch (error) { console.error('Failed to fetch language mappings:', error); return cachedData.mappings || {}; } } let languageMappings = {}; function normalizeLanguageName(language) { const normalizedLanguage = language.toLowerCase(); for (const [iconName, languageList] of Object.entries(languageMappings)) { if (languageList.includes(normalizedLanguage)) { return iconName; } } return normalizedLanguage; } async function fetchAvailableIcons() { const cacheKey = 'githubLanguageIconsCache'; const currentTime = Date.now(); const cachedData = JSON.parse(GM_getValue(cacheKey, '{}')); if (cachedData.timestamp && (currentTime - cachedData.timestamp < 7 * 24 * 60 * 60 * 1000)) { return cachedData.fileTypes; } try { const response = await fetch(`${BASE_URL}icons.json`); const data = await response.json(); GM_setValue(cacheKey, JSON.stringify({ fileTypes: data.fileTypes, timestamp: currentTime })); return data.fileTypes; } catch (error) { console.error('Failed to fetch icon list:', error); return cachedData.fileTypes || []; } } async function replaceLanguageIcons() { let availableIcons; try { availableIcons = await fetchAvailableIcons(); } catch (error) { console.error('Error getting available icons:', error); return; } const processedElements = new Set(); function processElement(element) { if (processedElements.has(element)) return; processedElements.add(element); let langElement, language; if (element.matches('.d-inline')) { langElement = element.querySelector('.text-bold'); if (!langElement || langElement.textContent.toLowerCase() === 'other' || element.dataset.iconChecked) return; language = normalizeLanguageName(langElement.textContent); element.dataset.iconChecked = 'true'; const svg = element.querySelector('svg'); if (!svg || !availableIcons.includes(language)) return; const img = document.createElement('img'); img.src = `${ICON_BASE_URL}${language}.svg`; img.width = 16; img.height = 16; img.className = 'mr-2'; img.style.verticalAlign = 'middle'; svg.parentNode.replaceChild(img, svg); } else if (element.matches('.f6.color-fg-muted .repo-language-color + span[itemprop="programmingLanguage"]')) { language = normalizeLanguageName(element.textContent); if (!availableIcons.includes(language)) return; const parentSpan = element.parentElement; const colorSpan = parentSpan.querySelector('.repo-language-color'); const img = document.createElement('img'); img.src = `${ICON_BASE_URL}${language}.svg`; img.width = 16; img.height = 16; img.style.marginRight = '2px'; img.style.verticalAlign = 'sub'; if (colorSpan) { colorSpan.parentNode.insertBefore(img, colorSpan); colorSpan.remove(); } } else if (element.matches('.mb-3 .no-wrap span[itemprop="programmingLanguage"]')) { language = normalizeLanguageName(element.textContent); if (!availableIcons.includes(language)) return; const parentSpan = element.parentElement; const colorSpan = parentSpan.querySelector('.repo-language-color'); const img = document.createElement('img'); img.src = `${ICON_BASE_URL}${language}.svg`; img.width = 16; img.height = 16; img.style.marginRight = '4px'; const flexContainer = document.createElement('span'); flexContainer.style.display = 'inline-flex'; flexContainer.style.alignItems = 'center'; if (colorSpan) { colorSpan.remove(); flexContainer.appendChild(img); flexContainer.appendChild(element.cloneNode(true)); parentSpan.replaceWith(flexContainer); } } else if (element.matches('.Box-sc-g0xbh4-0.fCvgBf')) { const preLanguageElement = element.querySelector('.Box-sc-g0xbh4-0:not(.fVplbS)'); if (preLanguageElement) { preLanguageElement.style.display = 'none'; } const languageSpan = element.querySelector('.Box-sc-g0xbh4-0.fVplbS'); if (languageSpan && !languageSpan.dataset.iconProcessed) { language = normalizeLanguageName(languageSpan.textContent.trim()); if (availableIcons.includes(language)) { const iconImg = document.createElement('img'); iconImg.src = `${ICON_BASE_URL}${language}.svg`; iconImg.alt = `${language} icon`; iconImg.width = 16; iconImg.height = 16; iconImg.style.marginRight = '2px'; iconImg.style.verticalAlign = 'middle'; languageSpan.insertAdjacentElement('beforebegin', iconImg); languageSpan.dataset.iconProcessed = 'true'; } } } else if (element.matches('.repo-language-color')) { const languageSpan = element.parentElement.querySelector('[itemprop="programmingLanguage"]'); if (languageSpan && !languageSpan.dataset.iconProcessed) { language = normalizeLanguageName(languageSpan.textContent); if (availableIcons.includes(language)) { const iconImg = document.createElement('img'); iconImg.src = `${ICON_BASE_URL}${language}.svg`; iconImg.alt = `${language} icon`; iconImg.width = 16; iconImg.height = 16; iconImg.style.marginRight = '2px'; iconImg.style.verticalAlign = 'sub'; element.parentElement.insertBefore(iconImg, element); element.remove(); languageSpan.dataset.iconProcessed = 'true'; } } } else if (element.matches('.Box-sc-g0xbh4-0.hjDqIa')) { const languageSpan = element.nextElementSibling; if (languageSpan && languageSpan.getAttribute('aria-label') && !languageSpan.dataset.iconProcessed) { language = normalizeLanguageName(languageSpan.getAttribute('aria-label').replace(' language', '')); if (availableIcons.includes(language)) { const iconImg = document.createElement('img'); iconImg.src = `${ICON_BASE_URL}${language}.svg`; iconImg.alt = `${language} icon`; iconImg.width = 16; iconImg.height = 16; iconImg.style.marginRight = '4px'; iconImg.style.verticalAlign = 'middle'; element.style.display = 'none'; languageSpan.parentNode.insertBefore(iconImg, languageSpan); languageSpan.dataset.iconProcessed = 'true'; } } } } const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches('.d-inline, .f6.color-fg-muted .repo-language-color + span[itemprop="programmingLanguage"], .mb-3 .no-wrap span[itemprop="programmingLanguage"], .Box-sc-g0xbh4-0.fCvgBf, .repo-language-color, .Box-sc-g0xbh4-0.hjDqIa')) { processElement(node); } else { node.querySelectorAll('.d-inline, .f6.color-fg-muted .repo-language-color + span[itemprop="programmingLanguage"], .mb-3 .no-wrap span[itemprop="programmingLanguage"], .Box-sc-g0xbh4-0.fCvgBf, .repo-language-color, .Box-sc-g0xbh4-0.hjDqIa').forEach(processElement); } } } } }); observer.observe(document.body, { childList: true, subtree: true }); document.querySelectorAll('.d-inline, .f6.color-fg-muted .repo-language-color + span[itemprop="programmingLanguage"], .mb-3 .no-wrap span[itemprop="programmingLanguage"], .Box-sc-g0xbh4-0.fCvgBf, .repo-language-color, .Box-sc-g0xbh4-0.hjDqIa').forEach(processElement); } function hideAndReplaceDivs() { document.querySelectorAll('span.Box-sc-g0xbh4-0.eXDtUe').forEach(spanElement => { if (!spanElement) return; const divToHide = spanElement.querySelector('div[class^="Box-sc-g0xbh4-0"]'); const titleElement = spanElement.closest('a')?.querySelector('div[title]'); const title = titleElement?.getAttribute('title'); if (divToHide && title && !divToHide.dataset.processed) { const normalizedTitle = normalizeLanguageName(title); divToHide.style.display = 'none'; divToHide.dataset.processed = 'true'; const svgElement = document.createElement('img'); svgElement.src = `${ICON_BASE_URL}${normalizedTitle}.svg`; svgElement.alt = title; svgElement.width = svgElement.height = 16; divToHide.parentNode.insertBefore(svgElement, divToHide); } }); } function observeDOMChanges() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { hideAndReplaceDivs(); } }); }); const config = { childList: true, subtree: true }; observer.observe(document.body, config); hideAndReplaceDivs(); } async function init() { languageMappings = await fetchLanguageMappings(); replaceLanguageIcons(); observeDOMChanges(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();