您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allows users to select specific audio output device for HTML5 audio / video in a per site basis.
当前为
// ==UserScript== // @name Selective HTML5 Media Audio Output for Chrome // @namespace https://greasyfork.org/en/users/85671-jcunews // @version 1.0.1 // @license AGPLv3 // @author jcunews // @description Allows users to select specific audio output device for HTML5 audio / video in a per site basis. // @match *://*/* // @grant GM_registerMenuCommand // @grant unsafeWindow // @run-at document-start // ==/UserScript== /* Audio output selection can be accessed by clicking on the "Select audio output device for this site" menu of this script's entry on the Tampermonkey/Violentmonkey/Greasemonkey browser extension's popup menu. Alternatively, the audio selection menu can be provided as a bookmarklet and be added onto the browser's bookmark toolbar. The bookmark URL should be: javascript:shmao_ujs() Note: HTML5 audio output selection is currently supported only on Chrome browser and its clones, and when the HTML page is not accessed using "file://" URL. */ ((si, ds, sl, err, ec, pc) => { function errSet(e) { alert(`Failed to set audio output device to "${sl}".\n${e}`); } function setOutput(el, single) { if (si) { if (single) ec = null; el.setSinkId(si).catch(e => ec = e).finally(() => (single || !--pc) && ec && errSet(ec)); } } function setAll(es) { pc = (es = document.querySelectorAll('audio,video')).length; ec = null; es.forEach(e => setOutput(e)); } function devLabel(d) { return (/[0-9a-f]{64}/).test(d.deviceId) ? d.label : d.deviceId; } function refDevInfo() { if (location.protocol === "file:") return err = true; navigator.mediaDevices.getUserMedia({audio: true}).catch(() => err = true).then(() => { if (err) return; navigator.mediaDevices.enumerateDevices().catch(() => err = true).then((dis, ns, k) => { if (err || (dis.length && !dis[0].label)) return err = true; ns = {}; k = ""; ds = dis.reduce((r, di, i, s) => { if (di.kind === "audiooutput") { if (ns[di.label] && (ns[di.label] !== di.groupId)) { for (i = 2; i < 99; i++) { s = di.label + " #" + i; if (!ns[s]) { di = Object.keys(di).reduce((r, k) => { r[k] = di[k]; return r; }, {}); di.label = s; break; } } } ns[di.label] = di.groupId; if (sl && (devLabel(di) === sl)) k = di.deviceId; r.push(di); } return r; }, []); if (!ds.length) return; si = k ? k : "default"; setAll(); }); }); } if (!document.documentElement) return; ds = []; if (location.protocol !== "file:") { sl = localStorage.shmaoAudioOutput ? localStorage.shmaoAudioOutput : ""; } else sl = ""; refDevInfo(); GM_registerMenuCommand("Select audio output device for this site", unsafeWindow.shmao_ujs = (a, j, k, l, s, t) => { if (err) { if (location.protocol !== "file:") { alert("Audio output device can not be selected at this time."); } else alert('Audio output device can not be selected for HTML pages accessed using "file://" URL.'); return; } l = ds.map((d, i) => { if ((sl && (devLabel(d) === sl)) || (!sl && (d.deviceId === "default"))) j = i + 1; if (d.deviceId === "default") k = i + 1; return `[${i + 1}] ${d.label}`; }).join("\n") + "\n[0] <<Clear user selection (use the default device)>>"; if (isNaN(j)) { s = `User selected audio output device is no longer installed:\n ${sl}\n\n`; t = `[${k}] ${ds[k - 1].label}`; } else { s = ""; t = `[${j}] ${ds[j - 1].label}`; } a = prompt(`${s}Currently selected audio output device:\n ${t}\n\nPlease enter a device number to use:\n\n${l}`); if ((a === null) || !(a = a.replace(/^\s+|\s+$/g, "")) || isNaN(a = parseInt(a)) || (a < 0) || (a > ds.length)) return; if (a) { sl = devLabel(ds[a - 1]); if (location.protocol !== "file:") localStorage.shmaoAudioOutput = sl; si = ds[a - 1].deviceId; } else { sl = ""; si = "default"; if (location.protocol !== "file:") delete localStorage.shmaoAudioOutput; } setAll(); }); if (err) return; navigator.mediaDevices.addEventListener("devicechange", refDevInfo); (new MutationObserver( recs => recs.forEach( rec => rec.addedNodes.forEach(node => { if (["AUDIO", "VIDEO"].indexOf(node.tagName) >= 0) { setOutput(node, true); node.addEventListener("play", function() { setOutput(this, true); }); } }) ) )).observe(document.documentElement, {childList: true, subtree: true}); })();