improved logging, toggleContent, UI tweaks

This commit is contained in:
Alexandre Storelli
2018-01-30 23:31:16 +01:00
parent 1527b24406
commit 85d8ad52b8
10 changed files with 334 additions and 168 deletions
+1 -2
View File
@@ -1,8 +1,7 @@
"use strict";
var { Writable, Duplex } = require("stream");
var log = require("loglevel");
log.setLevel("debug");
var log = require("./log.js")("DlFactory");
var cp = require("child_process");
var fs = require("fs");
var { getMeta } = require("webradio-metadata");
+65 -5
View File
@@ -77,6 +77,14 @@
}
}
},
"add-dom-event-listener": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.0.2.tgz",
"integrity": "sha1-j67SxBAIchzxEdodMNmVuFvkK+0=",
"requires": {
"object-assign": "4.1.1"
}
},
"address": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz",
@@ -1234,7 +1242,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": {
"core-js": "2.5.1",
"regenerator-runtime": "0.11.0"
@@ -1243,8 +1250,7 @@
"core-js": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
"integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=",
"dev": true
"integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs="
}
}
},
@@ -5629,6 +5635,11 @@
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
"dev": true
},
"lodash._getnative": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
"integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
},
"lodash._reinterpolate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
@@ -5653,6 +5664,26 @@
"integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
"dev": true
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
},
"lodash.isarray": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
},
"lodash.keys": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
"integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
"requires": {
"lodash._getnative": "3.9.1",
"lodash.isarguments": "3.1.0",
"lodash.isarray": "3.0.4"
}
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -8146,6 +8177,28 @@
}
}
},
"rc-checkbox": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.4.tgz",
"integrity": "sha512-a5rDubpIsNzx/8u7yk8rD19RyZOM3uxqwXsUUfRzNhO+wD3Y0xntqRXqNPZ/dYQqXWoK/oRJrqghst1/8pFqZQ==",
"requires": {
"babel-runtime": "6.26.0",
"classnames": "2.2.5",
"prop-types": "15.6.0",
"rc-util": "4.3.1"
}
},
"rc-util": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.3.1.tgz",
"integrity": "sha512-OVNMKLePnwn0dCX/Gpc+/kGEDpmMo1Rfesg9xFcAckRd+D+YwVqV+dUJMHugP+4nRtbXi55o0HwPlkKIApYfQA==",
"requires": {
"add-dom-event-listener": "1.0.2",
"babel-runtime": "6.26.0",
"prop-types": "15.6.0",
"shallowequal": "0.2.2"
}
},
"react": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/react/-/react-16.1.1.tgz",
@@ -8409,8 +8462,7 @@
"regenerator-runtime": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
"integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==",
"dev": true
"integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A=="
},
"regenerator-transform": {
"version": "0.10.1",
@@ -8894,6 +8946,14 @@
"safe-buffer": "5.1.1"
}
},
"shallowequal": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-0.2.2.tgz",
"integrity": "sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4=",
"requires": {
"lodash.keys": "3.1.2"
}
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+2 -1
View File
@@ -5,6 +5,7 @@
"dependencies": {
"classnames": "^2.2.5",
"moment": "^2.20.1",
"rc-checkbox": "^2.1.4",
"react": "^16.1.1",
"react-dom": "^16.1.1",
"styled-components": "^2.4.0"
@@ -18,5 +19,5 @@
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"homepage" : "https://www.adblockradio.com/buffer"
"homepage": "https://www.adblockradio.com/buffer"
}
+79 -58
View File
@@ -40,6 +40,7 @@ class App extends Component {
this.refreshConfig = this.refreshConfig.bind(this);
this.insertRadio = this.insertRadio.bind(this);
this.removeRadio = this.removeRadio.bind(this);
this.toggleContent = this.toggleContent.bind(this);
}
componentDidMount() {
@@ -169,6 +170,13 @@ class App extends Component {
});
}
toggleContent(country, name, contentType, enabled, callback) {
var self = this;
load("/config/radios/content/" + encodeURIComponent(country) + "/" + encodeURIComponent(name) + "/" + encodeURIComponent(contentType) + "/" + (enabled ? "enable" : "disable") + "?t=" + Math.round(Math.random()*1000000), function(res) {
self.refreshConfig(callback);
});
}
render() {
let config = this.state.config;
var self = this;
@@ -225,65 +233,76 @@ class App extends Component {
//console.log("Metadata props: date=" + (+self.state.date) + " clockDiff=" + self.state.clockDiff + " playingDelay=" + self.state.playingDelay);
let mainContents;
if (self.state.playlistEditMode || config.radios.length === 0) {
mainContents = (
<Playlist config={self.state.config}
insertRadio={self.insertRadio}
removeRadio={self.removeRadio}
toggleContent={self.toggleContent} />
);
} else {
mainContents = (
<RadioList>
{config.radios.map(function(radioObj, i) {
var radio = radioObj.country + "_" + radioObj.name;
var playing = self.state.playingRadio === radio;
var liveMetadata;
var metaList = self.state[radio + "|metadata"];
if (metaList) {
var targetDate = self.state.date - (playing ? self.state.playingDelay : self.defaultDelay(radio));
for (let j=0; j<metaList.length; j++) {
if (metaList[j].validFrom - 1000 <= targetDate &&
(!metaList[j].validTo || (targetDate < +metaList[j].validTo - 1000)))
{
liveMetadata = metaList[j];
break;
}
}
}
return (
<RadioItem className={classNames({ playing: playing })}
id={"RadioItem" + i}
key={"RadioItem" + i}>
<RadioItemTopLine onClick={function() { self.play(radio); }}>
<RadioLogo src={radioObj.favicon} alt="logo" />
{liveMetadata &&
<MetadataItem>
<MetadataText>
{liveMetadata.payload.artist} - {liveMetadata.payload.title}
</MetadataText>
<MetadataCover src={liveMetadata.payload.cover || defaultCover} alt="logo" />
</MetadataItem>
}
</RadioItemTopLine>
{metaList &&
<DelayCanvas playingDelay={self.state.playingDelay}
availableCache={self.state[radio + "|available"]}
classList={self.state[radio + "|class"]}
date={new Date(+self.state.date - self.state.clockDiff)}
playing={playing}
cacheLen={self.state.config.user.cacheLen}
width={self.state.canvasWidth || 100}
playCallback={function(delay) { self.play(radio, delay); }} />
}
</RadioItem>
)
})}
</RadioList>
);
}
return (
<AppParent>
<AppView>
<RadioList>
{config.radios.map(function(radioObj, i) {
var radio = radioObj.country + "_" + radioObj.name;
var playing = self.state.playingRadio === radio;
var showMetadata = !self.state.playlistEditMode;
var liveMetadata;
if (showMetadata) {
var metaList = self.state[radio + "|metadata"];
if (metaList) {
for (let j=0; j<metaList.length; j++) {
if (metaList[j].validFrom - 1000 <= (self.state.date-self.defaultDelay(radio)) &&
(!metaList[j].validTo || (self.state.date-self.defaultDelay(radio) < +metaList[j].validTo - 1000)))
{
liveMetadata = metaList[j];
break;
}
}
}
}
return (
<RadioItem className={classNames({ playing: playing })}
id={"RadioItem" + i}
key={"RadioItem" + i}>
<RadioItemTopLine onClick={function() { self.play(radio); }}>
<RadioLogo src={radioObj.favicon} alt="logo" />
{showMetadata && liveMetadata &&
<MetadataItem>
<MetadataText>
{liveMetadata.payload.artist} - {liveMetadata.payload.title}
</MetadataText>
<MetadataCover src={liveMetadata.payload.cover || defaultCover} alt="logo" />
</MetadataItem>
}
</RadioItemTopLine>
{showMetadata && self.state[radio + "|metadata"] &&
<DelayCanvas playingDelay={self.state.playingDelay}
availableCache={self.state[radio + "|available"]}
classList={self.state[radio + "|class"]}
date={new Date(+self.state.date - self.state.clockDiff)}
playing={playing}
cacheLen={self.state.config.user.cacheLen}
width={self.state.canvasWidth || 100}
playCallback={function(delay) { self.play(radio, delay); }} />
}
</RadioItem>
)
})}
</RadioList>
{(self.state.playlistEditMode || config.radios.length === 0) &&
<Playlist config={self.state.config}
insertRadio={self.insertRadio}
removeRadio={self.removeRadio} />
}
{mainContents}
</AppView>
<Controls>
{status}
@@ -312,7 +331,8 @@ const AppParent = styled.div`
const AppView = styled.div`
display: flex;
height: calc(100% - 100px);
height: calc(100% - 60px);
margin: 0 10px;
`;
const RadioList = styled.div`
@@ -355,7 +375,7 @@ const RadioLogo = styled.img`
const MetadataItem = styled.div`
flex-grow: 1;
margin: 0 0 0 15px;
padding: 10px;
padding: 0 10px;
flex-shrink: 1;
background: #eee;
display: flex;
@@ -365,6 +385,7 @@ const MetadataItem = styled.div`
const MetadataText = styled.p`
flex-grow: 1;
align-self: center;
margin: 10px 0;
`
const MetadataCover = styled.img`
+43 -11
View File
@@ -5,6 +5,8 @@ import PropTypes from "prop-types";
import styled from "styled-components";
import { load } from './load.js';
import classNames from 'classnames';
import Checkbox from 'rc-checkbox';
import 'rc-checkbox/assets/index.css';
import defaultCover from "./img/default_radio_logo.svg";
class Playlist extends Component {
@@ -41,6 +43,11 @@ class Playlist extends Component {
this.props.removeRadio(country, name, this.componentDidMount);
}
/*toggleContent(country, name, contentType, enabled) {
console.log("toggleContent radio=" + country + "_" + name + " contentType=" + contentType + " enable=" + enabled);
this.props.toggleContent(country, name, contentType, enabled, this.componentDidMount);
}*/
render() {
var self = this;
if (!this.state.radiosLoaded) {
@@ -67,11 +74,23 @@ class Playlist extends Component {
}
{current.map(function(radio, i) {
return (
<PlaylistItem className={classNames({ active: true })} key={"item" + i} onClick={function() { self.remove(radio.country, radio.name); }}>
<PlaylistItemText>
{radio.name}
</PlaylistItemText>
<PlaylistItemLogo src={radio.favicon || defaultCover} alt="logo" />
<PlaylistItem className={classNames({ active: true })} key={"item" + i}>
<PlaylistItemTopRow>
<PlaylistItemLogo src={radio.favicon || defaultCover} alt="logo" onClick={function() { self.remove(radio.country, radio.name); }} />
<PlaylistItemText onClick={function() { self.remove(radio.country, radio.name); }}>
{radio.name}
</PlaylistItemText>
</PlaylistItemTopRow>
<PlaylistItemConfigContainer>
<label>
<Checkbox
checked={!radio.content.ads}
onChange={(e) => self.props.toggleContent(radio.country, radio.name, "ads", !e.target.checked, self.componentDidMount)}
disabled={!self.props.config.user.token}
/>
&nbsp; skip ads
</label>
</PlaylistItemConfigContainer>
</PlaylistItem>
)
})}
@@ -83,10 +102,12 @@ class Playlist extends Component {
{available.map(function(radio, i) {
return (
<PlaylistItem className={classNames({ active: !playlistFull })} key={"item" + i} onClick={function() { if (!playlistFull) self.insert(radio.country, radio.name); }}>
<PlaylistItemText>
{radio.name}
</PlaylistItemText>
<PlaylistItemLogo src={radio.favicon || defaultCover} alt="logo" />
<PlaylistItemTopRow>
<PlaylistItemLogo src={radio.favicon || defaultCover} alt="logo" />
<PlaylistItemText>
{radio.name}
</PlaylistItemText>
</PlaylistItemTopRow>
</PlaylistItem>
)
})}
@@ -118,6 +139,7 @@ const PlaylistItem = styled.div`
flex-shrink: 0;
background: #eee;
display: flex;
flex-direction: column;
cursor: not-allowed;
&.active {
@@ -125,16 +147,26 @@ const PlaylistItem = styled.div`
}
`;
const PlaylistItemTopRow = styled.div`
display: flex;
flex-direction: row;
margin-bottom: 10px;
`;
const PlaylistItemText = styled.p`
flex-grow: 1;
align-self: center;
`
`;
const PlaylistItemLogo = styled.img`
width: 60px;
height: 60px;
align-self: center;
margin-left: 10px;
margin-right: 10px;
`;
const PlaylistItemConfigContainer = styled.div`
flex-grow: 1;
`;
export default Playlist;
+20 -10
View File
@@ -1,6 +1,6 @@
"use strict";
var log = require("loglevel");
var log = require("./log.js")("config");
var fs = require("fs");
var { getRadioMetadata } = require("../adblockradio-dl/dl.js");
var { getAvailable } = require("webradio-metadata");
@@ -30,7 +30,7 @@ var isRadioInConfig = function(country, name) {
return isAlreadyThere;
}
var insertRadio = function(country, name, callback) {
exports.insertRadio = function(country, name, callback) {
if (isRadioInConfig()) return callback("Radio already in the list");
if (config.radios.length >= config.user.maxRadios) return callback("Playlist is already full");
@@ -43,7 +43,7 @@ var insertRadio = function(country, name, callback) {
"country": country,
"name": name,
"content": {
"ads": true,
"ads": false,
"speech": true,
"music": true
},
@@ -55,7 +55,7 @@ var insertRadio = function(country, name, callback) {
});
}
var removeRadio = function(country, name, callback) {
exports.removeRadio = function(country, name, callback) {
for (var i=0; i<config.radios.length; i++) {
if (config.radios[i].country == country && config.radios[i].name == name) {
@@ -67,10 +67,21 @@ var removeRadio = function(country, name, callback) {
return callback("Radio not in the list");
}
exports.insertRadio = insertRadio;
exports.removeRadio = removeRadio;
exports.toggleContent = function(country, name, type, enable, callback) {
if (enable != "enable" && enable != "disable") {
return callback("keywords allowed are 'enable' and 'disable'");
}
for (var i=0; i<config.radios.length; i++) {
if (config.radios[i].country == country && config.radios[i].name == name) {
config.radios[i].content[type] = (enable == "enable") ? true : false;
saveRadios();
return callback(null);
}
}
return callback("Radio not in the list");
}
var getRadios = function() {
exports.getRadios = function() {
var radios = [];
for (var i=0; i<config.radios.length; i++) { // control on what data is exposed via the api
var radio = config.radios[i];
@@ -87,12 +98,11 @@ var getRadios = function() {
return radios;
}
exports.getRadios = getRadios;
var getUserConfig = function() {
var result = {};
Object.assign(result, {
token: config.user.token ? true : false,
cacheLen: config.user.cacheLen,
streamInitialBuffer: config.user.streamInitialBuffer,
streamGranularity: config.user.streamGranularity,
@@ -104,7 +114,7 @@ var getUserConfig = function() {
exports.getUserConfig = getUserConfig;
var saveRadios = function() {
var exportedRadios = getRadios();
var exportedRadios = exports.getRadios();
fs.writeFile("config/radios.json", JSON.stringify(exportedRadios), function(err) {
if (err) {
log.error("saveRadios: could not save radio config. err=" + err);
+53 -35
View File
@@ -3,8 +3,7 @@
"use strict";
var log = require("loglevel");
log.setLevel("debug");
var log = require("./log.js")("master");
var cp = require("child_process");
var findDataFiles = require("./findDataFiles.js");
var async = require("async");
@@ -17,7 +16,7 @@ const SEG_DURATION = 10; // in seconds
const LISTEN_BUFFER = 30; // in seconds
var USE_ABRSDK = true;
var { config, getRadios, getUserConfig, insertRadio, removeRadio, getAvailableInactive } = require("./config.js");
var { config, getRadios, getUserConfig, insertRadio, removeRadio, toggleContent, getAvailableInactive } = require("./config.js");
var dl = [];
var updateDlList = function() {
@@ -73,7 +72,30 @@ var updateDlList = function() {
} else {
if (playlistArray.length != validatedPlaylist.length) {
log.warn("abrsdk: playlist not accepted. requested=" + JSON.stringify(playlistArray) + " validated=" + JSON.stringify(validatedPlaylist));
} else {
log.debug("abrsdk: playlist successfully updated");
}
abrsdk.setPredictionCallback(function(predictions) {
var status, volume;
for (var i=0; i<predictions.radios.length; i++) {
switch (predictions.status[i]) {
case abrsdk.statusList.STATUS_AD: status = "AD"; break;
case abrsdk.statusList.STATUS_SPEECH: status = "SPEECH"; break;
case abrsdk.statusList.STATUS_MUSIC: status = "MUSIC"; break;
default: status = "not available";
}
// normalized volume to apply to the audio tag to have similar loudness between channels
volume = Math.pow(10, (Math.min(abrsdk.GAIN_REF-predictions.gain[i],0))/20);
// you can now plug the data to your radio player.
//log.debug("abrsdk: " + predictions.radios[i] + " has status " + status + " and volume " + Math.round(volume*100)/100);
var radio = getRadio(predictions.radios[i]);
if (!radio || !radio.liveStatus || !radio.liveStatus.onClassPrediction) {
log.error("abrsdk: cannot call prediction callback");
} else {
radio.liveStatus.onClassPrediction(status, volume);
}
}
});
}
});
}
@@ -84,28 +106,6 @@ if (USE_ABRSDK) {
if (err) {
log.error("abrsdk: connection error: " + err + ". switch off sdk");
USE_ABRSDK = false;
} else {
abrsdk.setPredictionCallback(function(predictions) {
var status, volume;
for (var i=0; i<predictions.radios.length; i++) {
switch (predictions.status[i]) {
case abrsdk.statusList.STATUS_AD: status = "AD"; break;
case abrsdk.statusList.STATUS_SPEECH: status = "SPEECH"; break;
case abrsdk.statusList.STATUS_MUSIC: status = "MUSIC"; break;
default: status = "not available";
}
// normalized volume to apply to the audio tag to have similar loudness between channels
volume = Math.pow(10, (Math.min(abrsdk.GAIN_REF-predictions.gain[i],0))/20);
// you can now plug the data to your radio player.
//log.debug("abrsdk: " + predictions.radios[i] + " has status " + status + " and volume " + Math.round(volume*100)/100);
var radio = getRadio(predictions.radios[i]);
if (!radio || !radio.liveStatus || !radio.liveStatus.onClassPrediction) {
log.error("abrsdk: cannot call prediction callback");
} else {
radio.liveStatus.onClassPrediction(status, volume);
}
}
});
}
updateDlList();
});
@@ -132,10 +132,10 @@ app.get('/config/radios/insert/:country/:name', function(request, response) {
if (err) {
log.error("/config/insert/" + country + "/" + name + ": err=" + err);
response.writeHead(400);
response.end();
response.end("err=" + err);
} else {
response.writeHead(200);
response.end();
response.end("OK");
updateDlList();
}
});
@@ -149,10 +149,10 @@ app.get('/config/radios/remove/:country/:name', function(request, response) {
if (err) {
log.error("/config/remove/" + country + "/" + name + ": err=" + err);
response.writeHead(400);
response.end();
response.end("err=" + err);
} else {
response.writeHead(200);
response.end();
response.end("OK");
updateDlList();
}
});
@@ -163,6 +163,24 @@ app.get('/config/radios/available', function(request, response) {
response.json(getAvailableInactive());
});
app.get('/config/radios/content/:country/:name/:type/:enable', function(request, response) {
response.set({ 'Access-Control-Allow-Origin': '*' });
var country = decodeURIComponent(request.params.country);
var name = decodeURIComponent(request.params.name);
var type = decodeURIComponent(request.params.type);
var enable = decodeURIComponent(request.params.enable);
toggleContent(country, name, type, enable, function(err) {
if (err) {
log.error("/config/radios/content/" + country + "/" + name + "/" + type + "/" + enable + ": err=" + err);
response.writeHead(400);
response.end("err=" + err);
} else {
response.writeHead(200);
response.end("OK");
}
});
});
var getRadio = function(country, name) {
if (name) { // both parameters used
for (var j=0; j<config.radios.length; j++) {
@@ -190,7 +208,7 @@ app.get('/:action/:radio/:delay', function(request, response) {
if (!getRadio(radio) || !getRadio(radio).enable) {
response.writeHead(400);
return response.end();
return response.end("radio not found");
}
switch(action) {
@@ -209,7 +227,7 @@ app.get('/:action/:radio/:delay', function(request, response) {
if (!initialBuffer) {
log.error("/listen/" + radio + "/" + delay + ": initialBuffer not available");
response.writeHead(400);
return response.end();
return response.end("buffer not available");
}
log.info("listen: send initial buffer of " + initialBuffer.length + " bytes");
@@ -274,21 +292,21 @@ app.get('/:action/:radio/:delay', function(request, response) {
if (!radio) {
log.error("/metadata/" + radio + "/" + delay + ": radio not available");
response.writeHead(400);
return response.end();
return response.end("radio not found");
} else if (!radio.liveStatus) {
log.error("/metadata/" + radio + "/" + delay + ": radio.liveStatus not available");
response.writeHead(400);
return response.end();
return response.end("radio not ready");
} else if (!radio.liveStatus.metaCache) {
log.error("/metadata/" + radio + "/" + delay + ": metadata not available");
response.writeHead(400);
return response.end();
return response.end("metadata not available");
}
response.json(radio.liveStatus.metaCache.read());
break;
default:
response.writeHead(400);
response.end();
response.end("unknown route");
}
});
+27
View File
@@ -0,0 +1,27 @@
var log = require("loglevel");
log.setLevel("debug");
var prefix = require('loglevel-plugin-prefix');
var chalk = require('chalk');
// #### logging decoration ####
// see https://github.com/kutuluk/loglevel-plugin-prefix
const colors = {
TRACE: chalk.magenta,
DEBUG: chalk.cyan,
INFO: chalk.blue,
WARN: chalk.yellow,
ERROR: chalk.red,
};
prefix.reg(log);
log.enableAll();
prefix.apply(log, {
format(level, name, timestamp) {
return `${chalk.gray(`[${timestamp}]`)} ${colors[level.toUpperCase()](level)} ${chalk.green(`${name}:`)}`;
},
});
module.exports = function(moduleName) {
return log.getLogger(moduleName || "root");
}
+41 -45
View File
@@ -37,8 +37,11 @@
}
},
"adblockradio-sdk": {
"version": "git://github.com/dest4/adblockradio-sdk.git#149fde37e278f45c77c5c8c09e17321a9cf2152b",
"version": "git://github.com/dest4/adblockradio-sdk.git#52e27c7a8f38690fe16a5915c74bc23be29bebee",
"requires": {
"chalk": "2.3.0",
"loglevel": "1.6.1",
"loglevel-plugin-prefix": "0.8.3",
"socket.io-client": "2.0.4"
}
},
@@ -261,7 +264,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
"dev": true,
"requires": {
"ansi-styles": "3.2.0",
"escape-string-regexp": "1.0.5",
@@ -272,7 +274,6 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
"dev": true,
"requires": {
"color-convert": "1.9.1"
}
@@ -281,7 +282,6 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"dev": true,
"requires": {
"has-flag": "2.0.0"
}
@@ -325,7 +325,6 @@
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -333,8 +332,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"component-bind": {
"version": "1.0.0",
@@ -374,12 +372,9 @@
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-security-policy-builder": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-1.1.0.tgz",
"integrity": "sha1-2R8bB2I2wRmFDH3umSS/VeBXcrM=",
"requires": {
"dashify": "0.2.2"
}
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz",
"integrity": "sha512-j+Nhmj1yfZAikJLImCvPJFE29x/UuBi+/MWqggGGc515JKaZrjuei2RhULJmy0MsstW3E3htl002bwmBNMKr7w=="
},
"content-type": {
"version": "1.0.4",
@@ -418,11 +413,6 @@
"resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz",
"integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg="
},
"dashify": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dashify/-/dashify-0.2.2.tgz",
"integrity": "sha1-agdBWgHJH69KMuONnfunH2HLIP4="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -487,9 +477,9 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"engine.io-client": {
"version": "3.1.4",
@@ -529,8 +519,7 @@
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint": {
"version": "4.15.0",
@@ -675,7 +664,7 @@
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.2",
"encodeurl": "1.0.1",
"encodeurl": "1.0.2",
"escape-html": "1.0.3",
"etag": "1.8.1",
"finalhandler": "1.1.0",
@@ -752,7 +741,7 @@
"integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
"requires": {
"debug": "2.6.9",
"encodeurl": "1.0.1",
"encodeurl": "1.0.2",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
@@ -864,19 +853,18 @@
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
},
"helmet": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-3.9.0.tgz",
"integrity": "sha512-czCyS77TyanWlfVSoGlb9GBJV2Q2zJayKxU5uBw0N1TzDTs/qVNh1SL8Q688KU0i0Sb7lQ/oLtnaEqXzl2yWvA==",
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-3.10.0.tgz",
"integrity": "sha512-wVu5jSeImztLqNQPc4hqGr1DG0Ki2UJVmQ1KTugIrtl1f4Zw5SqVqh6QPyw5b6/Jo/iAnyTt+pcehB0RdEJsbw==",
"requires": {
"dns-prefetch-control": "0.1.0",
"dont-sniff-mimetype": "1.0.0",
"expect-ct": "0.1.0",
"frameguard": "3.0.0",
"helmet-csp": "2.6.0",
"helmet-csp": "2.7.0",
"hide-powered-by": "1.0.0",
"hpkp": "2.0.0",
"hsts": "2.1.0",
@@ -887,15 +875,15 @@
}
},
"helmet-csp": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.6.0.tgz",
"integrity": "sha512-n/oW9l6RtO4f9YvphsNzdvk1zITrSN7iRT8ojgrJu/N3mVdHl9zE4OjbiHWcR64JK32kbqx90/yshWGXcjUEhw==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.7.0.tgz",
"integrity": "sha512-IGIAkWnxjRbgMXFA2/kmDqSIrIaSfZ6vhMHlSHw7jm7Gm9nVVXqwJ2B1YEpYrJsLrqY+w2Bbimk7snux9+sZAw==",
"requires": {
"camelize": "1.0.0",
"content-security-policy-builder": "1.1.0",
"content-security-policy-builder": "2.0.0",
"dasherize": "2.0.0",
"lodash.reduce": "4.6.0",
"platform": "1.3.4"
"platform": "1.3.5"
}
},
"hide-powered-by": {
@@ -1111,6 +1099,11 @@
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz",
"integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po="
},
"loglevel-plugin-prefix": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.3.tgz",
"integrity": "sha512-oFDEE3krjFTlyXfdT6shN4HsIlDrbPyleI2WIgRfn//oUEVfe8dP7goO9ktTSdOQC08CTKshKHHdZXe4Dy9TxQ=="
},
"lru-cache": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
@@ -1328,9 +1321,9 @@
}
},
"platform": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.4.tgz",
"integrity": "sha1-bw+xftqqSPIUQrOpdcBjEw8cPr0="
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.5.tgz",
"integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
},
"pluralize": {
"version": "7.0.0",
@@ -1503,7 +1496,7 @@
"debug": "2.6.9",
"depd": "1.1.2",
"destroy": "1.0.4",
"encodeurl": "1.0.1",
"encodeurl": "1.0.2",
"escape-html": "1.0.3",
"etag": "1.8.1",
"fresh": "0.5.2",
@@ -1520,7 +1513,7 @@
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
"integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==",
"requires": {
"encodeurl": "1.0.1",
"encodeurl": "1.0.2",
"escape-html": "1.0.3",
"parseurl": "1.3.2",
"send": "0.16.1"
@@ -1742,12 +1735,15 @@
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"webradio-metadata": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/webradio-metadata/-/webradio-metadata-0.1.6.tgz",
"integrity": "sha512-345c6QzlnstTB9CZ4s535P2DwqSD0R1Uw/E9yHd4hwCpw3jNITelnxQ7biK78zXIKTDy4Po1dkKUwqUVHyiNOA==",
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/webradio-metadata/-/webradio-metadata-0.1.7.tgz",
"integrity": "sha512-0aS0WAxt+ptSxYtIzOmXDlRQODw4pG3Lm+8d06AKF4WQF1YzjsCCAuoRY5wK0Sj7wPdGI98pPevpPCpsjbrA3w==",
"requires": {
"chalk": "2.3.0",
"express": "4.16.2",
"helmet": "3.9.0",
"helmet": "3.10.0",
"loglevel": "1.6.1",
"loglevel-plugin-prefix": "0.8.3",
"xml2js": "0.4.19"
}
},
+3 -1
View File
@@ -11,8 +11,10 @@
"dependencies": {
"adblockradio-sdk": "git://github.com/dest4/adblockradio-sdk.git#master",
"async": "^2.6.0",
"chalk": "^2.3.0",
"loglevel": "^1.6.1",
"webradio-metadata": "^0.1.6"
"loglevel-plugin-prefix": "^0.8.3",
"webradio-metadata": "^0.1.7"
},
"devDependencies": {
"eslint": "^4.15.0"