diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a3d880e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,44 @@ +# Doc : https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs +# Must run before publish jobs (npmjs.yml & npm-github.yml) +name: Node.js CI + +on: + push: + branches: + - master + tags: + - 'v*.*.*' + pull_request: + branches: + - 'master' + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [10.x, 14.x, 16.x, 18.x, 20.x] + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + # Using npm ci installs the versions in the package-lock.json or npm-shrinkwrap.json file and prevents updates to the lock file. Using npm ci is generally faster than running npm install. + - name: Install dependencies + run: npm ci + # Will do nothing on this package (no 'build' script) + # - run: npm run build --if-present + # Test running it + - run: npm test + # Test publishing to npmjs + - run: npm publish --provenance --access public --dry-run + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # Test publishing to github + - run: npm publish --provenance --access public --dry-run + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/npm-github.yml b/.github/workflows/npm-github.yml new file mode 100644 index 0000000..d209919 --- /dev/null +++ b/.github/workflows/npm-github.yml @@ -0,0 +1,29 @@ +# Doc : https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages +name: Publish package to GitHub Packages + +on: + push: + tags: + - 'v*.*.*' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + id-token: write + steps: + - uses: actions/checkout@v3 + # Setup .npmrc file to publish to GitHub Packages + - uses: actions/setup-node@v3 + with: + node-version: '10.x' + registry-url: 'https://npm.pkg.github.com' + # Defaults to the user or organization that owns the workflow file + scope: '@nicolabs' + - run: npm ci + - run: npm test + - run: npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/npmjs.yml b/.github/workflows/npmjs.yml new file mode 100644 index 0000000..f6e73d6 --- /dev/null +++ b/.github/workflows/npmjs.yml @@ -0,0 +1,26 @@ +# Doc : https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages +name: Publish Package to npmjs + +on: + push: + tags: + - 'v*.*.*' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v3 + # Setup .npmrc file to publish to npm + - uses: actions/setup-node@v3 + with: + node-version: '10.x' + registry-url: 'https://registry.npmjs.org' + - run: npm ci + - run: npm test + - run: npm publish --provenance --access public + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 78f7499..0af9244 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # MusicCast "repair kit" 🩹 -[![Docker Hub](https://github.com/nicolabs/musiccast-repairkit/actions/workflows/dockerhub.yml/badge.svg)](https://hub.docker.com/r/nicolabs/musiccast-repairkit) [![GitHub repo](https://img.shields.io/badge/GitHub-repo-pink.svg?logo=github)](https://github.com/nicolabs/musiccast-repairkit) [![Buy us a tree](https://img.shields.io/badge/Plant%20trees-%F0%9F%8C%B3-lightgreen)](https://plant.treeware.earth/nicolabs/musiccast-repairkit) +[![Docker Hub](https://github.com/nicolabs/musiccast-repairkit/actions/workflows/dockerhub.yml/badge.svg)](https://hub.docker.com/r/nicolabs/musiccast-repairkit) [![npmjs repo](https://img.shields.io/npm/v/musiccast-repairkit)](https://npmjs.com/package/musiccast-repairkit) [![GitHub repo](https://img.shields.io/badge/GitHub-source-pink.svg?logo=github)](https://github.com/nicolabs/musiccast-repairkit) [![Buy us a tree](https://img.shields.io/badge/Plant%20trees-%F0%9F%8C%B3-lightgreen)](https://plant.treeware.earth/nicolabs/musiccast-repairkit) This software implements missing features for your [Yamaha MusicCast©](https://usa.yamaha.com/products/contents/audio_visual/musiccast/index.html) devices by using their embedded Application Programming Interface (API). You will have to run this program on an always-on machine, connected to the same WiFi / Ethernet nertwork as your MusicCast devices so that it can communicate with them. -The behavior is managed by enabling and configuring scenarios, each doing a specific task. You can even code your own scenarios. +The behavior is managed by enabling and configuring scenarios, each one doing a specific task. You can even code your own scenarios. ## Scenarios Each scenario is implemented as a script, written in JavaScript (run with [NodeJs](https://nodejs.org/)). -There is no guide on how to develop your own scenario, but you should look at the existing scripts, which are easy to understand for any JavaScript programmer. +There is no guide on how to develop your own scenario, but you may look at the existing scripts, which are easy to understand for any JavaScript programmer. Basically they work by watching events over the network (e.g. volume or source change) and calling accordingly the API of the MusicCast devices. Scenarios are already provided in the [scripts](./scripts) directory in this project, for the following use cases : @@ -23,7 +23,7 @@ Scenarios are already provided in the [scripts](./scripts) directory in this pro - [standby several devices together](scenario-standby-several-devices-together) -### Scenario : Automatic sound program depending on the source +### Scenario 1 : Automatic sound program depending on the source ![Illustration : source buttons on remote](doc/source-buttons.png) @@ -42,12 +42,12 @@ Currently the following mappings from source to sound program are hard coded. Yo spotify => music with clear_voice disabled airplay => music with clear_voice disabled -On the command line, use `-s scripts/audio-profile.js` to enable this script and use the `--audio-profile.source=` option to set the hostname or IP address of the receiver. +On the command line, use `-s scripts/audio-profile.js` to enable this script and `--audio-profile.source=` to set the hostname or IP address of the receiver. -Top-level options (e.g. `--source`) and configuration file are also valid (see instructions below). +Top-level options (e.g. `--source`) and configuration file are also valid (see [instructions below](#command-line-usage)). -### Scenario : Synchronize volume of several devices +### Scenario 2 : Synchronize volume of several devices ![Illustration : volume buttons on remote](doc/volume-buttons.png) @@ -65,10 +65,10 @@ On the command line, use `-s scripts/sync-volume.js` to enable this script and u - `--sync-volume.source=` sets the hostname or IP address of the *master* receiver - `--sync-volume.target=` lists the *slave* devices that will reflect the master's volume changes. You can separate them with a space or pass the option several times. -Top-level options (e.g. `--source`) and configuration file are also valid (see instructions below). +Top-level options (e.g. `--source`) and configuration file are also valid (see [instructions below](#command-line-usage)). -### Scenario : Standby several devices together +### Scenario 3 : Standby several devices together #### What it does @@ -79,31 +79,33 @@ This script will automatically force a given list of devices to power on or off #### How to configure -On the command line, use `-s scripts/standby-together.js` to enable this script and use the following options : +On the command line, use `-s scripts/standby-together.js` to enable this script and the following options : - `--standby-together.source=` sets the hostname or IP address of the *master* receiver - `--standby-together.target=` lists the *slave* devices that will follow the master's power status. You can separate them with a space or pass the option several times. -Top-level options (e.g. `--source`) and configuration file are also valid (see instructions below). +Top-level options (e.g. `--source`) and configuration file are also valid (see [instructions below](#command-line-usage)). + ## Command line usage -This program requires [Node.js](https://nodejs.org) to run. - -Previously to running it, you need to install dependencies by running the following command in the source directory : - - npm install +> There are many ways to run this program ; the exact shape of the command line depends on how you run it : with [npm, node](#running-with-nodejs-npm), [docker](#running-with-docker) or another way. +> For instance if you run using *npx*, replace `musiccast-repairkit ...` in the commands below with `npx musiccast-repairkit ...`. When running the program you need to specify which scenarios to run. -The scenarios are `.js` scripts which implement the use cases above. More details in the next sections. +The scenarios are `.js` scripts which implement the use cases above. Use the **`-s` command line option to specify which script(s) to load** ; for example : - node . -s ./scripts/sync-volume.js --source=192.168.1.42 --target=192.168.1.43 --target=192.168.1.44 + musiccast-repairkit -s ./scripts/sync-volume.js --source=192.168.1.42 --target=192.168.1.43 --target=192.168.1.44 -You can pass all options on the command line, or use the **`--config` option to store them in a JSON file** ; example : +You can run several scenarios at the same time : - node . -s ./scripts/sync-volume.js --config config.json + musiccast-repairkit -s ./scripts/sync-volume.js -s ./scripts/standby-together.js ... + +You can pass all options on the command line, or use the **`--config` option to read them from a JSON file** ; example : + + musiccast-repairkit -s ./scripts/sync-volume.js --config config.json Contents of config.json : @@ -121,6 +123,7 @@ Contents of config.json : You can define **generic options** at the top level and **scenario-specific options** under a prefix named after the script's name (its filename without extension). For instance with `--source 1.2.3.4 --sync-volume.source 5.6.7.8`, `1.2.3.4` will be used as the *source* parameter by default but `5.6.7.8` will be used for the *sync-volume* scenario only. +This also works for the JSON configuration file. You can pass those arguments multiple times or provide space-separated values if you need to. @@ -131,19 +134,40 @@ The following **environment variables** may be specified before running `index.j Example - PORT=44444 LOCAL_IP=192.168.1.187 node . [...] + PORT=44444 LOCAL_IP=192.168.1.187 musiccast-repairkit ... -## Docker usage +## Running with Node.js / npm -Instead of installing _Node.js_ and running this program from sources you can run it directly from a [Docker](https://www.docker.com/) image : +You can run the program natively using [Node.js](https://nodejs.org). + +You can get the package from [npmjs](https://npmjs.com/package/musiccast-repairkit) ; here is one way : + + # Installs npx for npm < 5.2.0 + npm install -g npx + # Run the program + npx musiccast-repairkit -s my-custom-scenario.js --config my-config.json + +Or you can run from the sources directly : + + # Get the sources + git clone https://github.com/nicolabs/musiccast-repairkit + cd musiccast-repairkit + # Install dependencies + npm install + # Run the program + node . -s my-custom-scenario.js --config my-config.json + + + +## Running with Docker + +Instead of running this program with _Node.js_ / _npm_ you can run it as a [Docker](https://hub.docker.com/r/nicolabs/musiccast-repairkit) container : docker run -d --network=host nicolabs/musiccast-repairkit:1.1 -s ./scripts/standby-together.js --source 192.168.1.42 --target 192.168.1.43 -See also [docker-compose.yml](docker-compose.yml) for a deployment template. - -This sample contains an example *command* that you shall override to fit your needs. +See also [docker-compose.yml](docker-compose.yml) for a deployment template. It contains a sample *command* that you shall override to fit your needs. You can edit it locally to reflect the IP addresses of your setup (or use a `.env` file or set environment variables). It should not be necessary to define a `LOCAL_IP` environment variable as IP addresses inside the container will likely don't match the one of the host. @@ -176,12 +200,12 @@ Otherwise, logging is set in the [`logging.js`](logging.js) module : feel free t There is a special `scripts/debug.js` script that does nothing but print debug informations. It is simply loaded as a scenario (you need to set log level to *debug* at least) : - node . -s ./scripts/sync-volume.js ./scripts/debug.js -l debug --source=192.168.1.42 ... + musiccast-repairkit -s ./scripts/sync-volume.js ./scripts/debug.js -l debug --source=192.168.1.42 ... Note : Node.Js natively allows to log network activity : - NODE_DEBUG="net" node index.js ... + NODE_DEBUG="net" musiccast-repairkit ... ## References diff --git a/index.js b/index.js old mode 100644 new mode 100755 index 94a8150..f974f33 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +#!/usr/bin/env node + const yargs = require('yargs'); const path = require('path'); const log = require('./logging'); diff --git a/package-lock.json b/package-lock.json index 3e575ac..d65faa3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,9 @@ "yamaha-yxc-nodejs": "3.1.2", "yargs": "^17.7.1" }, + "bin": { + "musiccast-repairkit": "index.js" + }, "engines": { "node": ">=10" } diff --git a/package.json b/package.json index 31604d2..d1772cb 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,6 @@ "main": "index.js", "author": "nicobo (https://www.nicolabs.net/people/nicobo)", "license": "MIT", - "private": true, "engines": { "node": ">=10" }, @@ -12,5 +11,9 @@ "winston": "^3.3.3", "yamaha-yxc-nodejs": "3.1.2", "yargs": "^17.7.1" - } + }, + "scripts": { + "test": "node . --version" + }, + "bin": "./index.js" }