npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

volumio-ext-players

v1.1.0

Published

Start, control and monitor [vlc](https://www.videolan.org/) or [mpv](https://mpv.io/) in Volumio.

Readme

volumio-ext-players

Start, control and monitor vlc or mpv in Volumio.

Background

This project, originally developed for the Volumio SoundCloud plugin, now aims to provide a versatile toolset for any plugins that may find it beneficial.

Created for Volumio SoundCloud plugin to provide support for HLS+AAC and HLS+Opus streams. Originally, I hoped I could use MusicPlayerDaemon (MPD) to handle these streams, because it's already available and decently integrated with Volumio. But:

  • HLS+AAC plays, but seeking results in silence and renders MPD unresponsive.
  • HLS+Opus won't play at all. This is due to FFmpeg rejecting non-standard HLS stream segments. This is solvable by passing extension_picky=0, allowed_extensions=ALL and allowed_segment_extensions=ALL to FFmpeg, but there is no option in MPD configuration to do this.

After a bit of testing, I found that:

  • VLC handles HLS+AAC streams fine with seeking possible; but it fails with HLS+Opus streams (same FFmpeg issue).
  • mpv can handle HLS+Opus streams after passing the relevant FFmpeg options.

To use these players in Volumio, the SoundCloud plugin needs to set itself as a "volatile" plugin. This means it is responsible for pretty much everything that happens before, during and after playback, including:

  • running, controlling and monitoring the player;
  • providing state updates to Volumio;
  • handling commands from Volumio, like "next", "previous", "pause", "repeat" and "random";
  • if appropriate, moving on to the next track when current playback ends.

I could do all this within the plugin, or come up with a separate reusable module. The latter makes more sense, hence this project.

Usage

Install vlc and mpv in install.sh of your plugin:

...

echo "Installing VLC media player..."
sudo apt update
sudo apt-get install -y vlc-bin vlc-plugin-base

echo "Installing mpv media player..."
sudo apt-get install -y mpv

...

Starting the player:

const { MPVService, VLCService } = require('volumio-ext-players');

// Common vars
const serviceName = 'mymusicservice';
const logger = {
  info: (msg) => { ... }
  warn: (msg) => { ... }
  error: (msg) => { ... } 
};
const volumioCtx = {
  commandRouter: sc.volumioCoreCommand,
  mpdPlugin: sc.getMpdPlugin(),
  statemachine: sc.getStateMachine()

  // Optional - modify state before sending it to Volumio
  stateTransformer: {
    transformStateBeforePush(state) {
      // Modify state
      const transformed = {
        ...state,
        title: 'Custom title'
      };
      // Return it
      return transformed;
    },

    modifyVolatileSeekBeforeSet(playerTime) {
      return playerTime - 10;
    }
  }

  // When player stops, should the service automatically disengage (unset volatile)?
  // Values:
  // - `always` (default)
  // - `never`
  // - `manual`: disengage when player stops as a result of stop() being called.
  unsetVolatileOnStop: 'manual'
};

// Start VLC
const vlc = new VLCService({
  serviceName,
  logger,
  volumio: volumioCtx
});

await vlc.start();

// Start mpv

const mpv = new MPVService({
  serviceName,
  logger,
  volumio: volumioCtx,
  mpvArgs: [
    // args passed to mpv
    '--demuxer=lavf',
    '--demuxer-lavf-o=extension_picky=0,allowed_extensions=ALL,allowed_segment_extensions=ALL'
  ]
});

await mpv.start();

Controlling the player:

// Play a track
// uri and streamUrl are required; rest is optional, but provide
// as much as you can, otherwise they will be obtained from the player
// status (not guaranteed to be available).
await vlc.play({
  uri: ...  // URI recognized by Volumio (the one sent to explodeUri()) 
  streamUrl: ... // The URL of the actual stream to be played
  title: ...
  artist: ...
  album: ...
  albumart: ...
  trackType: ...
  duration: ...
  samplerate: ...
  bitdepth: ...
  bitrate: ...
  channels: ...
});

// Pause and resume
await vlc.pause();
await vlc.resume();

// Seek to 30 seconds
await vlc.seek(30);

// Stop the player
// This sets the player to idle state, and releases
// the audio device.
// Not to be confused with quit(), which actually
// ends the player's system process.
await vlc.stop();

// Move to previous / next track
await vlc.previous();
await vlc.next();

// Set random - note this is not async
vlc.setRandom(true);

// Set repeat / repeat single
await vlc.setRepeat(true, true);

// Quit the player
// This will end the player's system process
vlc.quit();

Monitoring is automatic and state updates are sent to Volumio as necessary, but sometimes you might want to inspect the player status:

// Get the current player status
const status = vlc.getStatus();

// Is the player active and not idle?
if (vlc.isActive()) {
  ...
}

// Listen for status changes
vlc.on('status', (status) => {
  ...
});

// Get notified when player's system process is closed.
// This could be due to quitting the player intentionally or
// the player has simply crashed.
vlc.on('close', (code, signal) => {
  ...
});

You can also manually send a state update to Volumio:

vlc.pushState();

Note the use of await in the above examples. Since Volumio still uses kew, make sure you wrap your async calls into kew-compatible Promises.

Changelog

v1.1.0

  • play(): add start option to indicate position from which to start playback.
  • Add pushState() to allow manual dispatch of Volumio state.
  • Add unsetVolatileOnStop option to specify condition on which to unset volatile state.
  • Add stateTransformer option for modifying state before sending it to Volumio.
  • Add spawn options
  • mpv: resolve loadfile command differences across different versions.

v1.0.0

  • Initial release

License

MIT