{"id":16557660,"url":"https://github.com/patrickkfkan/lms-cli-notifications","last_synced_at":"2026-04-20T07:02:02.769Z","repository":{"id":57701599,"uuid":"498086347","full_name":"patrickkfkan/lms-cli-notifications","owner":"patrickkfkan","description":"Node module for subscribing to and receiving notifications through Logitech Media Server's CLI.","archived":false,"fork":false,"pushed_at":"2023-07-11T17:44:32.000Z","size":62,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-15T20:05:32.961Z","etag":null,"topics":["events","logitech-media-server","notifications","squeezebox","squeezebox-server","squeezelite"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/patrickkfkan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-30T20:22:09.000Z","updated_at":"2023-11-26T21:02:07.000Z","dependencies_parsed_at":"2022-08-29T05:31:06.259Z","dependency_job_id":null,"html_url":"https://github.com/patrickkfkan/lms-cli-notifications","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickkfkan%2Flms-cli-notifications","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickkfkan%2Flms-cli-notifications/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickkfkan%2Flms-cli-notifications/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/patrickkfkan%2Flms-cli-notifications/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/patrickkfkan","download_url":"https://codeload.github.com/patrickkfkan/lms-cli-notifications/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241940529,"owners_count":20045878,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["events","logitech-media-server","notifications","squeezebox","squeezebox-server","squeezelite"],"created_at":"2024-10-11T20:08:10.392Z","updated_at":"2026-04-20T07:01:57.724Z","avatar_url":"https://github.com/patrickkfkan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lms-cli-notifications\n\nNode module for subscribing to and receiving notifications through Logitech Media Server's CLI.\n\nWhere in CLI, you subscribe to notifications as follows:\n\n```\n// Telnet to LMS\n$ telnet \u003cserver_address\u003e:\u003ccli_port\u003e\n\n// Subscribe to 'mixer' notifications\n# subscribe mixer\n\n// Also subscribe to 'play' and 'pause' notifications\n# subscribe mixer,play,pause\n\n// Unsubscribe from 'play' notifications\n# subscribe mixer,pause\n\n// Output when player volume changes:\n40%3A61%3A86%3Af0%3A8f%3A19 mixer volume 80\n\n```\n\nIn Node.JS, you would do this:\n\n```\n// ESM\nimport { NotificationListener } from 'lms-cli-notifications';\n// CJS\nconst { NotificationListener } = require('lms-cli-notifications');\n\nconst server = {\n  host: '\u003cserver_address\u003e',\n  port: '\u003ccli_port\u003e'\n};\n\nconst notificationListener = new NotificationListener({\n  server,\n  subscribe: 'mixer' // Subscribe to 'mixer' notifications\n});\n\nnotificationListener.on('notification', (data) =\u003e {\n  const {playerId, notification, params} = data;\n  console.log({playerId, notification, params});\n});\n\nawait notificationListener.start();\n\n// Also subscribe to 'play' and 'pause' notifications\nawait notificationListener.subscribe(['play', 'pause']);\n\n// Unsubscribe from 'play' notifications\nawait notificationListener.unsubscribe('play');\n\n...\n\n// Output when player volume changes:\n{\n  playerId: '40:61:86:f0:8f:19',\n  notification: 'mixer',\n  params: [ 'volume', '50' ]\n}\n\n```\n\nDo not confuse subscription in this context with the `subscribe` *tag* in *queries* (which this library does not support).\n\n## Install\n\n```\nnpm install --save lms-cli-notifications\n```\n\n## API\n\n### Class: `NotificationListener`\n\nA `NotificationListener` encapsulates the process of connecting to a Logitech Media Server's CLI, subscribing to notifications and receiving them (communicating back by way of Events). You would begin by first creating a `NotificationListener` instance.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enew NotificationListener([params])\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nCreates a `NotificationListener` instance and associates it with `server`, or `127.0.0.1:9090` if not specified.\n\n**Params**\n\n- `params`: ([`NotificationListenerParams`](docs/api/interfaces/NotificationListenerParams.md)) (*optional* and *all properties optional*)\n    - `server`:\n        - `host`: (string) address of server to connect to (default: '127.0.0.1`).\n        - `port`: (string) server's CLI port (default: '9090').\n        - `username`: (string) username for login - omit if not applicable.\n        - `password`: (string) password for login - omit if not applicable.\n    - `subscribe`: (string | Array\\\u003cstring\u003e)\n      - If string, the notification to subscribe to.\n      - If array, the list of notifications to subscribe to.\n\n\nThe `subscribe` param is included merely for convenience. You can subscribe to notifications at any stage by calling `subscribe()`. So the following:\n```\nconst server = { ... };\nconst notifications = ['client', 'mixer'];\n\nconst notificationListener = new NotificationListener({ \n  server,\n  subscribe: notifications\n});\nnotificationListener.start();\n```\n\nhas the same effect as:\n\n```\n...\nconst notificationListener = new NotificationListener({ server });\nnotificationListener.subscribe(notifications);\n\nnotificationListener.start();\n```\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.start()\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nEstablishes connection with the server and subscribes to the notification(s) specified at construction time.\n\n**Returns**\n\nPromise that resolves to `true` on success.\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.stop()\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nTerminates connection with the server.\n\n**Returns**\n\nPromise that resolves to `true` on success.\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.isConnected()\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nWhether the `NotificationListener` instance is connected to the server.\n\n**Returns**\n\nBoolean\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.subscribe(notification)\u003c/code\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nSubscribes to `notification`.\n\n\u003eIf server is not yet connected, subscription will be deferred until connection is established.\n\n**Params**\n\n- `notification` (string | Array\\\u003cstring\u003e):\n  - If string, a single notification to subscribe to.\n  - If array, the list of notifications to subscribe to.\n\n**Returns**\n\n- If server is not yet connected, a Promise that resolves after adding `notification` to the list of pending subscriptions.\n- If server is already connected, a Promise that resolves on successful subscription.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.unsubscribe(notification)\u003c/code\u003e\u003c/summary\u003e\n\nUnsubscribes from `notification`.\n\n**Params**\n\n- `notification` (string | Array\\\u003cstring\u003e):\n  - If string, a single notification to unsubscribe from.\n  - If array, the list of notifications to unsubscribe from.\n\n**Returns**\n\n- If server is not yet connected, a Promise that resolves when `notification` is removed from the list of pending subscriptions.\n- If server is already connected, a Promise that resolves on successful unsubscription.\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.getSubscribed()\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nReturns the list of currently-subscribed notifications. The list will be empty if there is no connection with the server.\n\n**Returns**\n\nArray\\\u003cstring\u003e\n\n---\n\u003c/details\u003e\n\n\n### Events\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.on('connect', (server) =\u003e ...)\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nEmitted when connection to `server` is established.\n\n**Listener Params**\n- `server`:\n  - `host`: (string)\n  - `port`: (string)\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.on('disconnect', (server) =\u003e ...)\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nEmitted when server is disconnected.\n\n**Listener Params**\n- `server`:\n  - `host`: (string)\n  - `port`: (string)\n\n---\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ccode\u003enotificationListener.on('notification', (data) =\u003e ...)\u003c/code\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\n\nEmitted when a subscribed notification is received.\n\n`NotificationListener` parses the raw message received from the server and converts it from something like this:\n```\n08%3A00%3A27%3Aa0%3Ad1%3A2c mixer volume 70\n```\ninto this:\n\n|Property                      |Value                                           |\n|------------------------------|------------------------------------------------|\n|`playerId` \\\u003cstring\\\u003e*        |'08:00:27:a0:d1:2c'                             |\n|`notification` \\\u003cstring\\\u003e     |'mixer'                                         |\n|`params` \\\u003cArray\\\u003e            |['volume', '70']                                |\n|`raw` \\\u003cstring\\\u003e              |'08%3A00%3A27%3Aa0%3Ad1%3A2c mixer volume 70'   |\n|`server` \\\u003cObject\\\u003e           |{ host: ..., port: ... }                        |\n\n\n**Listener Params**\n- `data`: ([Notification](docs/api/interfaces/Notification.md))\n  - `playerId`: (string)\n  - `notification`: (string)\n  - `params`: (Array\\\u003cstring\u003e)\n  - `raw`: (string) unprocessed notification message\n  - `server`: (object)\n    - `host`: (string)\n    - `port`: (string)\n\n\u003e Notifications that are not associated with a specific player, such as 'rescan', will not have the `playerId` param.\n\n---\n\u003c/details\u003e\n\n### Errors\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003ci\u003eBreaking change from v0.x to v1.x\u003c/i\u003e\u003c/summary\u003e\n\u003cbr /\u003e\n\nIn v0.x, error codes are defined as standalone constants.\n\nIn v1.x, they are defined in the [`NotificationListenerErrorCode`](docs/api/enums/NotificationListenerErrorCode.md) enum.\n\n\u003c/details\u003e\n\n```\nnotificationListener.start()\n  .then(() =\u003e {\n    ...\n  })\n  .catch((err) =\u003e {\n    ...\n  });\n```\nWhere an error is an instance of [`NotificationListenerError`](docs/api/classes/NotificationListenerError.md), you can obtain more information about it:\n\n```\nif (err instanceof NotificationListenerError) {\n  console.log(`\n    Error: ${ err.message },\n    Code: ${ err.code },   // Can be undefined\n    Cause: ${ err.cause }  // Underlying error (can be undefined)\n  `);\n  ...\n}\n```\n\n#### Error codes\n\n| Enum: [`NotificationListenerErrorCode`](docs/api/enums/NotificationListenerErrorCode.md)      | Description                                   |\n|-------------------------|---------------------------------------------------------------------------------------------------------------------|\n|`AuthError`              | Login attempt failed for a password-protected server.                                                               |\n|`SendCommandError`       | A command could not be sent to the server. The underlying error can be obtained from `err.cause`.                   |\n|`CommandResponseTimeout` | After sending a command to the server, a response is expected but not received within a timeout period of 5 seconds.|\n\n---\n\n## Running the Example\n```\n// ESM\nnpm run example -- -h [server address] -p [server CLI port] -u [username] -pw [password]\n\n// CJS\nnode index.cjs -h [server address] -p [server CLI port] -u [username] -pw [password]\n```\n\nOnly include options that are applicable. Generally, you do not have to specify `-p` since most\nLMS installations use the default 9090 port for CLI.\n\n## Changelog\n\n1.0.0:\n- Migrate to TypeScript and package as ESM / CJS hybrid module\n\n0.1.2:\n- Fix blank credentials causing login timeout\n\n0.1.1:\n- Fix example\n\n0.1.0:\n- Initial release\n\n## License\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatrickkfkan%2Flms-cli-notifications","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpatrickkfkan%2Flms-cli-notifications","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpatrickkfkan%2Flms-cli-notifications/lists"}