您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
スレッド内の書き込みにTwitch のリンクがあったら、shields.ioの配信状況バッジを挿入します。 multitwitchのリンクだった場合、チャンネルIDごとに表示します
当前为
// ==UserScript== // @name Twitch Status Badge at img // @namespace https://github.com/uzuky // @version 5.2 // @description スレッド内の書き込みにTwitch のリンクがあったら、shields.ioの配信状況バッジを挿入します。 multitwitchのリンクだった場合、チャンネルIDごとに表示します // @author uzuky // @license MIT // @match https://*.2chan.net/*/res/* // @match http://*.2chan.net/*/res/* // @match https://tsumanne.net/* // @match https://kako.futakuro.com/futa/* // @match https://*.ftbucket.info/*/cont/* // @grant none // ==/UserScript== (function() { 'use strict'; // shields.ioのバッジの見た目をカスタマイズする設定 // 詳細は https://shields.io/badges/twitch-status const shieldOptions = { style: 'flat', // スタイル (plastic, flat, flat-square, for-the-badge, social) logo: 'twitch', // 表示するロゴ (https://simpleicons.org/ にあるやつ) logoColor: 'white', // ロゴの色 //logoSize: '', // ロゴのサイズ label: '', // ラベルの文字 //labelColor: '', // ラベルの色 //color: '', // ラベルの背景色 //cacheSeconds: '', // 配信状況がキャッシュされる秒数 デフォルトの5分より短くしても意味がない }; function createShieldUrl(channelName, customOptions = {}) { const finalOptions = { ...shieldOptions, ...customOptions }; const params = new URLSearchParams(finalOptions); return `https://img.shields.io/twitch/status/${channelName}?${params.toString()}`; } function createBadgeImage(channelName, customOptions = {}) { const img = document.createElement('img'); img.src = createShieldUrl(channelName, customOptions); img.alt = `Twitch Status for ${channelName}`; img.title = `${channelName} の配信状況`; img.style.verticalAlign = 'middle'; img.style.height = '1.1em'; return img; } // 通常のTwitchリンクだったときの処理 function processSingleTwitchLink(aTag) { const twitchRegex = /^https?:\/\/(?:www\.)?twitch\.tv\/([a-zA-Z0-9_]+)\/?$/; const match = aTag.href.match(twitchRegex); if (match && match[1]) { const channelName = match[1]; const badge = createBadgeImage(channelName); badge.style.marginLeft = '4px'; aTag.appendChild(badge); aTag.dataset.twitchBadgeAdded = 'true'; } } // multitwitch だったときの処理 function processMultiTwitchLink(aTag) { const multitwitchRegex = /^https?:\/\/(?:www\.)?multitwitch\.(?:tv|live)\/(.+)$/; const match = aTag.href.match(multitwitchRegex); if (match && match[1]) { const path = match[1].replace(/\/$/, ''); if (!path) return; const channels = path.split('/').filter(p => p); const badgeContainer = document.createElement('span'); badgeContainer.style.display = 'block'; badgeContainer.style.marginTop = '4px'; channels.forEach(channelName => { const link = document.createElement('a'); link.href = `https://www.twitch.tv/${channelName}`; link.target = '_blank'; link.rel = 'noopener noreferrer'; link.style.marginRight = '4px'; // ラベルにチャンネル名を追加 const badge = createBadgeImage(channelName, { label: channelName }); link.appendChild(badge); badgeContainer.appendChild(link); }); aTag.insertAdjacentElement('afterend', badgeContainer); aTag.dataset.twitchBadgeAdded = 'true'; } } function scanAllLinksOnPage() { const links = document.querySelectorAll('a'); links.forEach(aTag => { // すでにバッジが追加されてたり、imgタグが中にはいってたり、リンクが設定されていない場合は何もしない if (aTag.dataset.twitchBadgeAdded || aTag.querySelector('img') || aTag.href === '') { return; } if (aTag.hostname.endsWith('multitwitch.tv') || aTag.hostname.endsWith('multitwitch.live')) { processMultiTwitchLink(aTag); } else if (aTag.hostname.endsWith('twitch.tv')) { processSingleTwitchLink(aTag); } }); } setTimeout(scanAllLinksOnPage, 250); // ページの動的更新に対応 const observer = new MutationObserver(() => { clearTimeout(observer.timer); observer.timer = setTimeout(scanAllLinksOnPage, 500); }); observer.observe(document.body, { childList: true, subtree: true }); })();