|
// ==UserScript== |
|
// @name Google Meet Push-to-talk |
|
// @namespace https://gist.github.com/mohno007/d4947babdfad47b2fd4cd5e68e798cd1 |
|
// @version 0.2.3 |
|
// @description Push-to-talk for Google Meet |
|
// @author mohno007 |
|
// @match https://meet.google.com/* |
|
// @license CC0-1.0 |
|
// @grant none |
|
// @downloadURL https://gist.github.com/mohno007/d4947babdfad47b2fd4cd5e68e798cd1/raw/google_meet_push_to_talk.user.js |
|
// @updateURL https://gist.github.com/mohno007/d4947babdfad47b2fd4cd5e68e798cd1/raw/google_meet_push_to_talk.user.js |
|
// ==/UserScript== |
|
|
|
(function main() { |
|
'use strict'; |
|
|
|
const micOn = new Audio('data:audio/x-wav;base64,UklGRrIBAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YY4BAACHp7esjGVJRlyBpbeuj2lLRVl+orawk2xNRVZ6n7Wxlm9PRVR2nLSzmXNSRVJzmbKznHdURVBwlrC0nnpXRk5skq60oX1aR01pj6y0o4FdSExmi6m0pYRgSktjiKezp4dkTEthhKSyqItnTktfgaGxqo5qUEtdfZ6wqpBuU0tbepuuq5NxVUxZd5itq5V1WE1YdZWrrJd4W05XcpKoq5l7Xk9Wb4+mqpt9YVFWbYujqpyAZFNWa4ihqZ2DZ1VWaYWep56FaldXaIObpp6HbFpXZoCYpJ6KcFxYZX2Wop6Lcl9ZZXuToJ6NdWFbZHmQn52Od2RcZHeNnJyPemZeZHaLmpuQfGlgZHSIl5qQfWtiZXOGlZmQf25kZnKEkpeQgHBmZ3KCkJWPgnJoaHKAjpOPg3RranJ/i5GOhHZtbHJ+iY+NhHhvbXJ8h42MhHpxb3N8hYuKhHt0cXR7g4iJhHx1c3V7goaHg314dXZ7gYSFg355d3h7f4ODgX57eXl8f4GBgH58e3t8fn9/f359fQ=='); |
|
const micOff = new Audio('data:audio/x-wav;base64,UklGRrYBAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YZEBAACDlKWxt7auoY98aFdLRUVMWWp+kaKvtrawpJJ/bFpNRkVLVmd6jp+ttbaxppaDb15QR0VKVWR3ipuqs7axqJmGc2FSSUZJU2FzhpinsbSyqZuKd2VWTEdJUl9wg5SkrrOyqp2NemhZTkpKUV1tf5Ggq7Gwqp+PfWxdUUtLUVxrfI2dqK+vqp+RgXBhVU5NUVtpeYqZpautqaCTg3NkWFFPUltndoaVoamrqKGVhndoXFRRVFtmdIORnaWop6CViHlsYFhUVltlcoCOmaGlpZ+WinxvZFtXWF1mcX2KlZ2iop6Wi39yaF9bW19mcHuHkpqen5yVjIF2a2NfXmFnb3qFjpaanJmUjIJ4b2diYWNob3iCi5KXmJeSi4N6cmtmZWZqcHiAh46TlZSRi4R8dW9raGlscXd+hYuPkZCOiYR+d3JubG1vcnd8goeLjY2LiIN+enVycHBydHh8gYSHiYmIhYJ/e3h2dHR1d3l8f4KDhIWEg4F/fXt6eHh5ent8foCAgYGAgH9+fX18fHx9fX19fgA='); |
|
micOn.volume = 0.4; |
|
micOff.volume = 0.4; |
|
|
|
// 設定 |
|
const isPushToTalkKey = (ev) => { |
|
// TBD Store config in LocalStorage |
|
// Example: |
|
// return ev.altKey && ev.key == 'm'; |
|
return ev.key === 'Alt'; |
|
}; |
|
const delay = 100; |
|
const micOnThreshold = 100; |
|
|
|
const findOldMuteButton = () => document.querySelector('div[role="button"][data-is-muted]'); |
|
const findNewMuteButton = () => document.querySelector('button[data-is-muted]'); |
|
|
|
// 通話中かどうかの判定に使っている |
|
const talking = document.querySelectorAll('a[href^="https://accounts.google.com/AccountChooser"').length === 0; |
|
if (!talking) { |
|
setTimeout(main, 1000); |
|
return; |
|
} |
|
|
|
const muteButton = [ |
|
findOldMuteButton(), |
|
findNewMuteButton(), |
|
].find(e => e != null); |
|
|
|
if (! muteButton?.dataset) { |
|
setTimeout(main, 200); |
|
return; |
|
} |
|
|
|
const mute = () => { |
|
if (muteButton.dataset.isMuted === "false") { |
|
micOff.play(); |
|
muteButton.click(); |
|
} |
|
}; |
|
|
|
const unmute = () => { |
|
if (muteButton.dataset.isMuted === "true") { |
|
micOn.play(); |
|
muteButton.click(); |
|
} |
|
}; |
|
|
|
// 起動時にミュートにする |
|
mute(); |
|
|
|
let timeoutId; |
|
let keydownTime = +new Date(); |
|
|
|
window.addEventListener('keydown', (ev) => { |
|
if (isPushToTalkKey(ev)) { |
|
if (muteButton.dataset.isMuted === "true") keydownTime = +new Date(); |
|
if (timeoutId !== undefined) clearTimeout(timeoutId); |
|
unmute(); |
|
} |
|
}); |
|
|
|
window.addEventListener('keyup', (ev) => { |
|
if (isPushToTalkKey(ev)) { |
|
if (timeoutId !== undefined) clearTimeout(timeoutId); |
|
const currentTime = +new Date(); |
|
if ((currentTime - keydownTime) <= micOnThreshold) return; |
|
timeoutId = setTimeout(() => mute(), delay); |
|
} |
|
}); |
|
})(); |