From 09cb648e5bcd248c7ad47fbafb4c6e3cf891badd Mon Sep 17 00:00:00 2001 From: Daniel Bulant Date: Sun, 12 Sep 2021 21:13:44 +0200 Subject: [PATCH] first commit --- .gitignore | 2 ++ index.ts | 28 ++++++++++++++++++ joystick.ts | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 ++++ spotify.ts | 21 +++++++++++++ tsconfig.json | 8 +++++ utils.ts | 31 ++++++++++++++++++++ 7 files changed, 177 insertions(+) create mode 100644 .gitignore create mode 100644 index.ts create mode 100644 joystick.ts create mode 100644 package.json create mode 100644 spotify.ts create mode 100644 tsconfig.json create mode 100644 utils.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b2ee77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/pnpm-lock.yaml \ No newline at end of file diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..42f94f8 --- /dev/null +++ b/index.ts @@ -0,0 +1,28 @@ +import { JoyStick } from "./joystick"; + +const devices = await JoyStick.getList(); + +for(const device of devices) { + const colors = await device.getColors(); + const max = await device.getMaxColors(); + console.log(`Found device ${device.name}: + Colors: + RED ${colors.red} + GREEN ${colors.green} + BLUE ${colors.blue} + Max colors: + RED ${max.red} + GREEN ${max.green} + BLUE ${max.blue}`) + const newColors = { + red: Math.floor(Math.random() * max.red), + green: Math.floor(Math.random() * max.green), + blue: Math.floor(Math.random() * max.blue), + }; + await device.setColors(newColors); + console.log(` + Updated colors: + RED ${newColors.red} + GREEN ${newColors.green} + BLUE ${newColors.blue}`); +} \ No newline at end of file diff --git a/joystick.ts b/joystick.ts new file mode 100644 index 0000000..db11a96 --- /dev/null +++ b/joystick.ts @@ -0,0 +1,81 @@ +import { exec, readUTF, writeUTF } from "./utils"; +import * as fs from "fs"; + +interface IJoyStick { + name: string; + led: string; + dev: string; +} + +interface Colors { + red: number; + green: number; + blue: number; +} + +export class JoyStick implements IJoyStick { + name: string; + led: string; + dev: string; + + constructor(data: IJoyStick) { + this.name = data.name; + this.led = data.led; + this.dev = data.dev; + } + + async getColors() { + const [ red, green, blue ] = (await Promise.all([ + readUTF(`/sys/class/leds/${this.led}:red/brightness`), + readUTF(`/sys/class/leds/${this.led}:green/brightness`), + readUTF(`/sys/class/leds/${this.led}:blue/brightness`), + ])).map(t => parseInt(t)); + + return { red, green, blue } as Colors; + } + + async setColors(colors: Colors) { + await Promise.all([ + writeUTF(`/sys/class/leds/${this.led}:red/brightness`, colors.red.toString()), + writeUTF(`/sys/class/leds/${this.led}:green/brightness`, colors.green.toString()), + writeUTF(`/sys/class/leds/${this.led}:blue/brightness`, colors.blue.toString()), + ]); + } + + private _maxColors?: Colors; + async getMaxColors() { + if(!this._maxColors) { + const [ red, green, blue ] = (await Promise.all([ + readUTF(`/sys/class/leds/${this.led}:red/max_brightness`), + readUTF(`/sys/class/leds/${this.led}:green/max_brightness`), + readUTF(`/sys/class/leds/${this.led}:blue/max_brightness`), + ])).map(t => parseInt(t)); + this._maxColors = { red, green, blue }; + } + + return this._maxColors; + } + + private static async getDevice(name: string) { + const out = await exec(["udevadm", "info", "-n", name]); + const data: Record = {}; + for(const line of out.split("\n")) { + if(line[0] !== "E") continue; + const [, key, val] = line.match(/^E: ([A-Z_]+)=(.*)$/)!; + data[key] = val; + } + return new JoyStick({ + name: data.ID_SERIAL, + led: data.DEVPATH.split("/")[8], + dev: data.DEVNAME + }); + } + + static async getList() { + const devices = await Promise.all([ + ...fs.readdirSync("/dev/input") + ].filter(t => t.startsWith("js")) + .map(t => this.getDevice(`/dev/input/${t}`))); + return devices; + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..b9af5bc --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "got": "^11.8.2", + "node-vibrant": "^3.2.1-alpha.1" + } +} diff --git a/spotify.ts b/spotify.ts new file mode 100644 index 0000000..63f5ae9 --- /dev/null +++ b/spotify.ts @@ -0,0 +1,21 @@ +import { exec } from "./utils"; + +interface Track { + length: number; + artURL: string; + id: string; + url: string; + artist: string; + album: string; + albumArtist: string; +} + +class Spotify { + async getCurrentTrack() { + const data: Record = {}; + const out = await exec(["qdbus", "org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player.Metadata"]); + + } +} + +export default new Spotify(); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c159a4c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "es2020", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + } +} \ No newline at end of file diff --git a/utils.ts b/utils.ts new file mode 100644 index 0000000..6764556 --- /dev/null +++ b/utils.ts @@ -0,0 +1,31 @@ +import { promises as afs } from "fs"; +import { spawn } from "child_process"; +import got from "got"; +import Vibrant from 'node-vibrant'; + +export async function readUTF(file: string) { + return await afs.readFile(file, { encoding: "utf-8" }) as string; +} +export async function writeUTF(file: string, data: string) { + return await afs.writeFile(file, data); +} + +export function exec(cmd: string[]) { + return new Promise((resolve, reject) => { + var output = ""; + const p = spawn(cmd.shift(), cmd); + p.stdout.on("data", (chunk) => output += chunk); + p.on("exit", (code) => { + if(code) return reject(code); + resolve(output); + }); + }); +} + +export async function getColor(image: string) { + var resp = await got(image, { + responseType: "buffer" + }); + var vibrant = new Vibrant(resp.body); + var color = await vibrant.getPalette(); +} \ No newline at end of file