mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Add simple listing of sonos devices and basic Dockefile for running it
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.nyc_output
|
||||
.vscode
|
||||
build
|
||||
node_modules
|
||||
.nyc_output
|
||||
28
Dockerfile
Normal file
28
Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
||||
FROM node:14.15-alpine as build
|
||||
|
||||
WORKDIR /bonob
|
||||
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
COPY tsconfig.json .
|
||||
COPY src .
|
||||
|
||||
RUN yarn install && \
|
||||
yarn build
|
||||
|
||||
|
||||
|
||||
FROM node:14.15-alpine
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
WORKDIR /bonob
|
||||
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
COPY --from=build /bonob/build/* ./
|
||||
COPY web web
|
||||
|
||||
RUN yarn install --prod
|
||||
|
||||
CMD ["node", "./app.js"]
|
||||
@@ -1,2 +0,0 @@
|
||||
"use strict";
|
||||
console.log("Hello World!!!");
|
||||
16
package.json
16
package.json
@@ -6,24 +6,30 @@
|
||||
"author": "simojenki <simojenki@users.noreply.github.com>",
|
||||
"license": "GPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@svrooij/sonos": "^2.3.0",
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/node": "^14.14.22",
|
||||
"axios": "^0.21.1",
|
||||
"eta": "^1.12.1",
|
||||
"express": "^4.17.1",
|
||||
"typescript": "^4.1.3"
|
||||
"ts-md5": "^1.2.7",
|
||||
"typescript": "^4.1.3",
|
||||
"winston": "^3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.14",
|
||||
"@types/mocha": "^8.2.0",
|
||||
"chai": "^4.2.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"mocha": "^8.2.1",
|
||||
"nodemon": "^2.0.7",
|
||||
"nyc": "^15.1.0",
|
||||
"ts-mockito": "^2.6.1"
|
||||
"ts-mockito": "^2.6.1",
|
||||
"ts-node": "^9.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node ./bin/app.js",
|
||||
"dev": "ts-node ./src/app.ts",
|
||||
"start": "node ./build/app.js",
|
||||
"dev": "nodemon ./src/app.ts",
|
||||
"test": "nyc ./node_modules/.bin/_mocha 'tests/**/*.test.ts'",
|
||||
"testw": "mocha --require ts-node/register --watch --watch-files tests/**/* tests/**/*.test.ts"
|
||||
}
|
||||
|
||||
35
src/app.ts
35
src/app.ts
@@ -1,11 +1,26 @@
|
||||
import {createServer} from './utils/server'
|
||||
import express from "express";
|
||||
import * as Eta from "eta";
|
||||
|
||||
createServer()
|
||||
.then(server => {
|
||||
server.listen(3000, () => {
|
||||
console.info(`Listening on http://localhost:3000`)
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(`Error: ${err}`)
|
||||
})
|
||||
// import { Navidrome } from "./music_service";
|
||||
import makeSonos from "./sonos";
|
||||
|
||||
const PORT = 3000;
|
||||
|
||||
makeSonos().then((sonos) => {
|
||||
const app = express();
|
||||
app.use(express.static("./web/public"));
|
||||
|
||||
app.engine("eta", Eta.renderFile);
|
||||
app.set("view engine", "eta");
|
||||
app.set("views", "./web/views");
|
||||
|
||||
app.get("/", (_, res) => {
|
||||
res.render("index", {
|
||||
devices: sonos.devices(),
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.info(`Listening on ${PORT}`);
|
||||
});
|
||||
});
|
||||
|
||||
24
src/logger.ts
Normal file
24
src/logger.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { createLogger, format, transports } from 'winston';
|
||||
|
||||
export function debugIt<T>(thing: T): T {
|
||||
logger.debug(thing);
|
||||
return thing;
|
||||
}
|
||||
|
||||
const logger = createLogger({
|
||||
level: 'debug',
|
||||
format: format.combine(
|
||||
format.timestamp({
|
||||
format: 'YYYY-MM-DD HH:mm:ss'
|
||||
}),
|
||||
format.errors({ stack: true }),
|
||||
format.splat(),
|
||||
format.json()
|
||||
),
|
||||
defaultMeta: { service: 'bonob' },
|
||||
transports: [
|
||||
new transports.Console()
|
||||
]
|
||||
});
|
||||
|
||||
export default logger;
|
||||
20
src/music_service.ts
Normal file
20
src/music_service.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import axios from "axios";
|
||||
import { Md5 } from "ts-md5/dist/md5";
|
||||
|
||||
const s = "foobar100";
|
||||
const navidrome = process.env["BONOB_NAVIDROME_URL"];
|
||||
const u = process.env["BONOB_USER"];
|
||||
const t = Md5.hashStr(`${process.env["BONOB_PASSWORD"]}${s}`);
|
||||
|
||||
export class Navidrome {
|
||||
ping = (): Promise<boolean> =>
|
||||
axios
|
||||
.get(
|
||||
`${navidrome}/rest/ping.view?u=${u}&t=${t}&s=${s}&v=1.16.1.0&c=myapp`
|
||||
)
|
||||
.then((_) => true)
|
||||
.catch((e) => {
|
||||
console.log(e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
48
src/sonos.ts
Normal file
48
src/sonos.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { SonosManager } from "@svrooij/sonos";
|
||||
|
||||
import logger from "./logger";
|
||||
|
||||
type Device = {
|
||||
name: string;
|
||||
group: string;
|
||||
ip: string;
|
||||
port: number;
|
||||
};
|
||||
|
||||
interface Sonos
|
||||
{
|
||||
devices: () => Device[];
|
||||
}
|
||||
|
||||
class RealSonos implements Sonos {
|
||||
manager: SonosManager;
|
||||
|
||||
constructor(manager: SonosManager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
devices = (): Device[] => {
|
||||
const devices = this.manager.Devices.map((d) => ({
|
||||
name: d.Name,
|
||||
group: d.GroupName || "",
|
||||
ip: d.Host,
|
||||
port: d.Port,
|
||||
}));
|
||||
logger.debug({ devices })
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
|
||||
const SonosDisabled: Sonos = {
|
||||
devices: () => [],
|
||||
};
|
||||
|
||||
export default function (): Promise<Sonos> {
|
||||
const manager = new SonosManager();
|
||||
return manager
|
||||
.InitializeWithDiscovery(10)
|
||||
.then((it) => (it ? new RealSonos(manager) : SonosDisabled))
|
||||
.catch((_) => {
|
||||
return SonosDisabled;
|
||||
});
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import express from 'express'
|
||||
import {Express} from 'express-serve-static-core'
|
||||
|
||||
export async function createServer(): Promise<Express> {
|
||||
const server = express()
|
||||
server.get('/', (_, res) => {
|
||||
res.send('Hello world!!!')
|
||||
})
|
||||
return server
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
"lib": ["es2019"], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
@@ -14,8 +14,8 @@
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./bin", /* Redirect output structure to the directory. */
|
||||
"rootDir": ".", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
"outDir": "./build", /* Redirect output structure to the directory. */
|
||||
"rootDir": ".", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
|
||||
6
web/views/devices.eta
Normal file
6
web/views/devices.eta
Normal file
@@ -0,0 +1,6 @@
|
||||
<ul>
|
||||
<% it.devices.forEach(function(d){ %>
|
||||
<li><%= d.name %> (<%= d.ip %>:<%= d.port %>)</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
|
||||
11
web/views/index.eta
Normal file
11
web/views/index.eta
Normal file
@@ -0,0 +1,11 @@
|
||||
<% layout('./layout') %>
|
||||
|
||||
<div id="content">
|
||||
<h1>bonob</h1>
|
||||
<h2>Devices</h2>
|
||||
<ul>
|
||||
<% it.devices.forEach(function(d){ %>
|
||||
<li><%= d.name %> (<%= d.ip %>:<%= d.port %>)</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
</div>
|
||||
9
web/views/layout.eta
Normal file
9
web/views/layout.eta
Normal file
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title><%= it.title || "bonob" %></title>
|
||||
</head>
|
||||
<body>
|
||||
<%~ it.body %>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user