Beep when Qwen finishes, even if you're on another tab.
// ==UserScript==
// @name Qwen Chat: chime when generation finishes
// @name:ru Qwen Chat: звуковой сигнал по завершении генерации
// @version 1.0
// @description Beep when Qwen finishes, even if you're on another tab.
// @description:ru Издает звуковой сигнал, когда Qwen заканчивает генерацию, даже если вы находитесь на другой вкладке.
// @author a114_you
// @match https://chat.qwen.ai/*
// @grant none
// @run-at document-end
// @license MIT
// @namespace https://greasyfork.org/users/1475624
// ==/UserScript==
(() => {
let generating = false, ctx;
const unlock = () => (ctx = new (window.AudioContext || window.webkitAudioContext)());
document.documentElement.onclick = unlock;
const play = () => {
const c = ctx || unlock();
if (c.state === 'suspended') c.resume();
const g = c.createGain();
g.gain.value = 0.3;
g.connect(c.destination);
let t = c.currentTime;
[440,660,880].forEach((f,i) => {
const o = c.createOscillator();
o.frequency.value = f;
o.connect(g);
o.start(t);
o.stop(t += [0.2,0.2,0.3][i]);
});
setTimeout(g.disconnect.bind(g), 800);
};
const isGenerating = () =>
!!document.querySelector('i.icon-StopIcon') &&
!document.querySelector('i.icon-line-arrow-up');
const check = () => {
const now = isGenerating();
if (generating !== now) {
generating = now;
!now && play();
}
};
new MutationObserver(check).observe(document.body, {
childList: true,
subtree: true,
attributes: true
});
document.readyState === 'complete' ? check() : window.onload = check;
})();