您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
旋转的五分硬币直播间深渊排队脚本
当前为
// ==UserScript== // @name 旋转的五分硬币排队 // @namespace http://tampermonkey.net/ // @version 0.0.14 // @description 旋转的五分硬币直播间深渊排队脚本 // @author Mimiko // @license MIT // @match *://live.bilibili.com/3140454* // @icon http://i0.hdslb.com/bfs/activity-plat/static/20211202/dddbda27ce6f43bf18f5bca141752a99/fCo7evLooK.webp@128w // @grant GM.xmlHttpRequest // ==/UserScript== (() => { if (window.top !== window.self) return; const Lines = { add_exist: '{name}已经排过队了,序号是{idx}', add_success: '{name}已经排队成功,序号是{idx}', admin_none: '尚未为排队姬指定饲养员', find_none: '{name}还没有排队', find_success: '{name}已经排过队了,序号是{idx}', server_none: '排队姬尚未启动', server_ready: '排队姬已经启动', voice_disconnect: '无法连接语音服务器', voice_fail: '语音设置失败', voice_invalid: '语音名称不存在', voice_success: '语音已设置为{name}', waiting_cancel: '开车已取消', waiting_countdown: '发车倒计时十秒', waiting_fail: '未能成功发车', waiting_none: '没有人在等车', waiting_start: '开车啦,请各位乘客输入自己的序号', waiting_success: '请序号为{idx}的{name}使用手机扫码上车', }; const Monkey = GM; const cacheId = new Set(); const cacheName = new Map(); const cacheTimer = new Map(); const delay = 30e3; const interval = 30e3; const listVoice = [ 'hiumaan', 'hsiaochen', 'huihui', 'kangkang', 'xiaoxiao', 'yaoyao', 'yunyang', ]; const observer = new MutationObserver(() => { pick(); clearDanmaku(); }); const port = 9644; const setAdmin = new Set(); const setWaiting = new Set(); const speaker = new SpeechSynthesisUtterance(); let isWaiting = false; const add = async (name, id) => { if (!validate(name, id)) return; const data = await get(`http://localhost:${port}/queue/add?name=${name}`); if (!data) return; if (!data.status) speak(Lines.add_exist, { idx: data.idx, name }); else speak(Lines.add_exist, { idx: data.idx, name }); }; const addTimer = (token, delay, callback) => { removeTimer(token); cacheTimer.set(token, window.setTimeout(callback, delay)); }; const cancelWaiting = () => { if (!isWaiting) return; isWaiting = false; setWaiting.clear(); removeTimer('waiting/countdown'); removeTimer('waiting/speak'); speak(Lines.waiting_cancel); }; const clearDanmaku = () => { const $el = document.getElementById('chat-items'); if (!$el) return; $el.innerHTML = ''; }; const endWaiting = () => { if (!isWaiting) return; isWaiting = false; if (!setWaiting.size) { speak(Lines.waiting_none); return; } const idx = Math.min(...setWaiting); setWaiting.clear(); setCurrent(idx); }; const find = async (name, id) => { if (!validate(name, id)) return; const data = await get(`http://localhost:${port}/queue/find?name=${name}`); if (!data) return; if (!data.idx) speak(Lines.find_none, { name }); else speak(Lines.find_success, { idx: data.idx, name }); }; const get = (url) => new Promise(resolve => { Monkey.xmlHttpRequest({ method: 'GET', onerror: () => resolve(null), onload: (response) => resolve(url.includes('localhost') ? JSON.parse(response.responseText) : response.responseText), url, }); }); const getListAdmin = async () => { const data = await get(`http://localhost:${port}/admin/list`); if (!data) return false; if (!data.list.length) { speak(Lines.admin_none); return false; } data.list .filter(name => name.trim()) .forEach(name => setAdmin.add(name.replace(/\r/g, ''))); return true; }; const log = (message) => { console.log(message); return message; }; const main = async () => { pauseVideo(); if (!(await ping())) return; if (!(await getListAdmin())) return; observe(); clearDanmaku(); }; const observe = () => { const timer = window.setInterval(() => { const $el = document.getElementById('chat-items'); if (!$el) return; window.clearInterval(timer); observer.observe($el, { childList: true, attributes: true, characterData: true, }); }, 50); }; const pauseVideo = () => document.querySelector('video')?.pause(); const pick = () => Array.from(document.querySelectorAll('#chat-items .danmaku-item')).forEach($danmaku => { const content = $danmaku.getAttribute('data-danmaku')?.trim() || ''; const id = $danmaku.getAttribute('data-ct')?.trim() || ''; const name = $danmaku.getAttribute('data-uname')?.trim() || ''; console.log(content, id, name); if (setAdmin.has(name)) { if (content === '开车') return startWaiting(); if (content === '刹车') return cancelWaiting(); for (const keyword of ['切换语音', '语音切换']) { if (content.startsWith(keyword)) return setVoice(content.replace(keyword, '').trim() || ''); } } if (content === '排队') return add(name, id); for (const keyword of ['查询排队', '排队查询']) { if (content.startsWith(keyword)) return find(content.replace(keyword, '').trim() || name, id); } if (isWaiting) { const idx = parseInt(content); if (idx > 0 && idx.toString() === content) return setWaiting.add(idx); } return; }); const ping = async () => { const data = await get(`http://localhost:${port}/system/ping`); if (!data) { speak(Lines.server_none); return false; } speak(Lines.server_ready); return true; }; const removeTimer = (token) => { const n = cacheTimer.get(token); if (!n) return; cacheTimer.delete(token); window.clearTimeout(n); }; const setCurrent = async (idx) => { const data = await get(`http://localhost:${port}/queue/setCurrent?idx=${idx}`); if (!data) return; if (!data.idx) speak(Lines.waiting_fail); else speak(Lines.waiting_success, { idx: data.idx, name: data.name }); }; const setVoice = async (name) => { if (!name) return; if (!listVoice.includes(name)) { speak(Lines.voice_invalid); return; } const isLocal = [ 'huihui', 'kangkang', 'yaoyao', ].includes(name); if (!isLocal) { const result = await get('https://speech.platform.bing.com/'); if (!result) { speak(Lines.voice_disconnect); return; } } let n = 0; const fn = () => { const voice = speechSynthesis.getVoices().filter(it => it.name.toLowerCase().includes(name))[0]; if (!voice) { n++; if (n > 10) { speak(Lines.voice_fail); return; } addTimer('voice/set', 100, fn); return; } speaker.voice = voice; speak(Lines.voice_success, { name }); }; fn(); }; const speak = (message, data = {}) => { let msg = message; Object.keys(data).forEach(key => msg = msg.replace(`{${key}}`, data[key].toString())); log(msg); speaker.text = msg; window.speechSynthesis.speak(speaker); }; const startWaiting = () => { if (isWaiting) return; isWaiting = true; setWaiting.clear(); addTimer('waiting/countdown', delay, endWaiting); speak(Lines.waiting_start); addTimer('waiting/speak', delay - 10e3, () => speak(Lines.waiting_countdown)); }; const validate = (name, id) => { if (cacheId.has(id)) return false; cacheId.add(id); if (setAdmin.has(name)) return true; const ts = cacheName.get(name) || 0; const now = Date.now(); if (now - ts < interval) return false; cacheName.set(name, now); return true; }; addTimer('main', 1e3, main); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址