您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Twitter の新着ツイートを niconizer へ連携します
// ==UserScript== // @name niconizer-tweetdeck // @namespace https://github.com/matzkoh // @version 1.1.0 // @description Twitter の新着ツイートを niconizer へ連携します // @author matzkoh // @include https://tweetdeck.twitter.com/ // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @noframes // ==/UserScript== GM_registerMenuCommand(`[niconizer]: Set server URL`, () => { const currentValue = GM_getValue('wsUrl', 'ws://localhost:25252/') const value = prompt('Set server URL', currentValue) if (value && value !== currentValue) { GM_setValue('wsUrl', value) location.reload() } }) const $3c4b2b695963bd2f$var$ws = new Promise(resolve => { const wsUrl = GM_getValue('wsUrl', 'ws://localhost:25252/') const ws = new WebSocket(wsUrl) ws.addEventListener('open', () => resolve(ws)) }) function $3c4b2b695963bd2f$var$escapeHtml(str) { const el = document.createElement('div') el.textContent = str return el.innerHTML } async function $3c4b2b695963bd2f$var$sendComment(comment) { ;(await $3c4b2b695963bd2f$var$ws).send($3c4b2b695963bd2f$var$escapeHtml(comment)) } document.addEventListener('click', event => { const icon = event.target.closest('.niconizer-toggle-icon') if (!icon) return const isActive = icon.classList.toggle('icon-toggle-on') icon.classList.toggle('icon-toggle-off') event.target.closest('.column')?.classList.toggle('niconizer-watching', isActive) }) new MutationObserver(mutations => { const addedElements = mutations.flatMap(m => Array.from(m.addedNodes)).filter(n => n.nodeType === Node.ELEMENT_NODE) addedElements .filter(el => el.matches('.column:not(.js-simple-column)')) .filter(el => el.querySelector('.column-header-links')) .filter(el => !el.querySelector('.niconizer-toggle-icon')) .forEach($3c4b2b695963bd2f$var$appendToggleIcon) addedElements .filter(el => el.matches('.column-header, .column-header-links')) .filter(el => !el.querySelector('.niconizer-toggle-icon')) .map(el => el.closest('.column:not(.js-simple-column)')) .filter(Boolean) .forEach($3c4b2b695963bd2f$var$appendToggleIcon) addedElements .filter(el => el.matches('.stream-item')) .filter(el => el.closest('.column.niconizer-watching')) .map($3c4b2b695963bd2f$var$getCommentBodyFromTweet) .filter(Boolean) .forEach($3c4b2b695963bd2f$var$sendComment) }).observe(document.body, { childList: true, subtree: true, }) function $3c4b2b695963bd2f$var$appendToggleIcon(column) { const buttonContainer = column.querySelector('.column-header-links') const btn = document.createElement('span') btn.className = 'column-header-link' btn.innerHTML = '<i class="niconizer-toggle-icon icon js-show-tip is-actionable" data-tooltip-position="bottom" title="niconizer 連携"></i>' const isActive = column.classList.contains('niconizer-watching') const icon = btn.firstElementChild icon.classList.toggle('icon-toggle-on', isActive) icon.classList.toggle('icon-toggle-off', !isActive) buttonContainer.insertBefore(btn, buttonContainer.firstElementChild) } function $3c4b2b695963bd2f$var$getCommentBodyFromTweet(el) { const isRetweet = el.querySelector('.tweet-context') if (isRetweet) return null const textEl = el.querySelector('.tweet-text') if (!textEl) return null let text = textEl.textContent el.closest('.column') ?.querySelector('.column-title-edit-box') ?.value.match(/#[^\s()]+/g) ?.forEach(hashTag => { text = text.split(hashTag).join('') }) return text.trim().replace(/\s+/g, ' ') }