Volumio Play "HERE" function

A play here Volumio Pluggin / Addon which adds a play here button on your volumio web ui screen which allows you to stream directly to the web interface in the same way the paid "Play Here" function operates.

Works on Volumio Version 3

Does not add a button on the local hdmi screen. Note some adjusting of the code may be required to suit your volumio installation name on the network. However not usually required..

Aprt from that, this has been tested and used on Pi4 and Rock 3A devices and survives restarting and functions to all expectations.

You can also stream the music from your favourite media player, VLC, moode player etc by adding the Volumio URL to a network stream in VLC volumio-ip:8000 or in moode for example add a station with your volumio-IP:8000

First of all ssh into your volumio box:-

/\_ \ __
__ __ ___\//\ \ __ __ ___ ___ /\_\ ___
/\ \/\ \ / __`\\ \ \ /\ \/\ \ /' __` __`\/\ \ / __`\
\ \ \_/ |/\ \L\ \\_\ \_\ \ \_\ \/\ \/\ \/\ \ \ \/\ \L\ \
\ \___/ \ \____//\____\\ \____/\ \_\ \_\ \_\ \_\ \____/
\/__/ \/___/ \/____/ \/___/ \/_/\/_/\/_/\/_/\/___/

Free Audiophile Linux Music Player - Version 3.0

© 2015-2021 Michelangelo Guarise - Volumio Team - Volumio.org

Volumio Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Welcome to Volumio for Rock 3A (6.1.29-rk35xx aarch64)

DO NOT USE SUDO for these commands unless specified here.

Create the working folder and go there:-
mkdir -p /data/plugins/miscellanea/labtools
cd /data/plugins/miscellanea/labtools

Create file

package.json

edit file and add:-


{
"name": "labtools",
"version": "2.0.0",
"description": "Lab Tools - Play Here stream button",
"main": "index.js",
"author": "Anthony",
"license": "ISC",
"volumio_info": {
"plugin_type": "miscellanea",
"boot_priority": 2
}
}


Create


config.json


edit and add :-


{}


Create


UIConfig.json

 

Edit and add:-

 

{
"page": { "label": "Lab Tools" },
"sections": [
{
"id": "labtools",
"element": "section",
"label": "Play Here",
"icon": "fa-headphones",
"content": [
{ "id": "volumiostream", "element": "button", "label": "Show stream address",
"onClick": { "type": "emit", "message": "callMethod",
"data": { "endpoint": "miscellanea/labtools", "method": "volumioStream", "data": "" } } }
]
}
]
}

 


create

 

index.js


edit and add:-

 

'use strict';

var libQ = require('/volumio/node_modules/kew');
var fs = require('fs');
var path = require('path');
var os = require('os');

var UI_DIRS = ['/volumio/http/www', '/volumio/http/www3', '/volumio/http/www4'];
var SCRIPT_NAME = 'labtools-playhere.js';
var SCRIPT_TAG = '<script src="' + SCRIPT_NAME + '"></script>';
var MPD_TMPL = '/volumio/app/plugins/music_service/mpd/mpd.conf.tmpl';
var HTTPD_BLOCK = [
'audio_output {',
'type "httpd"',
'name "HTTP Stream"',
'encoder "vorbis"',
'port "8000"',
'bitrate "320"',
'format "44100:16:2"',
'}'
].join('\n');

module.exports = LabTools;

function LabTools(context) {
this.context = context;
this.commandRouter = context.coreCommand;
this.logger = context.logger;
this.configManager = context.configManager;
}

LabTools.prototype.onVolumioStart = function () {
return libQ.resolve();
};

LabTools.prototype.onStart = function () {
this.logger.info('LabTools Started');
this.installPlayHere();
this.ensureHttpStream();
return libQ.resolve();
};

LabTools.prototype.onStop = function () {
this.removePlayHere();
return libQ.resolve();
};

LabTools.prototype.getUIConfig = function () {
var defer = libQ.defer();
try {
defer.resolve(require(__dirname + '/UIConfig.json'));
} catch (e) {
defer.reject(e);
}
return defer.promise;
};

// ---------- Play Here: inject button script into the web UI ----------

LabTools.prototype.installPlayHere = function () {
var self = this;
var src = path.join(__dirname, SCRIPT_NAME);
UI_DIRS.forEach(function (dir) {
var index = path.join(dir, 'index.html');
if (!fs.existsSync(index)) return;
try {
fs.copyFileSync(src, path.join(dir, SCRIPT_NAME));
var html = fs.readFileSync(index, 'utf8');
if (html.indexOf(SCRIPT_TAG) !== -1) {
self.logger.info('LabTools: Play Here already present in ' + index);
return;
}
if (html.indexOf('</body>') === -1) {
self.logger.error('LabTools: no </body> in ' + index + ', skipped');
return;
}
if (!fs.existsSync(index + '.labtools.bak')) {
fs.copyFileSync(index, index + '.labtools.bak');
}
fs.writeFileSync(index, html.replace('</body>', SCRIPT_TAG + '</body>'));
self.logger.info('LabTools: Play Here added to ' + index);
} catch (e) {
self.logger.error('LabTools: cannot update ' + index + ': ' + e);
}
});
};

LabTools.prototype.removePlayHere = function () {
var self = this;
UI_DIRS.forEach(function (dir) {
var index = path.join(dir, 'index.html');
if (!fs.existsSync(index)) return;
try {
var html = fs.readFileSync(index, 'utf8');
if (html.indexOf(SCRIPT_TAG) !== -1) {
fs.writeFileSync(index, html.split(SCRIPT_TAG).join(''));
self.logger.info('LabTools: Play Here removed from ' + index);
}
var js = path.join(dir, SCRIPT_NAME);
if (fs.existsSync(js)) fs.unlinkSync(js);
} catch (e) {
self.logger.error('LabTools: cannot clean ' + index + ': ' + e);
}
});
};

// ---------- Keep the MPD HTTP stream block alive after updates ----------

LabTools.prototype.ensureHttpStream = function () {
var self = this;
try {
var tmpl = fs.readFileSync(MPD_TMPL, 'utf8');
if (/type\s+"httpd"/.test(tmpl)) {
self.logger.info('LabTools: HTTP stream block present in mpd template');
return;
}
var m = tmpl.match(/audio_output\s*\{\s*type\s+"fifo"/);
if (!m) {
self.logger.error('LabTools: HTTP block missing and no fifo block to anchor on; not touching template');
return;
}
fs.copyFileSync(MPD_TMPL, MPD_TMPL + '.labtools.bak');
fs.writeFileSync(MPD_TMPL, tmpl.slice(0, m.index) + HTTPD_BLOCK + '\n\n' + tmpl.slice(m.index));
self.logger.info('LabTools: HTTP stream block RESTORED - restart Volumio once to activate');
self.commandRouter.pushToastMessage('warning', 'Lab Tools',
'HTTP stream was missing (update?) and has been restored. Restart Volumio once.');
} catch (e) {
self.logger.error('LabTools: cannot check mpd template: ' + e);
}
};

// ---------- Settings page button: this box's own stream address ----------

LabTools.prototype.volumioStream = function () {
var host = os.hostname();
var ip = '';
var nets = os.networkInterfaces();
Object.keys(nets).forEach(function (name) {
nets[name].forEach(function (a) {
if (!ip && a.family === 'IPv4' && !a.internal) ip = a.address;
});
});
this.commandRouter.pushToastMessage('success', 'Volumio Stream',
'Listen at http://' + host + '.local:8000' + (ip ? ' or http://' + ip + ':8000' : ''));
return libQ.resolve();
};

 

create

 

labtools-playhere.js

 

edit and add:-

 

(function () {
'use strict';
var STREAM = location.protocol + '//' + location.hostname + ':8000/';
var audio = null, active = false, retryTimer = null;

var btn = document.createElement('button');
btn.id = 'labtools-playhere';
btn.style.cssText = 'position:fixed;left:125px;bottom:148px;z-index:99999;' +
'padding:8px 14px;border-radius:20px;border:1px solid rgba(255,255,255,.35);' +
'background:rgba(0,0,0,.65);color:#fff;font:14px sans-serif;cursor:pointer;';

function setState(text, on) {
btn.textContent = text;
btn.style.background = on ? '#2e7d32' : 'rgba(0,0,0,.65)';
}

function teardown() {
if (!audio) return;
var a = audio;
audio = null;
a.pause();
a.removeAttribute('src');
a.load();
}

function onTrouble(e) {
if (e.target !== audio || !active) return;
teardown();
setState('\u2026 Waiting for stream', true);
clearTimeout(retryTimer);
retryTimer = setTimeout(function () { if (active) start(); }, 3000);
}

function start() {
active = true;
audio = new Audio(STREAM);
audio.addEventListener('playing', function (e) {
if (e.target === audio) setState('\u25A0 Stop here', true);
});
audio.addEventListener('error', onTrouble);
audio.addEventListener('ended', onTrouble);
setState('\u2026 Connecting', true);
var p = audio.play();
if (p && p.catch) p.catch(function () { onTrouble({ target: audio }); });
}

function stop() {
active = false;
clearTimeout(retryTimer);
teardown();
setState('\u266A Play here', false);
}

btn.onclick = function () { if (active) { stop(); } else { start(); } };
setState('\u266A Play here', false);

if (document.body) { document.body.appendChild(btn); }
else { document.addEventListener('DOMContentLoaded', function () { document.body.appendChild(btn); }); }
})();

 

 


Test everything :-

cd /data/plugins/miscellanea/labtools
for f in package.json config.json UIConfig.json; do node -e "require('./$f')" && echo "$f OK"; done
node -c index.js && echo "index.js OK"
node -c labtools-playhere.js && echo "labtools-playhere.js OK"
grep -c installPlayHere index.js


All five must say OK and the last line must print 2


Replies shoud look like :-
nano labtools-playhere.js
volumio@volumio:/data/plugins/miscellanea/labtools$ volumio@volumio:/data/plugins/miscellanea/labtools$ cd /data/plugins/miscellanea/labtools
volumio@volumio:/data/plugins/miscellanea/labtools$ for f in package.json config.json UIConfig.json; do node -e "require('./$f')" && echo "$f OK"; done
K"
node -c labtools-playhere.js && echo "labtools-playhere.js OK"
grep -c installPlayHere index.jspackage.json OK
config.json OK
UIConfig.json OK
volumio@volumio:/data/plugins/miscellanea/labtools$ node -c index.js && echo "index.js OK"
index.js OK
volumio@volumio:/data/plugins/miscellanea/labtools$ node -c labtools-playhere.js && echo "labtools-playhere.js OK"
labtools-playhere.js OK
volumio@volumio:/data/plugins/miscellanea/labtools$ grep -c installPlayHere index.js
2

 

If all is well, restart volumio and wait 30 seconds


sudo systemctl restart volumio

 

after 30 seconds or more , You can run this in the ssh session:-

journalctl -u volumio --since "3 min ago" | grep -i labtools

volumio@volumio:/data/plugins/miscellanea/labtools$ journalctl -u volumio --since "3 min ago" | grep -i labtools
Oct 20 03:32:53 volumio volumio[7809]: info: Plugin labtools is not enabled
Oct 20 03:33:29 volumio volumio[7809]: info: Enabling plugin labtools
Oct 20 03:33:29 volumio volumio[7809]: info: Loading plugin "labtools"...
Oct 20 03:33:29 volumio volumio[7809]: info: PLUGIN START: labtools
Oct 20 03:33:29 volumio volumio[7809]: info: LabTools Started
Oct 20 03:33:29 volumio volumio[7809]: info: LabTools: Play Here added to /volumio/http/www/index.html
Oct 20 03:33:29 volumio volumio[7809]: info: LabTools: Play Here added to /volumio/http/www3/index.html
Oct 20 03:33:29 volumio volumio[7809]: info: LabTools: Play Here added to /volumio/http/www4/index.html
Oct 20 03:33:29 volumio volumio[7809]: info: LabTools: HTTP stream block present in mpd template
Oct 20 03:33:33 volumio volumio[7809]: info: CALLMETHOD: miscellanea labtools volumioStream
Oct 20 03:33:33 volumio volumio[7809]: info: CoreCommandRouter::executeOnPlugin: labtools , volumioStream

 


look at your volumio devices hdmi screen if you have one, look at volumios web ui..

Volumio most likely will not enable the plugin itself on first installation.

So navigate to the Volumio menu and go to pluggins / click on installed pluggins and look for LabTools.

Enable it..

A play here button should be now visible on the web ui... Note there is not a button on the local HDMI display of volumio.


The music does not stop on the local Volumio machine when play back is used in the Play Here area on the web ui. Bt if you dont want to play locally on the main device, reduce the sound on the web ui to 0..

The volume on you web ui , iphone, ipad is controlled by the devices volume not the web ui.

 

Backup the sytem and youre done:-

cp -R /data/plugins/miscellanea/labtools ~/labtools-manual-backup

 

 

 The self instal one script sh installer can be downloaded with all files from WorldWideWebDev/playhere-stream: # Play Here Stream for Volumio   it will do the job in around 30 seconds for you/   Enjoy

  • Volumio, Volumio Play Here, Volumio Music Player, Volumio Play here Raspberry PI, Volumio Play here Rock 3a
  • 0 Utilisateurs l'ont trouvée utile
Cette réponse était-elle pertinente?

Related Articles

Volumio for Rock 3A

Volumio Music Player for the Rock 3A Rockchip RK3568 Quad-core 64 bit Cortex-A55 processor,...

Volumio Music Stream Function Rock 3A

The Volumio "Play Here" function which allows music to be played directly to your controlling pc...

Volumio Music Stream Function Raspberry PI4

The Volumio "Play Here" function which allows music to be played directly to your controlling pc...

Volumio Icecast Integration Guide: Creating a Continuous Network Audio Stream

Learn how to configure Volumio's MPD Shout output and Icecast2 on a Raspberry Pi 4 to create a...

Volumio - Icecast persistent streaming Guide Workflow

Volumio Pi 4 - Persistent Icecast Streaming Guide Documenting the working configuration created...