Greasy Fork is available in English.
Queue empty, async unarmed, Layer done, and bonus tooltip alerts with persistent settings, test buttons, and a live log.
// ==UserScript==
// @name DeepCo Croaker
// @author M3P / ChatGPT
// @namespace local
// @version 2026-03-20
// @description Queue empty, async unarmed, Layer done, and bonus tooltip alerts with persistent settings, test buttons, and a live log.
// @match https://*.deepco.app/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=deepco.app
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
(function () {
"use strict";
/* ----------------- CONFIG ----------------- */
const DEBUG = false;
const SETTINGS_KEY = "CROAKER_ALERTS_V2";
const SOUND_DATA = "data:audio/mpeg;base64,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VAivJFIIEd9yIhvKLOyiMYgMBkYTmhyuNNACgwWDJgYBgEBFABLABVEpYFgAQgGlbkgCV1cnssstZZVsu28+8////////////////rRbcb//BEJszwzuzOzg7ibfb62yNtJhVUUrUWsu4WVIRw9cc9WEtQj84D5bZ+5zDoGVsZqw6URUGJ5hYQAFQGrRakIKjHyY8pLNCJZMyw7/+7DE64Ax7dkh+d4AA9UzIv8xsAAeUBSUgTe0y7XMBHCIRpXaMNCxYUasyKSM6aREaaliEOy95QaEmElhyqEJFaCKKKApGlYNHoFlEojr6yybpZa+67k3C5ibocDSjGWO0/z+hQJwr1r2L7RtWOZV0wZkr0ymtKn77hZ1+d2pEOY49yw58zRyq7D8CP/Hp+UzMo73U3S5fr+ZUdzHvb+8cvabjHeNJh6JTlFj+X575/493l/////9z1jhySczx/v29Vq3S5enhlcQAABX15gIDB0lfCciZQUA921ul2zCkM0FoZupjTsKFSY0+ULemEC5gMAmCwmYcJ5kAmgUNGGQk64OChgEVqUGADyZkzaRw4DTOjlMPgMxCEUk5eaZ2xxcyGEQgYtEBzTymYgO1xWIu2uuLuW5aKBhsdGSzEYKFIOHidQwAy7MLi611NGWUS7FMC+SeogBpggFonAUAMCXag5A0Vf2KRfPTT2QMkU7a0zphxVABgUHGEBLS40tzGPFqggCN1YO1+X35fT3zI4UNVAYHJNNJWxU0H0MBAAEkoMMIgJpL8ynL7kUwxdhrDiZRyHIceuvLYFa9KmkwVEnxssphmHaWrATOrOU7HF3QPDcBMEREcutzOpbp8tbUMVYFAYYBD4gFIWBkMuHJ3Heh7EU2TPkw6o5UTaSoK03K1rlNHca3//P///////////////56GJFV////////////////pthUVMxMzcEHv7K3lvUqGD/Ti+oWuifZZEQfD9Kr7vOO4a9N1Zps2NLALtNeZc0piRhuHawZAYGVWbDENUcnyxdp3r7vRbHcczy7buaz//7oMTXgCxuDSn5vgJKkySkP5+QBHGaTtPYqsplsrm4ams/3ylt5Sv+P8/3ea/CSdrZ7x+ZlTky2X38uc3ZxmcJi3GsOb7XlnL9/X63Q3qaV9pvpqaxudsYR/CPUdg/U8spbIowUrAhADSh1aK0VZqXiquoIL7Sy3SsY2JbZM792wsLLFLAN1LE0QhKsLLVclnJjeWejDGTpjF0V5bE7JEpjd1E9PRx7t67hWk3eBDg1mjwWpIIpsrHw22zqA41bZfj5nz923Dlh2kkXBMj+WI8HbGxseLWgwIUt3OBakPFrb3H16t7na2Na+o0uN3rNX1tH3iXVIG6MDhSWvxqlt7jxKbh+9LZpesPd96prGdatSla0pSmsv36sVndX9ebeXSOCoH0+fAkGg9BhgoY0BGOpRwzaDFU20uQ3MWJDRhky1qKiOXGMWJjJAo0lQMZMQSRBRkMvlEyOKTBYyMnjox4VTVwSqGCQyBh2Y/Ghg1LmUnQWA0YCBBiWtFpDF4RKoAEgIb7SYhIhh0AKPmjwuY4EMh0YbBapkrDCIHQHmAw0YPByURdYEgRlr2W0OyYU8YTCJhMGo1mBwGYBAZgcGF7RwJGFQozlIkcApeZJ2OvZKy9YGBDTW3MBAIwAAFIUEljMVjSaCXE9OMaZMKggwqJDAYHTqMCAJoD+RiHH/f+RmYSEYGCpf19HP/7sMTNgBV9oyP094AmHsImvzfACG5yYZEYWE5eZfj+xjn6j8lcuB4IRUbxMRdj8QO0hzXkedL5YdDWLz7utaXdD0Tsu/YjL/XWcuE2Veixi9DW08C66fctht+7D6RRaCARuIQFzGo1MTBwwAAVWrGVLGaCMUzcVlMrMBBFWZjziL1gfWXZ2bkMfn+Xuc////////////////+dlvM////////////////5LM7f5d/MzNzEAHtqN9sifIeU1Nh2pGc4zZisCSmIOstpQJl0ZYK8MUyiT/P9WpaKVMCAIC0RjAaYGsSpcX2dqNX8efTVcJ2Uy2K0u7+OXcu67vVrKGlTO9DUqrXcbmss7mVb/yyyppdayx1KpdnXlMmmY3EXFd1/Wuu7g/07x/n+hqjxxx///fN1bNNa/v7q0tL3GrS83v8sccccf3ytKYzS2caWzWpv3j++Vn+h5/YdoJ6Ov7DuOOX/vHHHHH8ccf+Zhl/Y13HHHGZjMMy6VXdVV1kwAfmVtC4H++TbTMwuosNEGjdfwxicAmBCcbZkVSBkqWCLvoFEWcR4hQWWC8Tgt4kpaUbpkieImkVioShBi7SR2Q1mLqNyLDBG4QUhiZMJl9NMumqBdfUaoyezjGCyZHARYiRFRYxkSqTxmoaJVK5iakHWaMiUn84ifaormiBoXDZqL0CnKZvums+tKvQOumYMZv63pXmobHinmBICA/XQIXAkSUHYYga7Jp6GTyesTgJ1HAQeQx/Tgye+xA3eT9JIvDvBYKSAJgggdRAGLiAUC3hEYiZGPs0LomkLk+0gdJTAg4hH2P0g99GVDxjAtDIMGEoi//uQxOIAGX2jL/2MACJiqOT+nwAF6K0H3buv9WOmNBIQKJGXDxkRcCB97WHMLjSXr8IestL8LszSvMjES+iZhMMAUBbBDoYByFxYw5Etd516BuC6S46earXXaihmDgNV6dT1sQaTHl2KvksC2YZzbm473rwWYXbSHYw0BKxjary4yJEMWYeePbPXid+L134zlEP9/mRETskXWGB6Gjf0vf1SUDnl2Hnta///+Z/Yz7ykxt5/8vywUdQWL8Q0sUBC5h4KjOmepepmpMxUNKAbdj5XIJzKXTNyX9iDYIrhz/////////////////oVeY/////////////////2iub/P63MAwAALbNUhBkNSbSJZEIEVZ3N5AShOMwNMAV6sxTUVtZrStilWC7m2wmneUqaEvExEM2RcuMABbLmlQNMU8ZyluMa5e3ZlNjdjHHHeNmhnZp2X9mI6wLGzS4b7vHHGrhj3eOOOPP///dmDWuyhOZMWSR1drsw7S445Zf/4444/+OOP81KozZvRJ/oahq7OwzFZmlpaXH/s9/99//////5//ugxPWAKNoNO/mdpANAtKZ7saAAqVSmkhqRVbNa1nVs8q2e8//3jjjhlnWlMt1llTdqymmylTtO9Go0/0qpbOL//u7/xxE9UclCyQsA7mIlS2DZDUcCCZJLJM3CC3xZ7AhKIQ9ARIAdFwk9i1TAIxZLBJDbghNCgZCQpeeL66hFJqEhakp8zOu468tDoHQA99atv++8/qMsjOGZ6cDwFQVITQhFiICmVL89dm///lor1e5EqDKwKjpMoGkwDB0jkgQ6oiJkOs5/////sCWNoc9IirZLlWhjUJZX/8VXx/8v02v/QqmITMubebmbKCF1K1NKYBtialKwJR4oh1uCmdI9QkHSS7WGhPDqeuc6JiNsNTq9LCaCkXU6lZ0kokOUM1mJWEvV7C7mVqNdK7/+ZLWj6IiIDYbrGZDH1jjq/qRZIVnFcItXIUZImIhTIyYjC10fRMQci6f6qjm1I00uWUmmzUu3+WQ4URKTRqEC7Zsnenbmv1/7QU793//SVOZFJGPkByKENb/////zK7SOzdu8zJcQ+pW718WcSkAfB/0U6R6vZnJh0nHHT0/Rwj0sJysq9CgxemBJiHhwhumk4K46mZ8+fWsfuWpqcp1croUX/5x/Xtz9EikI5roxPYOoMX//9gqQD2N18Y5M1FuxqvMolTToud/RGVEkvyqjSLM/r860ZLBQCgOi//uAxOSAFP2fN+wxL6qXsmW89adM0RQei04kKhsNSP5p3/OJK1C41FJA443/8VA5MJO7s8M8RCBeSyAc0jLVWmkteZmCRKZFAJqwqGcihQlBUjBEoKsFT8//7yElLE00LK2fysMylB8DoaAWHqrSv//FkodNfK7Wq0te1z1rTObDesWqqgtTNMNK1KrAslFVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/+2DE6YATBZUt55j+oXUjI7xkoiVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU=";
const WATCHDOG_TIMEOUT = 500; // seconds before forcing a check
const WATCHDOG_INTERVAL = 100; // how often watchdog scans
/* ---------------- DEFAULT ALERTS ---------------- */
const DEFAULT_ALERTS = {
QUEUE_EMPTY: {
enabled: true,
sound: SOUND_DATA,
soundType: "base64",
volume: 0.7,
speed: 1,
message: "Queue Empty",
initialDelay: 1000,
repeat: 10000
},
ASYNC_UNARMED: {
enabled: true,
sound: SOUND_DATA,
soundType: "base64",
volume: 0.7,
speed: 1,
message: "Async Unarmed",
repeat: 20000
},
LAYER_COMPLETE: {
enabled: true,
sound: SOUND_DATA,
soundType: "base64",
volume: 0.7,
speed: 1,
message: "Layer Completed",
repeat: 20000
},
BONUS_TOOLTIP: {
enabled: true,
sound: SOUND_DATA,
soundType: "base64",
volume: 0.7,
speed: 1,
message: "Bonus Tooltip"
}
};
const WATCHDOG = {
checkQueue: { last: Date.now(), fn: checkQueue },
checkAsync: { last: Date.now(), fn: checkAsync },
checkLayer: { last: Date.now(), fn: checkLayer },
checkBonus: { last: Date.now(), fn: checkBonus }
};
/* ---------------- UTIL ---------------- */
const clone = v => JSON.parse(JSON.stringify(v));
function gmGet(k,f){try{return GM_getValue(k,f);}catch{return f}}
function gmSet(k,v){try{GM_setValue(k,v);}catch{}}
/* ---------------- SETTINGS LOAD ---------------- */
let ALERTS = gmGet(SETTINGS_KEY,null);
if(!ALERTS){
ALERTS = clone(DEFAULT_ALERTS);
gmSet(SETTINGS_KEY,ALERTS);
}else{
for(const k in DEFAULT_ALERTS){
if(!ALERTS[k]) ALERTS[k] = clone(DEFAULT_ALERTS[k]);
for(const f in DEFAULT_ALERTS[k]){
if(!(f in ALERTS[k])) ALERTS[k][f]=DEFAULT_ALERTS[k][f];
}
}
gmSet(SETTINGS_KEY,ALERTS);
}
let saveTimer=null;
function saveAlerts(){
clearTimeout(saveTimer);
saveTimer=setTimeout(()=>{
gmSet(SETTINGS_KEY,ALERTS);
},300);
}
/* ---------------- AUDIO CACHE ---------------- */
const AUDIO_CACHE = new Map();
function getAudio(src){
if(!AUDIO_CACHE.has(src)){
const audio = new Audio(src);
audio.preload="auto";
AUDIO_CACHE.set(src,audio);
}
return AUDIO_CACHE.get(src);
}
function playSound(alert,reason){
try{
const base = getAudio(alert.sound || SOUND_DATA);
const audio = base.cloneNode();
audio.volume = alert.volume ?? 1;
audio.playbackRate = alert.speed ?? 1;
audio.play().catch(console.warn);
croaker(`[${alert.message}]`,1);
log(`PLAY ${alert.message}${reason?` (${reason})`:''}`);
}catch(e){
console.warn(e);
log("Audio error");
}
}
/* ---------------- LOG ---------------- */
const LOG=[];
function log(msg){
const line = new Date().toLocaleTimeString()+" "+msg;
if (DEBUG) console.log(line);
LOG.push(line);
if(LOG.length>200)LOG.shift();
const el=document.getElementById("croaker-log");
if(el) el.textContent = LOG.slice().reverse().join("\n");
}
/* ---------------- CROAKER HEADER ---------------- */
function croaker(message,delay){
const anchor=document.querySelector("header.navbar div.flex-1 a");
if(!anchor)return;
let span=anchor.querySelector("span.croaker");
if(!span){
span=document.createElement("span");
span.className="croaker";
span.className="valuable";
anchor.appendChild(span);
}
if(span.textContent) return;
span.textContent=message;
setTimeout(()=>{
if(span.textContent===message) span.textContent="";
},delay*1000);
}
/* ---------------- ALERT STATE ---------------- */
const ALERT_STATE={};
for(const k in ALERTS){
ALERT_STATE[k]={active:false,timer:null,repeat:null};
}
let bonusArmed=true;
/* ---------------- ALERT CONTROL ---------------- */
function startAlert(key){
const a=ALERTS[key];
const s=ALERT_STATE[key];
if(!a.enabled || s.active) return;
s.active=true;
const fire=()=>playSound(a,key);
if(a.initialDelay){
s.timer=setTimeout(()=>{
fire();
if(a.repeat) s.repeat=setInterval(fire,a.repeat);
},a.initialDelay);
}else{
fire();
if(a.repeat) s.repeat=setInterval(fire,a.repeat);
}
log("START "+key);
}
function stopAlert(key){
const s=ALERT_STATE[key];
if(s.timer)clearTimeout(s.timer);
if(s.repeat)clearInterval(s.repeat);
s.timer=null;
s.repeat=null;
s.active=false;
log("STOP "+key);
}
/* ---------------- CONDITIONS ---------------- */
function queueEmpty(){
const t=document.title.toLowerCase();
return !t.includes("queue") && !t.includes("async") ;
}
function asyncActive(){
const t=document.title.toLowerCase();
return t.includes("async");
}
function countTileWrappers() {
return document.querySelectorAll('div[id^="tile_wrapper_"]').length;
}
function countQueuedTiles() {
return document.querySelectorAll('div[id^="tile_inner_"].you-are-queued-here').length;
}
function countMiningTiles() {
return document.querySelectorAll('div[id^="tile_inner_"].you-are-mining-here').length;
}
function layerComplete() {
return document.querySelector('div#layer-complete-text') !== null
}
function checkLayer() {
if (DEBUG) console.log('------- layerComplete - ' + layerComplete());
if (layerComplete()) {
startAlert("LAYER_COMPLETE");
} else {
stopAlert("LAYER_COMPLETE");
}
}
function checkQueue(){
if (DEBUG) console.log(' ===== check queue');
//console.log('CkQ layer-' + layerComplete() + ' queueempty-' + queueEmpty() + ' async-' + asyncActive() + ' queuedtiles-' + countQueuedTiles() + ' miningtiles-' + countMiningTiles() + ' tilescnt-' + countTileWrappers());
if((queueEmpty() && countTileWrappers() > 0 && countMiningTiles() == 0) && !layerComplete() ) startAlert("QUEUE_EMPTY");
else stopAlert("QUEUE_EMPTY");
}
function checkAsync(){
if (DEBUG) console.log(' //// check async');
const el=document.querySelector('span[data-role="auto-async-indicator"]');
if(!el)return;
const t=document.title.toLowerCase();
if(el.classList.contains("hidden") && !t.includes("async"))
startAlert("ASYNC_UNARMED");
else
stopAlert("ASYNC_UNARMED");
}
function checkBonus(){
if (DEBUG) console.log(' @@@@ check bonus');
const panel=document.querySelector("turbo-frame#bonus-panel");
if(!panel)return;
const tooltip=panel.querySelector("div.tooltip:not(.bonus-active)");
if(tooltip){
if(bonusArmed){
playSound(ALERTS.BONUS_TOOLTIP,"BONUS");
bonusArmed=false;
}
}else{
bonusArmed=true;
}
}
/* ---------------- UI ---------------- */
GM_addStyle(`
#croaker-gear{position:fixed;bottom:10px;left:10px;background:#222;color:#fff;padding:6px;border-radius:6px;cursor:pointer;z-index:9999}
#croaker-panel{position:fixed;bottom:50px;left:10px;background:#111;color:#eee;padding:10px;border-radius:8px;width:320px;max-height:60vh;overflow:auto;z-index:9999}
#croaker-panel input[type=range]{width:120px}
#croaker-log{white-space:pre;font-family:monospace;font-size:11px;background:#000;padding:6px;margin-top:6px;max-height:150px;overflow:auto}
button{cursor:pointer}
`);
function buildUI(){
const gear=document.createElement("div");
gear.id="croaker-gear";
gear.textContent="⚙";
const panel=document.createElement("div");
panel.id="croaker-panel";
panel.style.display="none";
document.body.appendChild(gear);
document.body.appendChild(panel);
gear.onclick=()=>{
panel.style.display = panel.style.display==="none"?"block":"none";
};
for(const key in ALERTS){
const a=ALERTS[key];
const row=document.createElement("div");
row.innerHTML=`
<label>
<input type="checkbox" ${a.enabled?"checked":""}> <b>${key}</b>
</label>
<br>vol <input type="range" min="0" max="1" step="0.05" value="${a.volume}">
<br>spd <input type="range" min="0.5" max="2" step="0.1" value="${a.speed}">
<button class="test">Test</button>
<div>
<input class="url" placeholder="Sound URL" style="width:90%">
<input type="file" class="file" accept="audio/*">
<button class="default">Default</button>
</div>
<br>
`;
const checkbox=row.querySelector("input[type=checkbox]");
const sliders=row.querySelectorAll("input[type=range]");
const test=row.querySelector(".test");
const url=row.querySelector(".url");
const file=row.querySelector(".file");
const def=row.querySelector(".default");
checkbox.onchange=()=>{
a.enabled=checkbox.checked;
saveAlerts();
};
sliders[0].oninput=()=>{
a.volume=parseFloat(sliders[0].value);
saveAlerts();
};
sliders[1].oninput=()=>{
a.speed=parseFloat(sliders[1].value);
saveAlerts();
};
test.onclick=()=>playSound(a,"TEST");
url.onchange=()=>{
a.sound=url.value.trim();
a.soundType="url";
saveAlerts();
log(key+" URL sound");
};
file.onchange=()=>{
const reader=new FileReader();
reader.onload=e=>{
a.sound=e.target.result;
a.soundType="file";
AUDIO_CACHE.delete(a.sound);
saveAlerts();
log(key+" file sound");
};
reader.readAsDataURL(file.files[0]);
};
def.onclick=()=>{
a.sound=DEFAULT_ALERTS[key].sound;
a.soundType="base64";
saveAlerts();
log(key+" default sound");
};
panel.appendChild(row);
}
const logBox=document.createElement("div");
logBox.id="croaker-log";
panel.appendChild(logBox);
}
setInterval(()=>{
const now = Date.now();
for(const key in WATCHDOG){
const w = WATCHDOG[key];
if(now - w.last > WATCHDOG_TIMEOUT){
log("WATCHDOG fired: "+key);
w.last = now;
try{
w.fn();
}catch(e){
console.warn("watchdog error",key,e);
}
}
}
}, WATCHDOG_INTERVAL);
/* ---------------- INIT ---------------- */
buildUI();
checkQueue();
checkAsync();
checkBonus();
checkLayer();
log("Croaker ready");
})();