153 lines
4.1 KiB
JavaScript
Executable File
153 lines
4.1 KiB
JavaScript
Executable File
#!/bin/env node
|
|
const debug = require("debug");
|
|
const { spawnSync } = require("child_process");
|
|
const yargs = require("yargs");
|
|
const suncalc = require("suncalc");
|
|
const dbus = require("./dbus");
|
|
const pulse = require("./pulse");
|
|
const mpd = require("./mpd");
|
|
const { colors, brightness } = require("./colors");
|
|
|
|
const o = yargs.options({
|
|
a: {
|
|
alias: "audio",
|
|
default: "analog-surround-51",
|
|
describe: "String used to match the pulse audio device",
|
|
type: "string",
|
|
},
|
|
m: {
|
|
alias: ["mic", "record"],
|
|
default: "C-Media_Electronics_Inc._USB_PnP_Sound_Device",
|
|
describe: "String used to match the pulse microphone device",
|
|
type: "string",
|
|
},
|
|
v: {
|
|
alias: "verbose",
|
|
default: 0,
|
|
describe: "Verbosity level, add more -v for more verbosity",
|
|
type: "count",
|
|
},
|
|
mpdport: {
|
|
alias: "p",
|
|
default: 6600,
|
|
describe: "MPD port",
|
|
type: "number",
|
|
},
|
|
mpdhost: {
|
|
alias: "h",
|
|
default: "localhost",
|
|
describe: "MPD Host",
|
|
type: "string",
|
|
},
|
|
}).argv;
|
|
const AUDIO_NAME = o.a;
|
|
const MIC_NAME = o.m;
|
|
|
|
const levels = ["*:error", "*:warn", "*:info", "*:log", "*:debug"].slice(
|
|
0,
|
|
o.v + 1,
|
|
);
|
|
|
|
debug.enable(levels.join(","));
|
|
|
|
function isNight() {
|
|
const now = new Date();
|
|
const night = suncalc.getTimes(now, 45.524128, -73.735409);
|
|
const isnight = now >= night.sunset || now <= night.sunrise;
|
|
return isnight;
|
|
}
|
|
|
|
function getBrightness() {
|
|
return isNight() ? 60 : 100;
|
|
}
|
|
const volume =
|
|
(Math.min(
|
|
parseInt(
|
|
spawnSync(
|
|
`pactl list | grep -E "Name: .*${AUDIO_NAME}$|Volume" | grep "Name:" -A1 | tail -1 | cut -d% -f1 | cut -d/ -f2 | tr -d " "`,
|
|
{ shell: true },
|
|
).stdout,
|
|
),
|
|
30,
|
|
) /
|
|
30) *
|
|
100;
|
|
async function setMutedMic() {
|
|
const muted = !spawnSync(
|
|
`pacmd dump | grep ^set-source-mute.*${MIC_NAME}.*yes`,
|
|
{ shell: true },
|
|
).status;
|
|
const b = muted ? getBrightness() : 100;
|
|
return dbus.staticMatrix(
|
|
...(muted
|
|
? brightness(colors.BASE_COLOR, b).rgb()
|
|
: brightness(colors.ALERT_COLOR, b).rgb()),
|
|
6,
|
|
22,
|
|
);
|
|
}
|
|
|
|
async function setAudio(matrix) {
|
|
const keys = [21];
|
|
const muted = !spawnSync(
|
|
`pacmd dump | grep ^set-sink-mute.*${AUDIO_NAME}.*yes`,
|
|
{ shell: true },
|
|
).status;
|
|
if (muted) {
|
|
keys.forEach(x =>
|
|
dbus.setKey(matrix, 0, x, ...colors.SAFE_COLOR.rgb()),
|
|
);
|
|
} else if (volume === 0) {
|
|
keys.forEach(x => dbus.setKey(matrix, 0, x, ...colors.BLUE.rgb()));
|
|
} else {
|
|
const volume = parseInt(
|
|
spawnSync(
|
|
`pactl list | grep -E "Name: .*${AUDIO_NAME}$|Volume" | grep "Name:" -A1 | tail -1 | cut -d% -f1 | cut -d/ -f2 | tr -d " "`,
|
|
{ shell: true },
|
|
).stdout,
|
|
);
|
|
const c = brightness(
|
|
volume < DANGEROUS_VOLUME
|
|
? colors.BASE_COLOR.rgb()
|
|
: colors.ALERT_COLOR.rgb(),
|
|
(volume / 50) * 100,
|
|
);
|
|
keys.forEach(x => dbus.setKey(matrix, 0, x, ...c.rgb()));
|
|
}
|
|
}
|
|
|
|
async function run() {
|
|
const interfaces = await dbus.connect();
|
|
|
|
const matrix = await setMutedMic();
|
|
setAudio(matrix);
|
|
setPlaying(matrix);
|
|
await interfaces.brightness.setBrightness(100);
|
|
await interfaces.chroma.setKeyRow(matrix);
|
|
dbus.disconnect();
|
|
}
|
|
|
|
async function daemon() {
|
|
const matrix = dbus.staticMatrix(...colors.BASE_COLOR.rgb(), 6, 22);
|
|
const setKey = (...args) => {
|
|
dbus.setKey(matrix, ...args);
|
|
};
|
|
const interfaces = await dbus.connect();
|
|
const draw = async () => await interfaces.chroma.setKeyRow(matrix);
|
|
|
|
const mpdDisconnect = mpd(
|
|
{ host: o.mpdhost, port: o.mpdport },
|
|
setKey,
|
|
draw,
|
|
)();
|
|
const p = pulse.connect({ out: AUDIO_NAME, mic: MIC_NAME, setKey, draw });
|
|
|
|
process.on("SIGINT", () => {
|
|
mpdDisconnect();
|
|
dbus.disconnect();
|
|
p.disconnect();
|
|
});
|
|
}
|
|
|
|
daemon();
|