Advertisement
Guest User

Untitled

a guest
Jan 25th, 2017
529
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'use strict';
  2.  
  3. var libMpd = require('mpd');
  4. var libQ = require('kew');
  5. var libFast = require('fast.js');
  6. var libFsExtra = require('fs-extra');
  7. var exec = require('child_process').exec;
  8. var nodetools = require('nodetools');
  9. var convert = require('convert-seconds');
  10. var pidof = require('pidof');
  11. var parser = require('cue-parser');
  12. var mm = require('musicmetadata');
  13. var os = require('os');
  14. var execSync = require('child_process').execSync;
  15.  
  16. // Define the ControllerMpd class
  17. module.exports = ControllerMpd;
  18. function ControllerMpd(context) {
  19.     // This fixed variable will let us refer to 'this' object at deeper scopes
  20.     this.context = context;
  21.     this.commandRouter = this.context.coreCommand;
  22.     this.logger = this.context.logger;
  23.     this.configManager = this.context.configManager;
  24.     this.config = new (require('v-conf'))();
  25. }
  26.  
  27. // Public Methods ---------------------------------------------------------------------------------------
  28. // These are 'this' aware, and return a promise
  29.  
  30. // Define a method to clear, add, and play an array of tracks
  31.  
  32. //MPD Play
  33. ControllerMpd.prototype.play = function (N) {
  34.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::play ' + N);
  35.     return this.sendMpdCommand('play', [N]);
  36. };
  37.  
  38. //MPD Add
  39. ControllerMpd.prototype.add = function (data) {
  40.     this.commandRouter.pushToastMessage('success', data + self.commandRouter.getI18nString('COMMON.ADD_QUEUE_TEXT_1'));
  41.     return this.sendMpdCommand('add', [data]);
  42. };
  43. //MPD Remove
  44. ControllerMpd.prototype.remove = function (position) {
  45.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::remove ' + position);
  46.     return this.sendMpdCommand('delete', [position]);
  47. };
  48.  
  49.  
  50.  
  51.  
  52.  
  53. //MPD Next
  54. ControllerMpd.prototype.next = function () {
  55.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::next');
  56.     return this.sendMpdCommand('next', []);
  57. };
  58.  
  59. //MPD Previous
  60. ControllerMpd.prototype.previous = function () {
  61.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::previous');
  62.     return this.sendMpdCommand('previous', []);
  63. };
  64.  
  65. //MPD Seek
  66. ControllerMpd.prototype.seek = function (timepos) {
  67.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::seek to ' + timepos);
  68.     return this.sendMpdCommand('seekcur', [timepos]);
  69. };
  70.  
  71. //MPD Random
  72. ControllerMpd.prototype.random = function (randomcmd) {
  73.     var string = randomcmd ? 1 : 0;
  74.     this.commandRouter.pushToastMessage('success', "Random", string === 1 ? self.commandRouter.getI18nString('COMMON.ON') : self.commandRouter.getI18nString('COMMON.OFF'));
  75.     return this.sendMpdCommand('random', [string])
  76. };
  77.  
  78. //MPD Repeat
  79. ControllerMpd.prototype.repeat = function (repeatcmd) {
  80.     var string = repeatcmd ? 1 : 0;
  81.     this.commandRouter.pushToastMessage('success', "Repeat", string === 1 ? self.commandRouter.getI18nString('COMMON.ON') : self.commandRouter.getI18nString('COMMON.ON'));
  82.     return this.sendMpdCommand('repeat', [string]);
  83. };
  84.  
  85.  
  86.  
  87.  
  88. // MPD clear
  89. ControllerMpd.prototype.clear = function () {
  90.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::clear');
  91.     return this.sendMpdCommand('clear', []);
  92. };
  93.  
  94. // MPD enable output
  95. ControllerMpd.prototype.enableOutput = function (output) {
  96.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'Enable Output ' + output);
  97.     return this.sendMpdCommand('enableoutput', [output]);
  98. };
  99.  
  100. // MPD disable output
  101. ControllerMpd.prototype.disableOutput = function (output) {
  102.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'Disable Output ' + output);
  103.     return this.sendMpdCommand('disableoutput', [output]);
  104. };
  105.  
  106. //UpdateDB
  107. ControllerMpd.prototype.updateMpdDB = function () {
  108.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'Update mpd DB');
  109.     return this.sendMpdCommand('update', []);
  110. };
  111.  
  112.  
  113. ControllerMpd.prototype.addPlay = function (fileName) {
  114.     var self=this;
  115.  
  116.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::addPlay');
  117.     this.commandRouter.pushToastMessage('Success', '', fileName + self.commandRouter.getI18nString('COMMON.ADD_QUEUE_TEXT_1'));
  118.  
  119.  
  120.     //Add playlists and cue with load command
  121.     if (fileName.endsWith('.cue') || fileName.endsWith('.pls') || fileName.endsWith('.m3u')) {
  122.         this.logger.info('Adding Playlist: ' + fileName);
  123.         return this.sendMpdCommandArray([
  124.             {command: 'clear', parameters: []},
  125.             {command: 'load', parameters: [fileName]},
  126.             {command: 'play', parameters: []}
  127.         ])
  128.     } else if (fileName.startsWith('albums')) {
  129.         self.logger.info("PLAYYYYYYYY");
  130.         return self.playAlbum(fileName);
  131.     } else {
  132.         return this.sendMpdCommandArray([
  133.             {command: 'clear', parameters: []},
  134.             {command: 'add', parameters: [fileName]},
  135.             {command: 'play', parameters: []}
  136.         ])
  137.     }
  138.     /*.then(function() {
  139.      self.commandRouter.volumioPlay();
  140.  
  141.      });*/
  142. };
  143.  
  144. ControllerMpd.prototype.addPlayCue = function (data) {
  145.     //this.commandRouter.pushToastMessage('Success', '', data.uri + self.commandRouter.getI18nString('COMMON.ADD_QUEUE_TEXT_1'));
  146.  
  147.     //Add playlists and cue with load command
  148.  
  149.     console.log(data);
  150.     if(data.number!==undefined)
  151.     {
  152.         this.logger.info('Adding CUE individual entry: ' + data.number + ' ' + data.uri);
  153.  
  154.         this.commandRouter.addQueueItems([{
  155.             uri:'cue://'+data.uri+'@'+data.number,
  156.             service:'mpd'
  157.         }]);
  158.  
  159.         var index=this.commandRouter.stateMachine.playQueue.arrayQueue.length;
  160.         this.commandRouter.volumioPlay(index);
  161.     }
  162.  
  163.  
  164.  
  165.     var items=[];
  166.  
  167.     /*
  168.      var cuesheet = parser.parse('/mnt/' + path);
  169.  
  170.      list.push({
  171.      service: 'mpd',
  172.      type: 'song',
  173.      title: name,
  174.      icon: 'fa fa-list-ol',
  175.      uri: s0 + path
  176.      });
  177.      var tracks = cuesheet.files[0].tracks;
  178.      for (var j in tracks) {
  179.  
  180.      list.push({
  181.      service: 'mpd',
  182.      type: 'cuesong',
  183.      title: tracks[j].title,
  184.      artist: tracks[j].performer,
  185.      album: path.substring(path.lastIndexOf("/") + 1),
  186.      number: tracks[j].number - 1,
  187.      icon: 'fa fa-music',
  188.      uri: s0 + path
  189.      });
  190.      }*/
  191.  
  192.  
  193.     /*this.commandRouter.addQueueItems();
  194.  
  195.     return this.sendMpdCommandArray([
  196.         {command: 'clear', parameters: []},
  197.         {command: 'load', parameters: [data.uri]},
  198.         {command: 'play', parameters: [data.number]}
  199.     ])*/
  200. };
  201.  
  202.  
  203. // MPD music library
  204. ControllerMpd.prototype.getTracklist = function () {
  205.     var self = this;
  206.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::getTracklist');
  207.  
  208.     return self.mpdReady
  209.         .then(function () {
  210.             return libQ.nfcall(self.clientMpd.sendCommand.bind(self.clientMpd), libMpd.cmd('listallinfo', []));
  211.         })
  212.         .then(function (objResult) {
  213.             var listInfo = self.parseListAllInfoResult(objResult);
  214.             return listInfo.tracks;
  215.         });
  216. };
  217.  
  218. // Internal methods ---------------------------------------------------------------------------
  219. // These are 'this' aware, and may or may not return a promise
  220.  
  221. // Parses the info out of the 'listallinfo' MPD command
  222. // Metadata fields to roughly conform to Ogg Vorbis standards (http://xiph.org/vorbis/doc/v-comment.html)
  223. ControllerMpd.prototype.parseListAllInfoResult = function (sInput) {
  224.  
  225.     var arrayLines = sInput.split('\n');
  226.     var objReturn = {};
  227.     var curEntry = {};
  228.  
  229.     objReturn.tracks = [];
  230.     objReturn.playlists = [];
  231.     var nLines = arrayLines.length;
  232.  
  233.     for (var i = 0; i < nLines; i++) {
  234.         var arrayLineParts = libFast.map(arrayLines[i].split(':'), function (sPart) {
  235.             return sPart.trim();
  236.         });
  237.  
  238.         if (arrayLineParts[0] === 'file') {
  239.             curEntry = {
  240.                 'name': '',
  241.                 'service': this.servicename,
  242.                 'uri': arrayLineParts[1],
  243.                 'browsepath': [this.displayname].concat(arrayLineParts[1].split('/').slice(0, -1)),
  244.                 'artists': [],
  245.                 'album': '',
  246.                 'genres': [],
  247.                 'performers': [],
  248.                 'tracknumber': 0,
  249.                 'date': '',
  250.                 'duration': 0
  251.             };
  252.             objReturn.tracks.push(curEntry);
  253.         } else if (arrayLineParts[0] === 'playlist') {
  254.             // Do we even need to parse MPD playlists?
  255.         } else if (arrayLineParts[0] === 'Time') {
  256.             curEntry.duration = arrayLineParts[1];
  257.         } else if (arrayLineParts[0] === 'Title') {
  258.             curEntry.name = arrayLineParts[1];
  259.         } else if (arrayLineParts[0] === 'Artist') {
  260.             curEntry.artists = libFast.map(arrayLineParts[1].split(','), function (sArtist) {
  261.                 // TODO - parse other options in artist string, such as "feat."
  262.                 return sArtist.trim();
  263.             });
  264.         } else if (arrayLineParts[0] === 'AlbumArtist') {
  265.             curEntry.performers = libFast.map(arrayLineParts[1].split(','), function (sPerformer) {
  266.                 return sPerformer.trim();
  267.             });
  268.         } else if (arrayLineParts[0] === 'Album') {
  269.             curEntry.album = arrayLineParts[1];
  270.         } else if (arrayLineParts[0] === 'Track') {
  271.             curEntry.tracknumber = Number(arrayLineParts[1]);
  272.         } else if (arrayLineParts[0] === 'Date') {
  273.             // TODO - parse into a date object
  274.             curEntry.date = arrayLineParts[1];
  275.         }
  276.     }
  277.  
  278.     return objReturn;
  279. };
  280.  
  281. // Define a method to get the MPD state
  282. ControllerMpd.prototype.getState = function () {
  283.  
  284.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::getState');
  285.     var timeCurrentUpdate = Date.now();
  286.     this.timeLatestUpdate = timeCurrentUpdate;
  287.  
  288.     var self = this;
  289.     return self.sendMpdCommand('status', [])
  290.         /*.then(function(data) {
  291.          return self.haltIfNewerUpdateRunning(data, timeCurrentUpdate);
  292.          })*/
  293.         .then(function (objState) {
  294.             var collectedState = self.parseState(objState);
  295.  
  296.             // If there is a track listed as currently playing, get the track info
  297.             if (collectedState.position !== null) {
  298.                 return self.sendMpdCommand('playlistinfo', [collectedState.position])
  299.                     /*.then(function(data) {
  300.                      return self.haltIfNewerUpdateRunning(data, timeCurrentUpdate);
  301.                      })*/
  302.                     .then(function (objTrackInfo) {
  303.                         var trackinfo = self.parseTrackInfo(objTrackInfo);
  304.                         collectedState.isStreaming = trackinfo.isStreaming != undefined ? trackinfo.isStreaming : false;
  305.                         collectedState.title = trackinfo.title;
  306.                         collectedState.artist = trackinfo.artist;
  307.                         collectedState.album = trackinfo.album;
  308.                         //collectedState.albumart = trackinfo.albumart;
  309.                         collectedState.uri = trackinfo.uri;
  310.                         collectedState.trackType = trackinfo.trackType;
  311.                         return collectedState;
  312.                     });
  313.                 // Else return null track info
  314.             } else {
  315.                 collectedState.isStreaming = false;
  316.                 collectedState.title = null;
  317.                 collectedState.artist = null;
  318.                 collectedState.album = null;
  319.                 //collectedState.albumart = null;
  320.                 collectedState.uri = null;
  321.                 return collectedState;
  322.             }
  323.         });
  324. };
  325.  
  326. // Stop the current status update thread if a newer one exists
  327. ControllerMpd.prototype.haltIfNewerUpdateRunning = function (data, timeCurrentThread) {
  328.     var self = this;
  329.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::haltIfNewerUpdateRunning');
  330.  
  331.     if (self.timeLatestUpdate > timeCurrentThread) {
  332.         return libQ.reject('Alert: Aborting status update - newer one detected');
  333.     } else {
  334.         return libQ.resolve(data);
  335.     }
  336. };
  337.  
  338. // Announce updated MPD state
  339. ControllerMpd.prototype.pushState = function (state) {
  340.     var self = this;
  341.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::pushState');
  342.  
  343.     return self.commandRouter.servicePushState(state, self.servicename);
  344. };
  345.  
  346. // Pass the error if we don't want to handle it
  347. ControllerMpd.prototype.pushError = function (sReason) {
  348.     var self = this;
  349.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::pushError');
  350.     self.commandRouter.pushConsoleMessage(sReason);
  351.  
  352.     // Return a resolved empty promise to represent completion
  353.     return libQ.resolve();
  354. };
  355.  
  356. // Define a general method for sending an MPD command, and return a promise for its execution
  357. ControllerMpd.prototype.sendMpdCommand = function (sCommand, arrayParameters) {
  358.     var self = this;
  359.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::sendMpdCommand '+sCommand);
  360.  
  361.     return self.mpdReady
  362.         .then(function () {
  363.             self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'sending command...');
  364.             return libQ.nfcall(self.clientMpd.sendCommand.bind(self.clientMpd), libMpd.cmd(sCommand, arrayParameters));
  365.         })
  366.         .then(function (response) {
  367.             self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'parsing response...');
  368.             var respobject = libMpd.parseKeyValueMessage.call(libMpd, response);
  369.             // If there's an error show an alert on UI
  370.             if ('error' in respobject) {
  371.                 self.commandRouter.broadcastToastMessage('error', 'Error', respobject.error)
  372.                 //console.log(respobject.error);
  373.             }
  374.             return libQ.resolve(respobject);
  375.         });
  376. };
  377.  
  378. // Define a general method for sending an array of MPD commands, and return a promise for its execution
  379. // Command array takes the form [{command: sCommand, parameters: arrayParameters}, ...]
  380. ControllerMpd.prototype.sendMpdCommandArray = function (arrayCommands) {
  381.     var self = this;
  382.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::sendMpdCommandArray');
  383.  
  384.     return self.mpdReady
  385.         .then(function () {
  386.             return libQ.nfcall(self.clientMpd.sendCommands.bind(self.clientMpd),
  387.                 libFast.map(arrayCommands, function (currentCommand) {
  388.                     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'COMMAND '+currentCommand);
  389.                     return libMpd.cmd(currentCommand.command, currentCommand.parameters);
  390.                 })
  391.             );
  392.         })
  393.         .then(libMpd.parseKeyValueMessage.bind(libMpd));
  394. };
  395.  
  396. // Parse MPD's track info text into Volumio recognizable object
  397. ControllerMpd.prototype.parseTrackInfo = function (objTrackInfo) {
  398.  
  399.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::parseTrackInfo');
  400.  
  401.     //self.commandRouter.logger.info(JSON.stringify("OBJTRACKINFO "+JSON.stringify(objTrackInfo)));
  402.     var resp = {};
  403.  
  404.  
  405.     if (objTrackInfo.Time === 0){
  406.         resp.isStreaming = true;
  407.     }
  408.  
  409.     if (objTrackInfo.file != undefined) {
  410.         resp.uri = objTrackInfo.file;
  411.         resp.trackType = objTrackInfo.file.split('.').pop();
  412.         if (resp.uri.indexOf('cdda:///') >= 0) {
  413.             resp.trackType = 'CD Audio';
  414.             resp.title = resp.uri.replace('cdda:///', 'Track ');
  415.         }
  416.         else if (resp.uri.indexOf('http://') >= 0) {
  417.             resp.service='dirble';
  418.         }
  419.     } else {
  420.         resp.uri = null;
  421.     }
  422.  
  423.     if (objTrackInfo.Title != undefined) {
  424.         resp.title = objTrackInfo.Title;
  425.     } else {
  426.         var file = objTrackInfo.file;
  427.         if(file!== undefined)
  428.         {
  429.             var filetitle = file.replace(/^.*\/(?=[^\/]*$)/, '');
  430.  
  431.             resp.title = filetitle;
  432.         }
  433.  
  434.     }
  435.  
  436.     if (objTrackInfo.Artist != undefined) {
  437.         resp.artist = objTrackInfo.Artist;
  438.     } else {
  439.         resp.artist = null;
  440.     }
  441.  
  442.     if (objTrackInfo.Album != undefined) {
  443.         resp.album = objTrackInfo.Album;
  444.     } else {
  445.         resp.album = null;
  446.     }
  447.  
  448.     var web;
  449.  
  450.     if (objTrackInfo.Artist != undefined) {
  451.         if (objTrackInfo.Album != undefined) {
  452.             web = {artist: objTrackInfo.Artist, album: objTrackInfo.Album};
  453.         } else {
  454.             web = {artist: objTrackInfo.Artist};
  455.         }
  456.     }
  457.  
  458.     var artUrl;
  459.  
  460.     if (resp.isStreaming) {
  461.         artUrl = this.getAlbumArt(web);
  462.     } else {
  463.         artUrl = this.getAlbumArt(web, file);
  464.     }
  465.  
  466.     resp.albumart = artUrl;
  467.  
  468.     return resp;
  469. };
  470.  
  471. // Parse MPD's text playlist into a Volumio recognizable playlist object
  472. ControllerMpd.prototype.parsePlaylist = function (objQueue) {
  473.     var self = this;
  474.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::parsePlaylist');
  475.  
  476.     // objQueue is in form {'0': 'file: http://uk4.internet-radio.com:15938/', '1': 'file: http://2363.live.streamtheworld.com:80/KUSCMP128_SC'}
  477.     // We want to convert to a straight array of trackIds
  478.     return libQ.fcall(libFast.map, Object.keys(objQueue), function (currentKey) {
  479.         return convertUriToTrackId(objQueue[currentKey]);
  480.     });
  481. };
  482.  
  483. // Parse MPD's text status into a Volumio recognizable status object
  484. ControllerMpd.prototype.parseState = function (objState) {
  485.     var self = this;
  486.     //console.log(objState);
  487.  
  488.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::parseState');
  489.  
  490.     // Pull track duration out of status message
  491.     var nDuration = null;
  492.     if ('time' in objState) {
  493.         var arrayTimeData = objState.time.split(':');
  494.         nDuration = Math.round(Number(arrayTimeData[1]));
  495.     }
  496.  
  497.     // Pull the elapsed time
  498.     var nSeek = null;
  499.     if ('elapsed' in objState) {
  500.         nSeek = Math.round(Number(objState.elapsed) * 1000);
  501.     }
  502.  
  503.     // Pull the queue position of the current track
  504.     var nPosition = null;
  505.     if ('song' in objState) {
  506.         nPosition = Number(objState.song);
  507.     }
  508.  
  509.     // Pull audio metrics
  510.     var nBitDepth = null;
  511.     var nSampleRate = null;
  512.     var nChannels = null;
  513.     if ('audio' in objState) {
  514.         var objMetrics = objState.audio.split(':');
  515.         var nSampleRateRaw = Number(objMetrics[0]) / 1000;
  516.  
  517.             if (nSampleRateRaw === 352.8){
  518.                 var nSampleRateRaw = 2.82+' MHz';
  519.             } else if (nSampleRateRaw === 705.6) {
  520.                 var nSampleRateRaw = 5.64+' MHz';
  521.             } else if (nSampleRateRaw === 1411.2) {
  522.                 var nSampleRateRaw = 11.2+' MHz';
  523.             }else {
  524.                 var nSampleRateRaw = nSampleRateRaw+' KHz';
  525.             }
  526.         nSampleRate = nSampleRateRaw;
  527.         nBitDepth = Number(objMetrics[1])+' bit';
  528.         nChannels = Number(objMetrics[2]);
  529.     }
  530.  
  531.     var random = null;
  532.     if ('random' in objState) {
  533.         random = objState.random == 1;
  534.     }
  535.  
  536.     var repeat = null;
  537.     if ('repeat' in objState) {
  538.         repeat = objState.repeat == 1;
  539.     }
  540.  
  541.     var sStatus = null;
  542.     if ('state' in objState) {
  543.         sStatus = objState.state;
  544.     }
  545.  
  546.     var updatedb = false;
  547.     if ('updating_db' in objState) {
  548.         updatedb = true;
  549.     }
  550.  
  551.     return {
  552.         status: sStatus,
  553.         position: nPosition,
  554.         seek: nSeek,
  555.         duration: nDuration,
  556.         samplerate: nSampleRate,
  557.         bitdepth: nBitDepth,
  558.         channels: nChannels,
  559.         random: random,
  560.         updatedb: updatedb,
  561.         repeat: repeat
  562.     };
  563. };
  564.  
  565. ControllerMpd.prototype.logDone = function (timeStart) {
  566.     var self = this;
  567.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + '------------------------------ ' + (Date.now() - timeStart) + 'ms');
  568.     return libQ.resolve();
  569. };
  570.  
  571. ControllerMpd.prototype.logStart = function (sCommand) {
  572.     var self = this;
  573.     self.commandRouter.pushConsoleMessage('\n' + '[' + Date.now() + '] ' + '---------------------------- ' + sCommand);
  574.     return libQ.resolve();
  575. };
  576.  
  577. /*
  578.  * This method can be defined by every plugin which needs to be informed of the startup of Volumio.
  579.  * The Core controller checks if the method is defined and executes it on startup if it exists.
  580.  */
  581. ControllerMpd.prototype.onVolumioStart = function () {
  582.     var self = this;
  583.  
  584.     this.commandRouter.sharedVars.registerCallback('alsa.outputdevice', this.outputDeviceCallback.bind(this));
  585.     // Connect to MPD only if process MPD is running
  586.  
  587.     var configFile = self.commandRouter.pluginManager.getConfigurationFile(self.context, 'config.json');
  588.  
  589.  
  590.     self.config.loadFile(configFile);
  591.     pidof('mpd', function (err, pid) {
  592.         if (err) {
  593.             self.logger.info('Cannot initialize  MPD Connection: MPD is not running');
  594.         } else {
  595.             if (pid) {
  596.                 self.logger.info('MPD running with PID' + pid + ' ,establishing connection');
  597.                 self.mpdEstablish();
  598.  
  599.             } else {
  600.                 self.logger.info('Cannot initialize  MPD Connection: MPD is not running');
  601.             }
  602.         }
  603.     });
  604.  
  605.     return libQ.resolve();
  606. };
  607.  
  608. ControllerMpd.prototype.mpdEstablish = function () {
  609.     var self = this;
  610.  
  611.  
  612.     // TODO use names from the package.json instead
  613.     self.servicename = 'mpd';
  614.     self.displayname = 'MPD';
  615.  
  616.     //getting configuration
  617.  
  618.  
  619.     // Save a reference to the parent commandRouter
  620.     self.commandRouter = self.context.coreCommand;
  621.     // Connect to MPD
  622.     self.mpdConnect();
  623.  
  624.     // Make a promise for when the MPD connection is ready to receive events
  625.     self.mpdReady = libQ.nfcall(self.clientMpd.on.bind(self.clientMpd), 'ready');
  626.     // Catch and log errors
  627.     self.clientMpd.on('error', function (err) {
  628.         console.log('MPD error: ' + err);
  629.         if (err = "{ [Error: This socket has been ended by the other party] code: 'EPIPE' }") {
  630.             // Wait 5 seconds before trying to reconnect
  631.             setTimeout(function () {
  632.                 self.mpdEstablish();
  633.             }, 5000);
  634.         } else {
  635.             console.log(err);
  636.         }
  637.     });
  638.  
  639.     // This tracks the the timestamp of the newest detected status change
  640.     self.timeLatestUpdate = 0;
  641.     self.updateQueue();
  642.     // TODO remove pertaining function when properly found out we don't need em
  643.     //self.fswatch();
  644.     // When playback status changes
  645.     self.clientMpd.on('system', function (status) {
  646.         var timeStart = Date.now();
  647.  
  648.         self.logger.info('Mpd Status Update: '+status);
  649.         self.logStart('MPD announces state update')
  650.             .then(self.getState.bind(self))
  651.             .then(self.pushState.bind(self))
  652.             .fail(self.pushError.bind(self))
  653.             .done(function () {
  654.                 return self.logDone(timeStart);
  655.             });
  656.     });
  657.  
  658.  
  659.     self.clientMpd.on('system-playlist', function () {
  660.         var timeStart = Date.now();
  661.  
  662.         self.logStart('MPD announces system state update')
  663.             .then(self.updateQueue.bind(self))
  664.             .fail(self.pushError.bind(self))
  665.             .done(function () {
  666.                 return self.logDone(timeStart);
  667.             });
  668.     });
  669.  
  670.     //Notify that The mpd DB has changed
  671.     self.clientMpd.on('system-database', function () {
  672.         //return self.commandRouter.fileUpdate();
  673.         //return self.reportUpdatedLibrary();
  674.     });
  675.  
  676.  
  677.     self.clientMpd.on('system-update', function () {
  678.  
  679.          self.sendMpdCommand('status', [])
  680.             .then(function (objState) {
  681.                 var state = self.parseState(objState);
  682.                 execSync("/bin/sync", { uid: 1000, gid: 1000});
  683.                 return self.commandRouter.fileUpdate(state.updatedb);
  684.             });
  685.     });
  686. };
  687.  
  688. ControllerMpd.prototype.mpdConnect = function () {
  689.  
  690.     var self = this;
  691.  
  692.     var configFile = self.commandRouter.pluginManager.getConfigurationFile(self.context, 'config.json');
  693.  
  694.     self.config = new (require('v-conf'))();
  695.     self.config.loadFile(configFile);
  696.  
  697.     var nHost = self.config.get('nHost');
  698.     var nPort = self.config.get('nPort');
  699.     self.clientMpd = libMpd.connect({port: nPort, host: nHost});
  700. };
  701.  
  702. ControllerMpd.prototype.outputDeviceCallback = function () {
  703.     var self = this;
  704.  
  705.     var defer = libQ.defer();
  706.     self.context.coreCommand.pushConsoleMessage('Output device has changed, restarting MPD');
  707.     self.createMPDFile(function (error) {
  708.         if (error !== undefined && error !== null) {
  709.             self.commandRouter.pushToastMessage('error', self.commandRouter.getI18nString('COMMON.CONFIGURATION_UPDATE'), self.commandRouter.getI18nString('COMMON.CONFIGURATION_UPDATE_ERROR'));
  710.             defer.resolve({});
  711.         }
  712.         else {
  713.             //self.commandRouter.pushToastMessage('success', self.commandRouter.getI18nString('mpd_configuration_update'), self.commandRouter.getI18nString('mpd_playback_configuration_error'));
  714.  
  715.             self.restartMpd(function (error) {
  716.                 if (error !== null && error != undefined) {
  717.                     self.logger.info('Cannot restart MPD: ' + error);
  718.                     //self.commandRouter.pushToastMessage('error', self.commandRouter.getI18nString('mpd_player_restart'), self.commandRouter.getI18nString('mpd_player_restart_error'));
  719.                 }
  720.                 else {
  721.                     self.commandRouter.pushToastMessage('success', self.commandRouter.getI18nString('COMMON.CONFIGURATION_UPDATE'), self.commandRouter.getI18nString('COMMON.PLAYER_RESTARTED'));
  722.                     setTimeout(function(){self.mpdEstablish()}, 3000)
  723.                 }
  724.                 defer.resolve({});
  725.             });
  726.         }
  727.     });
  728. }
  729.  
  730.  
  731. ControllerMpd.prototype.savePlaybackOptions = function (data) {
  732.     var self = this;
  733.  
  734.     var defer = libQ.defer();
  735.  
  736.     self.config.set('volume_normalization', data['volume_normalization']);
  737.     self.config.set('audio_buffer_size', data['audio_buffer_size'].value);
  738.     self.config.set('buffer_before_play', data['buffer_before_play'].value);
  739.  
  740.     //fixing dop
  741.     if (self.config.get('dop') == null) {
  742.         self.config.addConfigValue('dop', 'boolean', true);
  743.     } else {
  744.         self.config.set('dop', data['dop']);
  745.     }
  746.  
  747.  
  748.     self.createMPDFile(function (error) {
  749.         if (error !== undefined && error !== null) {
  750.             //self.commandRouter.pushToastMessage('error', self.commandRouter.getI18nString('mpd_configuration_update'), self.commandRouter.getI18nString('mpd_configuration_update_error'));
  751.             defer.resolve({});
  752.         }
  753.         else {
  754.             //self.commandRouter.pushToastMessage('success', self.commandRouter.getI18nString('mpd_configuration_update'), self.commandRouter.getI18nString('mpd_playback_configuration_error'));
  755.  
  756.             self.restartMpd(function (error) {
  757.                 if (error !== null && error != undefined) {
  758.                     self.logger.error('Cannot restart MPD: ' + error);
  759.                     //self.commandRouter.pushToastMessage('error', self.commandRouter.getI18nString('mpd_player_restart'), self.commandRouter.getI18nString('mpd_player_restart_error'));
  760.                 }
  761.                 else
  762.                     //self.commandRouter.pushToastMessage('success', self.commandRouter.getI18nString('mpd_player_restart'), self.commandRouter.getI18nString('mpd_player_restart_success'));
  763.  
  764.                 defer.resolve({});
  765.             });
  766.         }
  767.     });
  768.  
  769.     return defer.promise;
  770.  
  771. };
  772.  
  773.  
  774. ControllerMpd.prototype.restartMpd = function (callback) {
  775.     var self = this;
  776.  
  777.     if (callback) {
  778.         exec('/usr/bin/sudo /bin/systemctl restart mpd.service ', {uid:1000, gid:1000},
  779.             function (error, stdout, stderr) {
  780.                 callback(error);
  781.             });
  782.     } else {
  783.         exec('/usr/bin/sudo /bin/systemctl restart mpd.service ', {uid:1000, gid:1000},
  784.             function (error, stdout, stderr) {
  785.                 if (error){
  786.                     self.logger.error('Cannot restart MPD: ' + error);
  787.                 }
  788.             });
  789.     }
  790.  
  791.  
  792. };
  793.  
  794. ControllerMpd.prototype.createMPDFile = function (callback) {
  795.     var self = this;
  796.  
  797.     exec('/usr/bin/sudo /bin/chmod 777 /etc/mpd.conf', {uid:1000,gid:1000},
  798.         function (error, stdout, stderr) {
  799.             if(error != null) {
  800.             self.logger.info('Error setting mpd conf file perms: '+error);
  801.             } else {
  802.                 self.logger.info('MPD Permissions set');
  803.             }
  804.         });
  805.  
  806.     try {
  807.  
  808.         fs.readFile(__dirname + "/mpd.conf.tmpl", 'utf8', function (err, data) {
  809.             if (err) {
  810.                 return console.log(err);
  811.             }
  812.             var outdev = self.getAdditionalConf('audio_interface', 'alsa_controller', 'outputdevice');
  813.             var mixer = self.getAdditionalConf('audio_interface', 'alsa_controller', 'mixer');
  814.             var mixerdev = '';
  815.             var mixerstrings = '';
  816.             if (outdev != 'softvolume' ) {
  817.                 mixerdev = 'hw:'+outdev;
  818.                 outdev = 'hw:'+outdev+',0';
  819.             } else {
  820.                 mixerdev = 'SoftMaster';
  821.             }
  822.  
  823.             var conf1 = data.replace("${gapless_mp3_playback}", self.checkTrue('gapless_mp3_playback'));
  824.             var conf2 = conf1.replace("${device}", outdev);
  825.             var conf3 = conf2.replace("${volume_normalization}", self.checkTrue('volume_normalization'));
  826.             var conf4 = conf3.replace("${audio_buffer_size}", self.config.get('audio_buffer_size'));
  827.             var conf5 = conf4.replace("${buffer_before_play}", self.config.get('buffer_before_play'));
  828.             if (self.config.get('dop')){
  829.                 var dop = 'yes';
  830.             } else {
  831.                 var dop = 'no';
  832.             }
  833.             var conf6 = conf5.replace("${dop}", dop);
  834.  
  835.  
  836.             if (mixer) {
  837.                 if (mixer.length > 0) {
  838.                     mixerstrings = 'mixer_device    "'+ mixerdev + '"' + os.EOL + '                mixer_control   "'+ mixer +'"'+ os.EOL + '                mixer_type      "hardware"'+ os.EOL;
  839.                 }
  840.             }
  841.  
  842.  
  843.             var conf7 = conf6.replace("${mixer}", mixerstrings);
  844.  
  845.             fs.writeFile("/etc/mpd.conf", conf7, 'utf8', function (err) {
  846.                 if (err) return console.log(err);
  847.             });
  848.         });
  849.  
  850.         callback();
  851.     }
  852.     catch (err) {
  853.  
  854.         callback(err);
  855.     }
  856.  
  857. };
  858.  
  859. ControllerMpd.prototype.checkTrue = function (config) {
  860.     var self = this;
  861.     var out = "no";
  862.     var value = self.config.get(config);
  863.  
  864.     if(value){
  865.         out = "yes";
  866.         return out
  867.     } else {
  868.         return out
  869.     }
  870. };
  871.  
  872.  
  873.  
  874. /*
  875.  * This method shall be defined by every plugin which needs to be configured.
  876.  */
  877. ControllerMpd.prototype.setConfiguration = function (configuration) {
  878.     //DO something intelligent
  879. };
  880.  
  881. ControllerMpd.prototype.getConfigParam = function (key) {
  882.     var self = this;
  883.  
  884.     return self.config.get(key);
  885. };
  886. ControllerMpd.prototype.setConfigParam = function (data) {
  887.     var self = this;
  888.  
  889.     self.config.set(data.key, data.value);
  890. };
  891.  
  892. ControllerMpd.prototype.listPlaylists = function (uri) {
  893.     var self = this;
  894.  
  895.  
  896.     var defer = libQ.defer();
  897.  
  898.     var response={
  899.         "navigation": {
  900.             "lists": [
  901.                 {
  902.                     "availableListViews": [
  903.                         "list"
  904.                     ],
  905.                     "items": [
  906.  
  907.                     ]
  908.                 }
  909.             ]
  910.         }
  911.     };
  912.     var promise = self.commandRouter.playListManager.listPlaylist();
  913.     promise.then(function (data) {
  914.         for (var i in data) {
  915.             var ithdata = data[i];
  916.             var playlist = {
  917.                 "service": "mpd",
  918.                 "type": 'playlist',
  919.                 "title": ithdata,
  920.                 "icon": 'fa fa-list-ol',
  921.                 "uri": 'playlists/' + ithdata
  922.             };
  923.             response.navigation.lists[0].items.push(playlist);
  924.  
  925.  
  926.             }
  927.  
  928.  
  929.         defer.resolve(response);
  930.     });
  931.  
  932.  
  933.     return defer.promise;
  934. };
  935.  
  936. ControllerMpd.prototype.browsePlaylist = function (uri) {
  937.     var self = this;
  938.  
  939.     var defer = libQ.defer();
  940.  
  941.     var response={
  942.         "navigation": {
  943.             "lists": [
  944.                 {
  945.                     "availableListViews": [
  946.                         "list"
  947.                     ],
  948.                     "items": [
  949.  
  950.                     ]
  951.                 }
  952.             ],
  953.             "prev": {
  954.                 "uri": "playlists"
  955.             }
  956.         }
  957.     };
  958.  
  959.     var name = uri.split('/')[1];
  960.  
  961.     var promise = self.commandRouter.playListManager.getPlaylistContent(name);
  962.     promise.then(function (data) {
  963.  
  964.         var n = data.length;
  965.         for (var i = 0; i < n; i++) {
  966.             var ithdata = data[i];
  967.             var song = {
  968.                 service: ithdata.service,
  969.                 type: 'song',
  970.                 title: ithdata.title,
  971.                 artist: ithdata.artist,
  972.                 album: ithdata.album,
  973.                 albumart: ithdata.albumart,
  974.                 uri: ithdata.uri
  975.             };
  976.             response.navigation.lists[0].items.push(song);
  977.         }
  978.  
  979.         defer.resolve(response);
  980.     });
  981.  
  982.     return defer.promise;
  983. };
  984.  
  985. ControllerMpd.prototype.lsInfo = function (uri) {
  986.     var self = this;
  987.  
  988.     var defer = libQ.defer();
  989.  
  990.     var sections = uri.split('/');
  991.     var prev = '';
  992.     var folderToList = '';
  993.     var command = 'lsinfo';
  994.  
  995.     if (sections.length > 1) {
  996.  
  997.         prev = sections.slice(0, sections.length - 1).join('/');
  998.  
  999.         folderToList = sections.slice(1).join('/');
  1000.  
  1001.         command += ' "' + folderToList + '"';
  1002.  
  1003.     }
  1004.  
  1005.     var cmd = libMpd.cmd;
  1006.  
  1007.     self.mpdReady.then(function () {
  1008.         self.clientMpd.sendCommand(cmd(command, []), function (err, msg) {
  1009.             var list = [];
  1010.             if (msg) {
  1011.                 var s0 = sections[0] + '/';
  1012.                 var path;
  1013.                 var name;
  1014.                 var lines = msg.split('\n');
  1015.                 for (var i = 0; i < lines.length; i++) {
  1016.                     var line = lines[i];
  1017.  
  1018.                     //self.logger.info("LINE "+line);
  1019.                     if (line.indexOf('directory:') === 0) {
  1020.                         path = line.slice(11);
  1021.                         name = path.split('/').pop();
  1022.                         list.push({
  1023.                             type: 'folder',
  1024.                             title: name,
  1025.                                                         service:'mpd',
  1026.                             icon: 'fa fa-folder-open-o',
  1027.                             uri: s0 + path
  1028.                         });
  1029.                     }
  1030.                     else if (line.indexOf('playlist:') === 0) {
  1031.                         path = line.slice(10);
  1032.                         name = path.split('/').pop();
  1033.                         if (path.endsWith('.cue')) {
  1034.                             try {
  1035.                                 var cuesheet = parser.parse('/mnt/' + path);
  1036.  
  1037.                                 list.push({
  1038.                                     service: 'mpd',
  1039.                                     type: 'song',
  1040.                                     title: name,
  1041.                                     icon: 'fa fa-list-ol',
  1042.                                     uri: s0 + path
  1043.                                 });
  1044.                                 var tracks = cuesheet.files[0].tracks;
  1045.                                 for (var j in tracks) {
  1046.  
  1047.                                     list.push({
  1048.                                         service: 'mpd',
  1049.                                         type: 'cuesong',
  1050.                                         title: tracks[j].title,
  1051.                                         artist: tracks[j].performer,
  1052.                                         album: path.substring(path.lastIndexOf("/") + 1),
  1053.                                         number: tracks[j].number - 1,
  1054.                                         icon: 'fa fa-music',
  1055.                                         uri: s0 + path
  1056.                                     });
  1057.                                 }
  1058.                             } catch (err) {
  1059.                                 self.logger.info('Cue Parser - Cannot parse ' + path);
  1060.                             }
  1061.                         } else {
  1062.                             list.push({
  1063.                                 service: 'mpd',
  1064.                                 type: 'song',
  1065.                                 title: name,
  1066.                                 icon: 'fa fa-list-ol',
  1067.                                 uri: s0 + path
  1068.                             });
  1069.                         }
  1070.                     }
  1071.                     else if (line.indexOf('file:') === 0) {
  1072.                         var path = line.slice(6);
  1073.                         var name = path.split('/').pop();
  1074.  
  1075.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1076.                         var album = self.searchFor(lines, i + 1, 'Album:');
  1077.                         var title = self.searchFor(lines, i + 1, 'Title:');
  1078.  
  1079.                         if (title) {
  1080.                             title = title;
  1081.                         } else {
  1082.                             title = name;
  1083.                         }
  1084.                         list.push({
  1085.                             service: 'mpd',
  1086.                             type: 'song',
  1087.                             title: title,
  1088.                             artist: artist,
  1089.                             album: album,
  1090.                             icon: 'fa fa-music',
  1091.                             uri: s0 + path
  1092.                         });
  1093.                     }
  1094.  
  1095.                 }
  1096.             }
  1097.             else self.logger.info(err);
  1098.  
  1099.             defer.resolve({
  1100.                 navigation: {
  1101.                     prev: {
  1102.                         uri: prev
  1103.                     },
  1104.                     lists: [{availableListViews:['list'],items:list}]
  1105.                 }
  1106.             });
  1107.         });
  1108.     });
  1109.     return defer.promise;
  1110. };
  1111.  
  1112. ControllerMpd.prototype.search = function (query) {
  1113.     var self = this;
  1114.  
  1115.     var defer = libQ.defer();
  1116.     var commandArtist = 'search artist '+' "' + query.value + '"';
  1117.     var commandAlbum = 'search album '+' "' + query.value + '"';
  1118.     var commandSong = 'search title '+' "' + query.value + '"';
  1119.     var deferArray=[];
  1120.     deferArray.push(libQ.defer());
  1121.     deferArray.push(libQ.defer());
  1122.     deferArray.push(libQ.defer());
  1123.  
  1124.     var cmd = libMpd.cmd;
  1125.  
  1126.     self.mpdReady.then(function () {
  1127.         self.clientMpd.sendCommand(cmd(commandArtist, []), function (err, msg) {
  1128.             var subList=[];
  1129.  
  1130.             if (msg) {
  1131.  
  1132.                 var lines = msg.split('\n');
  1133.                 for (var i = 0; i < lines.length; i++) {
  1134.                     var line = lines[i];
  1135.  
  1136.                     if (line.startsWith('file:')) {
  1137.                         var path = line.slice(5).trimLeft();
  1138.                         var name = path.split('/');
  1139.                         var count = name.length;
  1140.  
  1141.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1142.  
  1143.                         deferArray[0].resolve([{
  1144.                             service: 'mpd',
  1145.                             type: 'folder',
  1146.                             title: artist,
  1147.                             uri: 'artists://' + nodetools.urlEncode(artist),
  1148.                             albumart: self.getAlbumArt({artist: artist},
  1149.                                 self.getParentFolder('/mnt/' + path),
  1150.                                 'fa-tags')
  1151.  
  1152.                     }]);
  1153.  
  1154.                         return;
  1155.                     }
  1156.  
  1157.                 }
  1158.  
  1159.  
  1160.             }
  1161.             else if(err)  deferArray[0].reject(new Error('Artist:' +err));
  1162.             else deferArray[0].resolve();
  1163.         });
  1164.     });
  1165.  
  1166.     self.mpdReady.then(function () {
  1167.         self.clientMpd.sendCommand(cmd(commandAlbum, []), function (err, msg) {
  1168.             var subList=[];
  1169.  
  1170.             if (msg) {
  1171.  
  1172.                 var lines = msg.split('\n');
  1173.                 for (var i = 0; i < lines.length; i++) {
  1174.                     var line = lines[i];
  1175.  
  1176.                     if (line.startsWith('file:')) {
  1177.                         var path = line.slice(5).trimLeft();
  1178.                         var name = path.split('/');
  1179.                         var count = name.length;
  1180.  
  1181.                         var album = self.searchFor(lines, i + 1, 'Album:');
  1182.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1183.  
  1184.                         deferArray[1].resolve([{
  1185.                             service: 'mpd',
  1186.                             type: 'folder',
  1187.                             title: album,
  1188.                             artist: artist,
  1189.                             album:'',
  1190.                             uri: 'albums://' + nodetools.urlEncode(album),
  1191.                             albumart: self.getAlbumArt({artist: artist, album: album},
  1192.                                 self.getParentFolder('/mnt/' + path),'fa-tags')
  1193.  
  1194.                     }]);
  1195.  
  1196.                         return;
  1197.                     }
  1198.  
  1199.                 }
  1200.             }
  1201.             else if(err)  deferArray[1].reject(new Error('Album:' +err));
  1202.             else deferArray[1].resolve();
  1203.         });
  1204.     });
  1205.  
  1206.     self.mpdReady.then(function () {
  1207.         self.clientMpd.sendCommand(cmd(commandSong, []), function (err, msg) {
  1208.             var subList=[];
  1209.  
  1210.             if (msg) {
  1211.  
  1212.                 var lines = msg.split('\n');
  1213.                 for (var i = 0; i < lines.length; i++) {
  1214.                     var line = lines[i];
  1215.  
  1216.                     if (line.startsWith('file:')) {
  1217.                         var path = line.slice(5).trimLeft();
  1218.                         var name = path.split('/');
  1219.                         var count = name.length;
  1220.  
  1221.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1222.                         var album = self.searchFor(lines, i + 1, 'Album:');
  1223.                         var title = self.searchFor(lines, i + 1, 'Title:');
  1224.  
  1225.                         if (title == undefined) {
  1226.                             title = name[count - 1];
  1227.                         }
  1228.                         subList.push({
  1229.                             service: 'mpd',
  1230.                             type: 'song',
  1231.                             title: title,
  1232.                             artist: artist,
  1233.                             album: album,
  1234.                             uri: 'music-library/' + path,
  1235.                             albumart : self.getAlbumArt({artist: artist, album: album},
  1236.                                 self.getParentFolder('/mnt/' + path),'fa-tags')
  1237.  
  1238.                     });
  1239.                     }
  1240.  
  1241.                 }
  1242.  
  1243.                 deferArray[2].resolve(subList);
  1244.             }
  1245.             else if(err)  deferArray[2].reject(new Error('Song:' +err));
  1246.             else deferArray[2].resolve();
  1247.         });
  1248.     });
  1249.  
  1250.     libQ.all(deferArray).then(function(values){
  1251.         var list = [];
  1252.  
  1253.         if(values[0])
  1254.         {
  1255.             list=[
  1256.                 {
  1257.                     "title": self.commandRouter.getI18nString('COMMON.SEARCH_ARTIST_SECTION'),
  1258.                     "availableListViews": [
  1259.                         "list",
  1260.                         "grid"
  1261.                     ],
  1262.                     "items": []
  1263.                 }];
  1264.  
  1265.                 list[0].items=list[0].items.concat(values[0]);
  1266.         }
  1267.  
  1268.         if(values[1])
  1269.         {
  1270.             var albList=
  1271.                 {
  1272.                     "title": self.commandRouter.getI18nString('COMMON.SEARCH_ALBUM_SECTION'),
  1273.                     "availableListViews": [
  1274.                         "list",
  1275.                         "grid"
  1276.                     ],
  1277.                     "items": []
  1278.                 };
  1279.             albList.items=values[1];
  1280.  
  1281.  
  1282.             list.push(albList);
  1283.         }
  1284.  
  1285.         if(values[2])
  1286.         {
  1287.             var songList=
  1288.                 {
  1289.                     "title": self.commandRouter.getI18nString('COMMON.SEARCH_SONG_SECTION'),
  1290.                     "availableListViews": [
  1291.                         "list"
  1292.                     ],
  1293.                     "items": []
  1294.                 };
  1295.             songList.items=values[2];
  1296.  
  1297.  
  1298.             list.push(songList);
  1299.         }
  1300.  
  1301.         list=list.filter(function(v){return !!(v)==true;})
  1302.  
  1303.         defer.resolve(list);
  1304.     }).fail(function(err){
  1305.         self.commandRouter.logger.info("PARSING RESPONSE ERROR "+err);
  1306.  
  1307.         defer.resolve();
  1308.     })
  1309.     return defer.promise;
  1310. };
  1311.  
  1312. ControllerMpd.prototype.searchFor = function (lines, startFrom, beginning) {
  1313.  
  1314.     var count = lines.length;
  1315.     var i = startFrom;
  1316.  
  1317.     while (i < count) {
  1318.         var line = lines[i];
  1319.  
  1320.         if(line!==undefined)
  1321.         {
  1322.             if (line.indexOf(beginning) === 0)
  1323.                 return line.slice(beginning.length).trimLeft();
  1324.             else if (line.indexOf('file:') === 0)
  1325.                 return '';
  1326.             else if (line.indexOf('directory:') === 0)
  1327.                 return '';
  1328.         }
  1329.  
  1330.         i++;
  1331.     }
  1332. };
  1333.  
  1334. ControllerMpd.prototype.updateQueue = function () {
  1335.     var self = this;
  1336.  
  1337.     var defer = libQ.defer();
  1338.  
  1339.     var prev = '';
  1340.     var folderToList = '';
  1341.     var command = 'playlistinfo';
  1342.     var list = [];
  1343.  
  1344.     var cmd = libMpd.cmd;
  1345.     self.mpdReady.then(function () {
  1346.         self.clientMpd.sendCommand(cmd(command, []), function (err, msg) {
  1347.             if (msg) {
  1348.                 var lines = msg.split('\n');
  1349.  
  1350.                 //self.commandRouter.volumioClearQueue();
  1351.  
  1352.                 var queue = [];
  1353.                 for (var i = 0; i < lines.length; i++) {
  1354.                     var line = lines[i];
  1355.                     if (line.indexOf('file:') === 0) {
  1356.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1357.                         var album = self.searchFor(lines, i + 1, 'Album:');
  1358.                         var rawtitle = self.searchFor(lines, i + 1, 'Title:');
  1359.                         var tracknumber = self.searchFor(lines, i + 1, 'Pos:');
  1360.                         var path = line.slice(5).trimLeft();
  1361.  
  1362.                         if (rawtitle) {
  1363.                             var title = rawtitle;
  1364.                         } else {
  1365.                             var path = line.slice(5).trimLeft();
  1366.                             var name = path.split('/');
  1367.                             var title = name.slice(-1)[0];
  1368.                         }
  1369.  
  1370.                         var queueItem = {
  1371.                             uri: path,
  1372.                             service: 'mpd',
  1373.                             name: title,
  1374.                             artist: artist,
  1375.                             album: album,
  1376.                             type: 'track',
  1377.                             tracknumber: tracknumber,
  1378.                             albumart: self.getAlbumArt({artist: artist, album: album}, path)
  1379.                         };
  1380.                         queue.push(queueItem);
  1381.                     }
  1382.  
  1383.                 }
  1384.                 //self.commandRouter.addQueueItems(queue);
  1385.             }
  1386.             else self.logger.info(err);
  1387.  
  1388.             defer.resolve({
  1389.                 navigation: {
  1390.                     prev: {
  1391.                         uri: prev
  1392.                     },
  1393.                     list: list
  1394.                 }
  1395.             });
  1396.         });
  1397.     });
  1398.  
  1399.  
  1400.     return defer.promise;
  1401. };
  1402.  
  1403.  
  1404. ControllerMpd.prototype.getAlbumArt = function (data, path,icon) {
  1405.  
  1406.     var artist, album;
  1407.  
  1408.     if (data != undefined && data.path != undefined) {
  1409.         path = this.sanitizeUri(data.path);
  1410.     }
  1411.  
  1412.     var web;
  1413.  
  1414.     if (data != undefined && data.artist != undefined) {
  1415.         artist = data.artist;
  1416.         if (data.album != undefined)
  1417.             album = data.album;
  1418.         else album = data.artist;
  1419.  
  1420.         web = '?web=' + nodetools.urlEncode(artist) + '/' + nodetools.urlEncode(album) + '/large'
  1421.     }
  1422.  
  1423.     var url = '/albumart';
  1424.  
  1425.     if (web != undefined)
  1426.         url = url + web;
  1427.  
  1428.     if (web != undefined && path != undefined)
  1429.         url = url + '&';
  1430.     else if (path != undefined)
  1431.         url = url + '?';
  1432.  
  1433.     if (path != undefined)
  1434.         url = url + 'path=' + nodetools.urlEncode(path);
  1435.  
  1436.     if(icon!==undefined)
  1437.     {
  1438.         if(url==='/albumart')
  1439.             url=url+'?icon='+icon;
  1440.         else url=url+'&icon='+icon;
  1441.     }
  1442.  
  1443.  
  1444.  
  1445.     return url;
  1446. };
  1447.  
  1448.  
  1449. ControllerMpd.prototype.reportUpdatedLibrary = function () {
  1450.     var self = this;
  1451.     // TODO PUSH THIS MESSAGE TO ALL CONNECTED CLIENTS
  1452.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::DB Update Finished');
  1453.     //return self.commandRouter.pushToastMessage('Success', 'ASF', ' Added');
  1454. };
  1455.  
  1456. ControllerMpd.prototype.getConfigurationFiles = function () {
  1457.     var self = this;
  1458.  
  1459.     return ['config.json'];
  1460. };
  1461.  
  1462. ControllerMpd.prototype.getAdditionalConf = function (type, controller, data) {
  1463.     var self = this;
  1464.     return self.commandRouter.executeOnPlugin(type, controller, 'getConfigParam', data);
  1465. };
  1466.  
  1467. ControllerMpd.prototype.setAdditionalConf = function (type, controller, data) {
  1468.     var self = this;
  1469.     return self.commandRouter.executeOnPlugin(type, controller, 'setConfigParam', data);
  1470. };
  1471.  
  1472. ControllerMpd.prototype.getMyCollectionStats = function () {
  1473.     var self = this;
  1474.  
  1475.     var defer = libQ.defer();
  1476.  
  1477.     var cmd = libMpd.cmd;
  1478.     self.clientMpd.sendCommand(cmd("count", ["group", "artist"]), function (err, msg) {
  1479.         if (err) defer.resolve({
  1480.             artists: 0,
  1481.             albums: 0,
  1482.             songs: 0,
  1483.             playtime: '00:00:00'
  1484.         });
  1485.         else {
  1486.             var artistsCount = 0;
  1487.             var songsCount = 0;
  1488.             var playtimesCount = 0;
  1489.  
  1490.             var splitted = msg.split('\n');
  1491.             for (var i = 0; i < splitted.length - 1; i = i + 3) {
  1492.                 artistsCount++;
  1493.                 songsCount = songsCount + parseInt(splitted[i + 1].substring(7));
  1494.                 playtimesCount = playtimesCount + parseInt(splitted[i + 2].substring(10));
  1495.             }
  1496.  
  1497.             var convertedSecs = convert(playtimesCount);
  1498.  
  1499.  
  1500.             self.clientMpd.sendCommand(cmd("count", ["group", "album"]), function (err, msg) {
  1501.                 if (!err) {
  1502.                     var splittedAlbum = msg.split('\n').length;
  1503.                     var response = {
  1504.                         artists: artistsCount,
  1505.                         albums: (splittedAlbum - 1) / 3,
  1506.                         songs: songsCount,
  1507.                         playtime: convertedSecs.hours + ':' + ('0' + convertedSecs.minutes).slice(-2) + ':' + ('0' + convertedSecs.seconds).slice(-2)
  1508.                     };
  1509.                 }
  1510.  
  1511.                 defer.resolve(response);
  1512.  
  1513.             });
  1514.  
  1515.         }
  1516.  
  1517.  
  1518.     });
  1519.     return defer.promise;
  1520.  
  1521. };
  1522.  
  1523.  
  1524. ControllerMpd.prototype.rescanDb = function () {
  1525.     var self = this;
  1526.  
  1527.     return self.sendMpdCommand('rescan', []);
  1528. };
  1529.  
  1530. ControllerMpd.prototype.updateDb = function () {
  1531.     var self = this;
  1532.  
  1533.     return self.sendMpdCommand('update', []);
  1534. };
  1535.  
  1536.  
  1537. ControllerMpd.prototype.getGroupVolume = function () {
  1538.     var self = this;
  1539.     return self.sendMpdCommand('status', [])
  1540.         .then(function (objState) {
  1541.             var state = self.parseState(objState);
  1542.             if (state.volume != undefined) {
  1543.                 state.volume = groupvolume;
  1544.                 return libQ.resolve(groupvolume);
  1545.             }
  1546.         });
  1547. };
  1548.  
  1549. ControllerMpd.prototype.setGroupVolume = function (data) {
  1550.     var self = this;
  1551.     return self.sendMpdCommand('setvol', [data]);
  1552. };
  1553.  
  1554. ControllerMpd.prototype.syncGroupVolume = function (data) {
  1555.     var self = this;
  1556.  
  1557. };
  1558.  
  1559.  
  1560. // --------------------------------- music services interface ---------------------------------------
  1561.  
  1562. ControllerMpd.prototype.explodeUri = function(uri) {
  1563.     var self = this;
  1564.  
  1565.     var defer=libQ.defer();
  1566.  
  1567.     var items = [];
  1568.     var cmd = libMpd.cmd;
  1569.  
  1570.     if(uri.startsWith('cue://'))
  1571.     {
  1572.         var splitted=uri.split('@');
  1573.         var index=splitted[1];
  1574.         var path='/mnt/' + splitted[0].substring(6);
  1575.  
  1576.             var cuesheet = parser.parse(path);
  1577.  
  1578.             var tracks = cuesheet.files[0].tracks;
  1579.  
  1580.             defer.resolve({uri:uri,service:'mpd',name: tracks[index].title,
  1581.                 artist: tracks[index].performer,
  1582.                 album: path.substring(path.lastIndexOf("/") + 1),
  1583.                 number: tracks[index].number - 1,
  1584.                 albumart:'/albumart'
  1585.             });
  1586.     }
  1587.     else if(uri.startsWith('search://'))
  1588.     {
  1589.         //exploding search
  1590.         var splitted=uri.split('/');
  1591.  
  1592.         var argument=splitted[2];
  1593.         var value=splitted[3];
  1594.  
  1595.         if(argument==='artist')
  1596.         {
  1597.             var commandArtist = 'search artist '+' "' + value + '"';
  1598.  
  1599.             self.mpdReady.then(function () {
  1600.                 self.clientMpd.sendCommand(cmd(commandArtist, []), function (err, msg) {
  1601.                     var subList=[];
  1602.  
  1603.                     if (msg) {
  1604.                         var lines = msg.split('\n');
  1605.                         for (var i = 0; i < lines.length; i++) {
  1606.                             var line = lines[i];
  1607.  
  1608.                             if (line.startsWith('file:')) {
  1609.                                 var path = line.slice(5).trimLeft();
  1610.                                 var name = path.split('/');
  1611.                                 var count = name.length;
  1612.  
  1613.                                 var artist = self.searchFor(lines, i + 1, 'Artist:');
  1614.                                 var album = self.searchFor(lines, i + 1, 'Album:');
  1615.                                 var title = self.searchFor(lines, i + 1, 'Title:');
  1616.                                 var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  1617.  
  1618.                                 if (title) {
  1619.                                     title = title;
  1620.                                 } else {
  1621.                                     title = name;
  1622.                                 }
  1623.  
  1624.                                 items.push({
  1625.                                     uri: 'music-library/'+path,
  1626.                                     service: 'mpd',
  1627.                                     name: title,
  1628.                                     artist: artist,
  1629.                                     album: album,
  1630.                                     type: 'track',
  1631.                                     tracknumber: 0,
  1632.                                     albumart: self.getAlbumArt({artist:artist,album: album},uri),
  1633.                                     duration: time,
  1634.                                     trackType: 'mp3'
  1635.                                 });
  1636.                             }
  1637.  
  1638.                         }
  1639.  
  1640.                         defer.resolve(items);
  1641.                     }
  1642.                     else if(err)  defer.reject(new Error('Artist:' +err));
  1643.                     else defer.resolve(items);
  1644.                 });
  1645.             });
  1646.         }
  1647.         else if(argument==='album')
  1648.         {
  1649.             var commandAlbum = 'search album '+' "' + value + '"';
  1650.  
  1651.             self.mpdReady.then(function () {
  1652.                 self.clientMpd.sendCommand(cmd(commandAlbum, []), function (err, msg) {
  1653.                     var subList=[];
  1654.  
  1655.                     if (msg) {
  1656.  
  1657.                         var lines = msg.split('\n');
  1658.                         for (var i = 0; i < lines.length; i++) {
  1659.                             var line = lines[i];
  1660.  
  1661.                             if (line.startsWith('file:')) {
  1662.                                 var path = line.slice(5).trimLeft();
  1663.                                 var name = path.split('/');
  1664.                                 var count = name.length;
  1665.  
  1666.                                 var artist = self.searchFor(lines, i + 1, 'Artist:');
  1667.                                 var album = self.searchFor(lines, i + 1, 'Album:');
  1668.                                 var title = self.searchFor(lines, i + 1, 'Title:');
  1669.                                 var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  1670.  
  1671.                                 if (title) {
  1672.                                     title = title;
  1673.                                 } else {
  1674.                                     title = name;
  1675.                                 }
  1676.  
  1677.                                 items.push({
  1678.                                     uri: 'music-library/' + path,
  1679.                                     service: 'mpd',
  1680.                                     name: title,
  1681.                                     artist: artist,
  1682.                                     album: album,
  1683.                                     type: 'track',
  1684.                                     tracknumber: 0,
  1685.                                     albumart: self.getAlbumArt({artist: artist, album: album}, uri),
  1686.                                     duration: time,
  1687.                                     trackType: 'mp3'
  1688.                                 });
  1689.                             }
  1690.                         }
  1691.                         defer.resolve(items);
  1692.                     }
  1693.                     else if(err)  defer.reject(new Error('Artist:' +err));
  1694.                     else defer.resolve(items);
  1695.                 });
  1696.             });
  1697.         }
  1698.         else defer.reject(new Error());
  1699.     }
  1700.     else if(uri.startsWith('albums://')) {
  1701.         //exploding search
  1702.         var splitted = uri.split('/');
  1703.  
  1704.         var albumName = nodetools.urlDecode(splitted[2]);
  1705.  
  1706.         var cmd = libMpd.cmd;
  1707.         self.clientMpd.sendCommand(cmd("find album \""+albumName+"\"", []), function (err, msg) {
  1708.  
  1709.             var list = [];
  1710.             if (msg) {
  1711.                 var path;
  1712.                 var name;
  1713.                 var lines = msg.split('\n');
  1714.                 for (var i = 0; i < lines.length; i++) {
  1715.                     var line = lines[i];
  1716.                     if (line.indexOf('file:') === 0) {
  1717.                         var path = line.slice(6);
  1718.                         var name = path.split('/').pop();
  1719.  
  1720.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1721.                         var album = self.searchFor(lines, i + 1, 'Album:');
  1722.                         var title = self.searchFor(lines, i + 1, 'Title:');
  1723.                         var albumart=self.getAlbumArt({artist: artist, album: album,icon:'fa-dot-circle'}, self.getParentFolder('/mnt/'+path));
  1724.                         var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  1725.  
  1726.                         if (title) {
  1727.                             title = title;
  1728.                         } else {
  1729.                             title = name;
  1730.                         }
  1731.                         list.push({
  1732.                             uri: 'music-library/'+path,
  1733.                             service: 'mpd',
  1734.                             name: title,
  1735.                             artist: artist,
  1736.                             album: album,
  1737.                             type: 'track',
  1738.                             tracknumber: 0,
  1739.                             albumart: albumart,
  1740.                             duration: time,
  1741.                             trackType: path.split('.').pop()
  1742.                         });
  1743.  
  1744.  
  1745.                     }
  1746.  
  1747.                 }
  1748.             }
  1749.             else self.logger.info(err);
  1750.  
  1751.             defer.resolve(list);
  1752.         });
  1753.     }
  1754.     else if(uri.startsWith('artists://')) {
  1755.         /*
  1756.          artists://AC%2FDC/Rock%20or%20Bust in service mpd
  1757.          */
  1758.         var splitted = uri.split('/');
  1759.  
  1760.         if(splitted.length===4)
  1761.             return this.explodeUri('albums://'+splitted[3]);
  1762.  
  1763.         var artist = nodetools.urlDecode(splitted[2]);
  1764.  
  1765.         var cmd = libMpd.cmd;
  1766.  
  1767.         self.clientMpd.sendCommand(cmd("find artist \""+artist+"\"", []), function (err, msg) {
  1768.             if(msg=='')
  1769.             {
  1770.                 self.clientMpd.sendCommand(cmd("find albumartist \""+artist+"\"", []), function (err, msg) {
  1771.                     self.exploderArtist(err,msg,defer);
  1772.                 });
  1773.             }
  1774.             else self.exploderArtist(err,msg,defer);
  1775.         });
  1776.  
  1777.     }
  1778.     else if(uri.startsWith('genres://')) {
  1779.         //exploding search
  1780.         var splitted = uri.split('/');
  1781.  
  1782.         var genreName = nodetools.urlDecode(splitted[2]);
  1783.  
  1784.         var cmd = libMpd.cmd;
  1785.  
  1786.         self.clientMpd.sendCommand(cmd("find genre \"" + genreName + "\"", []), function (err, msg) {
  1787.             var list = [];
  1788.             var albums=[],albumarts=[];
  1789.             if (msg) {
  1790.                 var path;
  1791.                 var name;
  1792.                 var lines = msg.split('\n');
  1793.                 for (var i = 0; i < lines.length; i++) {
  1794.                     var line = lines[i];
  1795.                     if (line.indexOf('file:') === 0) {
  1796.                         var path = line.slice(6);
  1797.                         var name = path.split('/').pop();
  1798.  
  1799.                         var artist = self.searchFor(lines, i + 1, 'Artist:');
  1800.                         var album = self.searchFor(lines, i + 1, 'Album:');
  1801.                         var title = self.searchFor(lines, i + 1, 'Title:');
  1802.                         var albumart=self.getAlbumArt({artist: artist, album: album}, self.getParentFolder('/mnt/'+path));
  1803.                         var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  1804.  
  1805.                         if (title) {
  1806.                             title = title;
  1807.                         } else {
  1808.                             title = name;
  1809.                         }
  1810.  
  1811.                         if(title!=='')
  1812.                         {
  1813.                             list.push({
  1814.                                 uri: 'music-library/'+path,
  1815.                                 service: 'mpd',
  1816.                                 name: title,
  1817.                                 artist: artist,
  1818.                                 album: album,
  1819.                                 type: 'track',
  1820.                                 tracknumber: 0,
  1821.                                 albumart: albumart,
  1822.                                 duration: time,
  1823.                                 trackType: path.split('.').pop()
  1824.                             });
  1825.                         }
  1826.  
  1827.                     }
  1828.  
  1829.                 }
  1830.  
  1831.  
  1832.                 defer.resolve(list);
  1833.  
  1834.  
  1835.             }
  1836.             else
  1837.             {
  1838.                 self.logger.info(err);
  1839.                 defer.reject(new Error());
  1840.             }
  1841.         });
  1842.  
  1843.     }
  1844.     else {
  1845.         if(uri.endsWith('.cue'))
  1846.         {
  1847.             try {
  1848.                 var uriPath='/mnt/'+self.sanitizeUri(uri);
  1849.  
  1850.  
  1851.                 var cuesheet = parser.parse(uriPath);
  1852.  
  1853.                 var tracks = cuesheet.files[0].tracks;
  1854.                 var list=[];
  1855.                 for (var j in tracks) {
  1856.  
  1857.                     list.push({
  1858.                         service: 'mpd',
  1859.                         name: tracks[j].title,
  1860.                         artist: tracks[j].performer,
  1861.                         album: uriPath.substring(uriPath.lastIndexOf("/") + 1),
  1862.                         number: tracks[j].number - 1,
  1863.                         uri: 'cue://'+uri+'@'+j,
  1864.                         albumart:'/albumart'
  1865.                     });
  1866.                 }
  1867.  
  1868.                 defer.resolve(list);
  1869.             } catch (err) {
  1870.                 self.logger.info(err);
  1871.                 self.logger.info('Cue Parser - Cannot parse ' + uriPath);
  1872.             }
  1873.  
  1874.  
  1875.         }
  1876.         else
  1877.         {
  1878.             var uriPath='/mnt/'+self.sanitizeUri(uri);
  1879.             self.commandRouter.logger.info('----------------------------'+uriPath);
  1880.             var uris=self.scanFolder(uriPath);
  1881.             var response=[];
  1882.  
  1883.             libQ.all(uris)
  1884.                 .then(function(result)
  1885.                 {
  1886.                     for(var j in result)
  1887.                     {
  1888.  
  1889.                         self.commandRouter.logger.info("----->>>>> "+JSON.stringify(result[j]));
  1890.  
  1891.                         if(result!==undefined && result[j].uri!==undefined)
  1892.                         {
  1893.                             response.push({
  1894.                                 uri: self.fromPathToUri(result[j].uri),
  1895.                                 service: 'mpd',
  1896.                                 name: result[j].name,
  1897.                                 artist: result[j].artist,
  1898.                                 album: result[j].album,
  1899.                                 type: 'track',
  1900.                                 tracknumber: result[j].tracknumber,
  1901.                                 albumart: result[j].albumart,
  1902.                                 duration: result[j].duration,
  1903.                                 samplerate: result[j].samplerate,
  1904.                                 bitdepth: result[j].bitdepth,
  1905.                                 trackType: result[j].trackType
  1906.                             });
  1907.                         }
  1908.  
  1909.                     }
  1910.  
  1911.                     defer.resolve(response);
  1912.                 }).fail(function(err)
  1913.             {
  1914.                 self.commandRouter.logger.info("explodeURI: ERROR "+err);
  1915.                 defer.resolve([]);
  1916.             });
  1917.         }
  1918.  
  1919.     }
  1920.  
  1921.     return defer.promise;
  1922. };
  1923.  
  1924. ControllerMpd.prototype.exploderArtist=function(err,msg,defer)
  1925. {
  1926.     var self=this;
  1927.    
  1928.     var list = [];
  1929.     var albums=[],albumarts=[];
  1930.     if (msg) {
  1931.         var path;
  1932.         var name;
  1933.         var lines = msg.split('\n');
  1934.         for (var i = 0; i < lines.length; i++) {
  1935.             var line = lines[i];
  1936.             if (line.indexOf('file:') === 0) {
  1937.                 var path = line.slice(6);
  1938.                 var name = path.split('/').pop();
  1939.  
  1940.                 var artist = self.searchFor(lines, i + 1, 'Artist:');
  1941.                 var album = self.searchFor(lines, i + 1, 'Album:');
  1942.                 var title = self.searchFor(lines, i + 1, 'Title:');
  1943.                 var albumart=self.getAlbumArt({artist: artist, album: album}, self.getParentFolder('/mnt/'+path));
  1944.                 var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  1945.  
  1946.                 if (title) {
  1947.                     title = title;
  1948.                 } else {
  1949.                     title = name;
  1950.                 }
  1951.                 list.push({
  1952.                     uri: 'music-library/'+path,
  1953.                     service: 'mpd',
  1954.                     name: title,
  1955.                     artist: artist,
  1956.                     album: album,
  1957.                     type: 'track',
  1958.                     tracknumber: 0,
  1959.                     albumart: albumart,
  1960.                     duration: time,
  1961.                     trackType: path.split('.').pop()
  1962.                 });
  1963.             }
  1964.  
  1965.         }
  1966.  
  1967.  
  1968.         defer.resolve(list);
  1969.  
  1970.  
  1971.     }
  1972.     else
  1973.     {
  1974.         self.logger.info(err);
  1975.         defer.reject(new Error());
  1976.     }
  1977. }
  1978.  
  1979. ControllerMpd.prototype.fromUriToPath = function (uri) {
  1980.     var sections = uri.split('/');
  1981.     var prev = '';
  1982.  
  1983.     if (sections.length > 1) {
  1984.  
  1985.         prev = sections.slice(1, sections.length).join('/');
  1986.     }
  1987.     return prev;
  1988.  
  1989. };
  1990.  
  1991. ControllerMpd.prototype.fromPathToUri = function (uri) {
  1992.     var sections = uri.split('/');
  1993.     var prev = '';
  1994.  
  1995.     if (sections.length > 1) {
  1996.  
  1997.         prev = sections.slice(1, sections.length).join('/');
  1998.     }
  1999.     return prev;
  2000.  
  2001. };
  2002.  
  2003.  
  2004. ControllerMpd.prototype.scanFolder=function(uri)
  2005. {
  2006.     var self=this;
  2007.     var uris=[];
  2008.  
  2009.     var stat=libFsExtra.statSync(uri);
  2010.  
  2011.     if(stat.isDirectory())
  2012.     {
  2013.         var files=libFsExtra.readdirSync(uri);
  2014.  
  2015.         for(var i in files)
  2016.             uris=uris.concat(self.scanFolder(uri+'/'+files[i]));
  2017.     }
  2018.     else {
  2019.             var defer=libQ.defer();
  2020. /*
  2021.             var parser = mm(libFsExtra.createReadStream(uri), function (err, metadata) {
  2022.                 if (err) defer.resolve({});
  2023.                 else {
  2024.                     defer.resolve({
  2025.                         uri: 'music-library/'+self.fromPathToUri(uri),
  2026.                         service: 'mpd',
  2027.                         name: metadata.title,
  2028.                         artist: metadata.artist[0],
  2029.                         album: metadata.album,
  2030.                         type: 'track',
  2031.                         tracknumber: metadata.track.no,
  2032.                         albumart: self.getAlbumArt(
  2033.                             {artist:metadata.artist,
  2034.                              album: metadata.album},uri),
  2035.                         duration: metadata.duration
  2036.                     });
  2037.                 }
  2038.  
  2039.             });*/
  2040.  
  2041.             var sections = uri.split('/');
  2042.             var folderToList = '';
  2043.             var command = 'lsinfo';
  2044.  
  2045.             if (sections.length > 1) {
  2046.                 folderToList = sections.slice(2).join('/');
  2047.  
  2048.                 command += ' "' + folderToList + '"';
  2049.  
  2050.             }
  2051.  
  2052.             var cmd = libMpd.cmd;
  2053.  
  2054.             self.mpdReady.then(function () {
  2055.                 self.clientMpd.sendCommand(cmd(command, []), function (err, msg) {
  2056.                     var list = [];
  2057.                     if (msg) {
  2058.  
  2059.  
  2060.                         var s0 = sections[0] + '/';
  2061.                         var path;
  2062.                         var name;
  2063.                         var lines = msg.split('\n');
  2064.                         var isSolved=false;
  2065.  
  2066.                         for (var i = 0; i < lines.length; i++) {
  2067.                             var line = lines[i];
  2068.  
  2069.                             if (line.indexOf('file:') === 0) {
  2070.                                 var path = line.slice(6);
  2071.                                 var name = path.split('/').pop();
  2072.  
  2073.                                 var artist = self.searchFor(lines, i + 1, 'Artist:');
  2074.                                 var album = self.searchFor(lines, i + 1, 'Album:');
  2075.                                 var title = self.searchFor(lines, i + 1, 'Title:');
  2076.                                 var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  2077.  
  2078.                                 if (title) {
  2079.                                     title = title;
  2080.                                 } else {
  2081.                                     title = name;
  2082.                                 }
  2083.                                 self.commandRouter.logger.info("ALBUMART "+self.getAlbumArt({artist:artist,album: album},uri));
  2084.                                 self.commandRouter.logger.info("URI "+uri);
  2085.  
  2086.                                 defer.resolve({
  2087.                                     uri: 'music-library/'+self.fromPathToUri(uri),
  2088.                                     service: 'mpd',
  2089.                                     name: title,
  2090.                                     artist: artist,
  2091.                                     album: album,
  2092.                                     type: 'track',
  2093.                                     tracknumber: 0,
  2094.                                     albumart: self.getAlbumArt({artist:artist,album: album},self.getAlbumArtPathFromUri(uri)),
  2095.                                     duration: time,
  2096.                                     trackType: uri.split('.').pop()
  2097.                             });
  2098.  
  2099.                                 isSolved=true;
  2100.                             }
  2101.  
  2102.                         }
  2103.  
  2104.                         if(isSolved===false)
  2105.                             defer.resolve({});
  2106.  
  2107.                     }
  2108.                     else defer.resolve({});
  2109.                     });
  2110.                 });
  2111.  
  2112.             return defer.promise;
  2113.  
  2114.     }
  2115.  
  2116.     return uris;
  2117. }
  2118.  
  2119.  
  2120.  
  2121.  
  2122. //----------------------- new play system ----------------------------
  2123. ControllerMpd.prototype.clearAddPlayTrack = function (track) {
  2124.     var self = this;
  2125.  
  2126.     var sections = track.uri.split('/');
  2127.     var prev = '';
  2128.  
  2129.     if(track.uri.startsWith('cue://'))
  2130.     {
  2131.         var uri1=track.uri.substring(6);
  2132.         var splitted=uri1.split('@');
  2133.  
  2134.         var index=splitted[1];
  2135.         var uri=self.sanitizeUri(splitted[0]);
  2136.  
  2137.         self.logger.info(uri);
  2138.         self.logger.info(index);
  2139.  
  2140.         return self.sendMpdCommand('stop',[])
  2141.             .then(function()
  2142.             {
  2143.                 return self.sendMpdCommand('clear',[]);
  2144.             })
  2145.             .then(function()
  2146.             {
  2147.                 return self.sendMpdCommand('load "'+uri+'"',[]);
  2148.             })
  2149.             .then(function()
  2150.             {
  2151.                 return self.sendMpdCommand('play',[index]);
  2152.             });
  2153.     }
  2154.     else{
  2155.         var uri=self.sanitizeUri(track.uri);
  2156.  
  2157.         self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::clearAddPlayTracks '+uri);
  2158.  
  2159.         // Clear the queue, add the first track, and start playback
  2160.         var defer = libQ.defer();
  2161.         var cmd = libMpd.cmd;
  2162.  
  2163.  
  2164.         return self.sendMpdCommand('stop',[])
  2165.             .then(function()
  2166.             {
  2167.                 return self.sendMpdCommand('clear',[]);
  2168.             })
  2169.             .then(function()
  2170.             {
  2171.                 return self.sendMpdCommand('add "'+uri+'"',[]);
  2172.             })
  2173.             .then(function()
  2174.             {
  2175.                 return self.sendMpdCommand('play',[]);
  2176.             });
  2177.     }
  2178.  
  2179. };
  2180.  
  2181.  
  2182. ControllerMpd.prototype.seek = function(position) {
  2183.     var self=this;
  2184.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::seek');
  2185.  
  2186.     var defer = libQ.defer();
  2187.     var command = 'seek ';
  2188.     var cmd = libMpd.cmd;
  2189.  
  2190.  
  2191.         self.clientMpd.sendCommand(cmd(command, ['0',position/1000]), function (err, msg) {
  2192.             if (msg) {
  2193.                 self.logger.info(msg);
  2194.             }
  2195.             else self.logger.info(err);
  2196.  
  2197.             defer.resolve();
  2198.         });
  2199.  
  2200.     return defer.promise;
  2201. };
  2202.  
  2203.  
  2204. // MPD pause
  2205. ControllerMpd.prototype.pause = function () {
  2206.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::pause');
  2207.     return this.sendMpdCommand('pause', []);
  2208. };
  2209.  
  2210. // MPD resume
  2211. ControllerMpd.prototype.resume = function () {
  2212.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::resume');
  2213.     return this.sendMpdCommand('play', []);
  2214. };
  2215.  
  2216.  
  2217. // MPD stop
  2218. ControllerMpd.prototype.stop = function () {
  2219.     this.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::stop');
  2220.     return this.sendMpdCommand('stop', []);
  2221. };
  2222.  
  2223.  
  2224. ControllerMpd.prototype.sanitizeUri = function (uri) {
  2225.     return uri.replace('music-library/', '').replace('mnt/', '');
  2226. }
  2227.  
  2228. ControllerMpd.prototype.reportUpdatedLibrary = function () {
  2229.     var self = this;
  2230.     // TODO PUSH THIS MESSAGE TO ALL CONNECTED CLIENTS
  2231.     self.commandRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'ControllerMpd::DB Update Finished');
  2232.     return self.commandRouter.pushToastMessage('Success', 'ASF', ' Added');
  2233. };
  2234.  
  2235. ControllerMpd.prototype.getConfigurationFiles = function () {
  2236.     var self = this;
  2237.  
  2238.     return ['config.json'];
  2239. };
  2240.  
  2241. ControllerMpd.prototype.getAdditionalConf = function (type, controller, data) {
  2242.     var self = this;
  2243.     return self.commandRouter.executeOnPlugin(type, controller, 'getConfigParam', data);
  2244. };
  2245.  
  2246. ControllerMpd.prototype.setAdditionalConf = function (type, controller, data) {
  2247.     var self = this;
  2248.     return self.commandRouter.executeOnPlugin(type, controller, 'setConfigParam', data);
  2249. };
  2250.  
  2251. ControllerMpd.prototype.getMyCollectionStats = function () {
  2252.     var self = this;
  2253.  
  2254.     var defer = libQ.defer();
  2255.  
  2256.     var cmd = libMpd.cmd;
  2257.     self.clientMpd.sendCommand(cmd("count", ["group", "artist"]), function (err, msg) {
  2258.         if (err) defer.resolve({
  2259.             artists: 0,
  2260.             albums: 0,
  2261.             songs: 0,
  2262.             playtime: '00:00:00'
  2263.         });
  2264.         else {
  2265.             var artistsCount = 0;
  2266.             var songsCount = 0;
  2267.             var playtimesCount = 0;
  2268.  
  2269.             var splitted = msg.split('\n');
  2270.             for (var i = 0; i < splitted.length - 1; i = i + 3) {
  2271.                 artistsCount++;
  2272.                 songsCount = songsCount + parseInt(splitted[i + 1].substring(7));
  2273.                 playtimesCount = playtimesCount + parseInt(splitted[i + 2].substring(10));
  2274.             }
  2275.  
  2276.             var convertedSecs = convert(playtimesCount);
  2277.  
  2278.  
  2279.             self.clientMpd.sendCommand(cmd("count", ["group", "album"]), function (err, msg) {
  2280.                 if (!err) {
  2281.                     var splittedAlbum = msg.split('\n').length;
  2282.                     var response = {
  2283.                         artists: artistsCount,
  2284.                         albums: (splittedAlbum - 1) / 3,
  2285.                         songs: songsCount,
  2286.                         playtime: convertedSecs.hours + ':' + ('0' + convertedSecs.minutes).slice(-2) + ':' + ('0' + convertedSecs.seconds).slice(-2)
  2287.                     };
  2288.                 }
  2289.  
  2290.                 defer.resolve(response);
  2291.  
  2292.             });
  2293.  
  2294.         }
  2295.  
  2296.  
  2297.     });
  2298.     return defer.promise;
  2299.  
  2300. };
  2301.  
  2302.  
  2303. ControllerMpd.prototype.rescanDb = function () {
  2304.     var self = this;
  2305.  
  2306.     return self.sendMpdCommand('rescan', []);
  2307. };
  2308.  
  2309.  
  2310.  
  2311. ControllerMpd.prototype.getGroupVolume = function () {
  2312.     var self = this;
  2313.     var defer = libQ.defer();
  2314.  
  2315.     return self.sendMpdCommand('status', [])
  2316.         .then(function (objState) {
  2317.  
  2318.             if (objState.volume) {
  2319.                 console.log(objState.volume);
  2320.                 defer.resolve(objState.volume);
  2321.             }
  2322.  
  2323.  
  2324.  
  2325.         });
  2326.     return defer.promise;
  2327. };
  2328.  
  2329. ControllerMpd.prototype.setGroupVolume = function (data) {
  2330.     var self = this;
  2331.     return self.sendMpdCommand('setvol', [data]);
  2332. };
  2333.  
  2334. ControllerMpd.prototype.syncGroupVolume = function (data) {
  2335.     var self = this;
  2336.  
  2337. };
  2338.  
  2339.  
  2340. ControllerMpd.prototype.handleBrowseUri = function (curUri) {
  2341.     var self = this;
  2342.  
  2343.     var response;
  2344.  
  2345.     self.logger.info("CURURI: "+curUri);
  2346.     if (curUri.startsWith('music-library')) {
  2347.         response = self.lsInfo(curUri);
  2348.     }else if (curUri.startsWith('playlists')) {
  2349.         if (curUri == 'playlists')
  2350.             response = self.listPlaylists(curUri);
  2351.         else response = self.browsePlaylist(curUri);
  2352.     }else if (curUri.startsWith('albums://')) {
  2353.         if (curUri == 'albums://')
  2354.             response = self.listAlbums(curUri);
  2355.         else
  2356.         {
  2357.             var splitted=curUri.split('/');
  2358.             if(splitted.length==3)
  2359.                 response = self.listAlbumSongs(curUri,2,'albums://');
  2360.             else response = self.listAlbumSongs(curUri,3,'albums://'+splitted[2]);
  2361.         }
  2362.     }else if (curUri.startsWith('artists://')) {
  2363.         if (curUri == 'artists://')
  2364.             response = self.listArtists(curUri);
  2365.         else
  2366.         {
  2367.             var splitted=curUri.split('/');
  2368.             if(splitted.length==3)
  2369.                 response = self.listArtist(curUri,2,'artists://');
  2370.             else response = self.listAlbumSongs(curUri,3,'artists://'+splitted[2]);
  2371.         }
  2372.     }else if (curUri.startsWith('genres://')) {
  2373.         if (curUri == 'genres://')
  2374.             response = self.listGenres(curUri);
  2375.         else
  2376.         {
  2377.             var splitted=curUri.split('/');
  2378.  
  2379.             if(splitted.length==3)
  2380.                 response = self.listGenre(curUri);
  2381.             else if(splitted.length==4)
  2382.                 response= self.listArtist(curUri,3,'genres://'+splitted[2],'genres://'+splitted[2]+'/'+splitted[3]);
  2383.             else
  2384.             {
  2385.                 if(splitted[3]=='')
  2386.                     response = self.listAlbumSongs(curUri,4,'genres://'+splitted[2]);
  2387.                 else response = self.listAlbumSongs(curUri,4,'genres://'+splitted[2]+"/"+splitted[3]);
  2388.             }
  2389.  
  2390.         }
  2391.  
  2392.  
  2393.     }
  2394.  
  2395.  
  2396.     return response;
  2397. };
  2398.  
  2399.  
  2400. /**
  2401.  *
  2402.  * list album
  2403.  */
  2404. ControllerMpd.prototype.listAlbums = function () {
  2405.     var self = this;
  2406.  
  2407.  
  2408.     var defer = libQ.defer();
  2409.  
  2410.     var response = {
  2411.         "navigation": {
  2412.             "lists": [
  2413.                 {
  2414.                     "availableListViews": [
  2415.                         "list",
  2416.                         "grid"
  2417.                     ],
  2418.                     "items": [
  2419.  
  2420.                     ]
  2421.                 }
  2422.             ]
  2423.         }
  2424.     };
  2425.  
  2426.     var cmd = libMpd.cmd;
  2427.     self.clientMpd.sendCommand(cmd("list", ["album","group","albumartist"]), function (err, msg) {
  2428.         if(err)
  2429.             defer.reject(new Error('Cannot list albums'));
  2430.         else
  2431.         {
  2432.             var lines=msg.split('\n');
  2433.  
  2434.             for (var i = 0; i < lines.length; i++)
  2435.             {
  2436.                 var line=lines[i];
  2437.                 if (line.indexOf('Album:') === 0) {
  2438.                     var albumName = line.slice(6).trim();
  2439.  
  2440.                     if(albumName!==undefined && albumName!=='')
  2441.                     {
  2442.                         var artistName=lines[i+1].slice(12).trim();
  2443.  
  2444.                         var album = {service:'mpd',type: 'folder', title: albumName,  artist:artistName,albumart: self.getAlbumArt({artist:artistName,album:albumName},undefined,'fa-dot-circle-o'), uri: 'albums://' + albumName};
  2445.  
  2446.                         response.navigation.lists[0].items.push(album);
  2447.                     }
  2448.                 }
  2449.             }
  2450.             defer.resolve(response);
  2451.         }
  2452.     });
  2453.     return defer.promise;
  2454.  
  2455. };
  2456.  
  2457. /**
  2458.  *
  2459.  * list album
  2460.  */
  2461. ControllerMpd.prototype.listAlbumSongs = function (uri,index,previous) {
  2462.     var self = this;
  2463.  
  2464.     var defer = libQ.defer();
  2465.  
  2466.     var splitted = uri.split('/');
  2467.  
  2468.     var albumName = nodetools.urlDecode(splitted[index]);
  2469.  
  2470.     var response={
  2471.         "navigation": {
  2472.             "lists": [
  2473.                 {
  2474.                     "availableListViews": [
  2475.                         "list"
  2476.                     ],
  2477.                     "items": [
  2478.  
  2479.                     ]
  2480.                 }
  2481.             ],
  2482.             "prev": {
  2483.                 "uri": previous
  2484.             }
  2485.         }
  2486.     };
  2487.  
  2488.     var cmd = libMpd.cmd;
  2489.     self.clientMpd.sendCommand(cmd("find album \""+albumName+"\"", []), function (err, msg) {
  2490.         if (msg) {
  2491.             var path;
  2492.             var name;
  2493.             var lines = msg.split('\n');
  2494.             for (var i = 0; i < lines.length; i++) {
  2495.                 var line = lines[i];
  2496.                 if (line.indexOf('file:') === 0) {
  2497.                     var path = line.slice(6);
  2498.                     var name = path.split('/').pop();
  2499.  
  2500.                     var artist = self.searchFor(lines, i + 1, 'Artist:');
  2501.                     var album = self.searchFor(lines, i + 1, 'Album:');
  2502.                     var title = self.searchFor(lines, i + 1, 'Title:');
  2503.                     var albumart=self.getAlbumArt({artist: artist, album: album}, self.getParentFolder(path),'fa-dot-circle');
  2504.                     var time = parseInt(self.searchFor(lines, i + 1, 'Time:'));
  2505.  
  2506.                     if (title) {
  2507.                         title = title;
  2508.                     } else {
  2509.                         title = name;
  2510.                     }
  2511.                     response.navigation.lists[0].items.push({
  2512.                         uri: 'music-library/'+path,
  2513.                         service: 'mpd',
  2514.                         title: title,
  2515.                         artist: artist,
  2516.                         album: album,
  2517.                         type: 'song',
  2518.                         tracknumber: 0,
  2519.                         albumart: albumart,
  2520.                         duration: time,
  2521.                         trackType: path.split('.').pop()
  2522.                     });
  2523.  
  2524.  
  2525.                 }
  2526.  
  2527.             }
  2528.         }
  2529.         else self.logger.info(err);
  2530.  
  2531.         defer.resolve(response);
  2532.     });
  2533.  
  2534.     return defer.promise;
  2535.  
  2536. };
  2537.  
  2538. /**
  2539.  *
  2540.  * list album
  2541.  */
  2542. ControllerMpd.prototype.listArtists = function () {
  2543.     var self = this;
  2544.  
  2545.     var defer = libQ.defer();
  2546.  
  2547.     var response = {
  2548.         "navigation": {
  2549.         "lists": [{
  2550.             "availableListViews": [
  2551.                 "list",
  2552.                 "grid"
  2553.             ],
  2554.             "items": [
  2555.  
  2556.             ]
  2557.         }]
  2558.         }
  2559.     };
  2560.  
  2561.     var cmd = libMpd.cmd;
  2562.     self.clientMpd.sendCommand(cmd("list", ["albumartist"]), function (err, msg) {
  2563.         if(err)
  2564.             defer.reject(new Error('Cannot list artist'));
  2565.         else
  2566.         {
  2567.             var splitted=msg.split('\n');
  2568.  
  2569.             for(var i in splitted)
  2570.             {
  2571.                 if(splitted[i].startsWith('AlbumArtist:'))
  2572.                 {
  2573.                     var artist=splitted[i].substring(13);
  2574.  
  2575.                     if(artist!=='')
  2576.                     {
  2577.                         var codedArtists=nodetools.urlEncode(artist);
  2578.  
  2579.                         var albumart=self.getAlbumArt({artist:codedArtists},undefined,'fa-users');
  2580.                         var item={
  2581.                             service: "mpd",
  2582.                             type: 'folder',
  2583.                             title: artist,
  2584.                             albumart: albumart,
  2585.                             uri: 'artists://' + codedArtists
  2586.                         }
  2587.  
  2588.                         response.navigation.lists[0].items.push(item);
  2589.                     }
  2590.                 }
  2591.             }
  2592.             defer.resolve(response);
  2593.         }
  2594.     });
  2595.     return defer.promise;
  2596.  
  2597. };
  2598.  
  2599. /**
  2600.  *
  2601.  * list album
  2602.  */
  2603. ControllerMpd.prototype.listArtist = function (curUri,index,previous,uriBegin) {
  2604.     var self = this;
  2605.  
  2606.     var defer = libQ.defer();
  2607.  
  2608.     var splitted=curUri.split('/');
  2609.  
  2610.     var response = {
  2611.         "navigation": {
  2612.             "lists": [{
  2613.                 "title": self.commandRouter.getI18nString('COMMON.ALBUMS'),
  2614.                 "icon": "fa icon",
  2615.                 "availableListViews": [
  2616.                     "list",
  2617.                     "grid"
  2618.                 ],
  2619.                 "items": [
  2620.  
  2621.                 ]
  2622.             },
  2623.                 {
  2624.                     "title": self.commandRouter.getI18nString('COMMON.TRACKS'),
  2625.                     "icon": "fa icon",
  2626.                     "availableListViews": [
  2627.                         "list"
  2628.                     ],
  2629.                     "items": [
  2630.  
  2631.                     ]
  2632.                 }],
  2633.             "prev": {
  2634.                 "uri": previous
  2635.             }
  2636.         }
  2637.     };
  2638.  
  2639.     self.mpdReady
  2640.         .then(function()
  2641.         {
  2642.             var artist=nodetools.urlDecode(splitted[index]);
  2643.  
  2644.  
  2645.             var cmd = libMpd.cmd;
  2646.  
  2647.             self.clientMpd.sendCommand(cmd("find artist \""+artist+"\"", []), function (err, msg) {
  2648.                 console.log("ERR: "+err);
  2649.                 console.log("MSG: "+msg+ " "+(msg=='')+ " "+(msg==' '));
  2650.  
  2651.                 if(msg=='')
  2652.                 {
  2653.                     self.clientMpd.sendCommand(cmd("find albumartist \""+artist+"\"", []), function (err, msg) {
  2654.                         self.parseListAlbum(err,msg,defer,response,uriBegin);
  2655.                     });
  2656.                 }
  2657.                 else self.parseListAlbum(err,msg,defer,response,uriBegin);
  2658.  
  2659.             });
  2660.         });
  2661.  
  2662.     return defer.promise;
  2663.  
  2664. };
  2665.  
  2666.  
  2667. ControllerMpd.prototype.parseListAlbum= function(err,msg,defer,response,uriBegin)
  2668. {
  2669.     var self=this;
  2670.     var list = [];
  2671.     var albums=[],albumarts=[];
  2672.     if (msg) {
  2673.  
  2674.  
  2675.         var path;
  2676.         var name;
  2677.         var lines = msg.split('\n');
  2678.  
  2679.         console.log("LINES: "+lines.length);
  2680.         for (var i = 0; i < lines.length; i++) {
  2681.             var line = lines[i];
  2682.             if (line.indexOf('file:') === 0) {
  2683.                 var path = line.slice(6);
  2684.                 var name = path.split('/').pop();
  2685.  
  2686.                 var artist = self.searchFor(lines, i + 1, 'Artist:');
  2687.                 var album = self.searchFor(lines, i + 1, 'Album:');
  2688.                 var title = self.searchFor(lines, i + 1, 'Title:');
  2689.                 var albumart=self.getAlbumArt({artist: artist, album: album}, self.getParentFolder(path),'fa-dot-circle-o');
  2690.  
  2691.                 if (title) {
  2692.                     title = title;
  2693.                 } else {
  2694.                     title = name;
  2695.                 }
  2696.                 response.navigation.lists[1].items.push({
  2697.                     service: 'mpd',
  2698.                     type: 'song',
  2699.                     title: title,
  2700.                     artist: artist,
  2701.                     album: album,
  2702.                     albumart: albumart,
  2703.                     uri: path
  2704.                 });
  2705.  
  2706.                 if(albums.indexOf(album)===-1)
  2707.                 {
  2708.                     albums.push(album);
  2709.                     albumarts.push();
  2710.  
  2711.                     var uri;
  2712.  
  2713.                     if(uriBegin===undefined)
  2714.                         uri='artists://' + nodetools.urlEncode(artist) +'/'+nodetools.urlEncode(album);
  2715.                     else uri=uriBegin+'/'+nodetools.urlEncode(album);
  2716.  
  2717.                     response.navigation.lists[0].items.push(
  2718.                         {
  2719.                             service:'mpd',
  2720.                             type: 'folder',
  2721.                             title: album,
  2722.                             albumart: self.getAlbumArt({artist: artist, album: album}, self.getParentFolder(path),'fa-dot-circle-o'),
  2723.                             uri: uri
  2724.                         });
  2725.                 }
  2726.             }
  2727.  
  2728.         }
  2729.  
  2730.         defer.resolve(response);
  2731.  
  2732.  
  2733.     }
  2734.     else
  2735.     {
  2736.         self.logger.info(err);
  2737.         defer.reject(new Error());
  2738.     }
  2739. }
  2740.  
  2741.  
  2742. /**
  2743.  *
  2744.  * list album
  2745.  */
  2746. ControllerMpd.prototype.listGenres = function () {
  2747.     var self = this;
  2748.  
  2749.     var defer = libQ.defer();
  2750.  
  2751.     var response = {
  2752.         "navigation": {
  2753.             "lists": [
  2754.                 {
  2755.                     "availableListViews": [
  2756.                         "list"
  2757.                     ],
  2758.                     "items": [
  2759.  
  2760.                     ]
  2761.                 }
  2762.             ]
  2763.         }
  2764.     };
  2765.  
  2766.  
  2767.     var cmd = libMpd.cmd;
  2768.     self.clientMpd.sendCommand(cmd("list", ["genre"]), function (err, msg) {
  2769.         if(err)
  2770.             defer.reject(new Error('Cannot list genres'));
  2771.         else
  2772.         {
  2773.             var splitted=msg.split('\n');
  2774.  
  2775.             for(var i in splitted)
  2776.             {
  2777.                 if(splitted[i].startsWith('Genre:'))
  2778.                 {
  2779.                     var genreName=splitted[i].substring(7);
  2780.  
  2781.                     if(genreName!=='')
  2782.                     {
  2783.                         var albumart=self.getAlbumArt({},undefined,'fa-tags');
  2784.                         var album = {service:'mpd',type: 'folder', title: genreName, albumart:albumart, uri: 'genres://' + nodetools.urlEncode(genreName)};
  2785.  
  2786.                         response.navigation.lists[0].items.push(album);
  2787.                     }
  2788.  
  2789.                 }
  2790.             }
  2791.             defer.resolve(response);
  2792.         }
  2793.     });
  2794.     return defer.promise;
  2795.  
  2796. };
  2797.  
  2798. /**
  2799.  *
  2800.  * list album
  2801.  */
  2802. ControllerMpd.prototype.listGenre = function (curUri) {
  2803.     var self = this;
  2804.  
  2805.     var defer = libQ.defer();
  2806.  
  2807.     var splitted=curUri.split('/');
  2808.     var genreName=nodetools.urlDecode(splitted[2]);
  2809.  
  2810.     var response={
  2811.         "navigation": {
  2812.             "lists": [
  2813.                 {
  2814.                     "title": self.commandRouter.getI18nString('COMMON.ARTISTS'),
  2815.                     "icon": "fa icon",
  2816.                     "availableListViews": [
  2817.                         "list",
  2818.                         "grid"
  2819.                     ],
  2820.                     "items": []
  2821.                 },
  2822.                 {
  2823.                     "title": self.commandRouter.getI18nString('COMMON.ALBUMS'),
  2824.                     "icon": "fa icon",
  2825.                     "availableListViews": [
  2826.                         "list",
  2827.                         "grid"
  2828.                     ],
  2829.                     "items": []
  2830.                 }
  2831.                 ,{
  2832.                     "title": self.commandRouter.getI18nString('COMMON.TRACKS'),
  2833.                     "icon": "fa icon",
  2834.                     "availableListViews": [
  2835.                         "list"
  2836.                     ],
  2837.                     "items": []
  2838.                 }
  2839.             ],
  2840.             "prev": {
  2841.                 "uri": "genres://"
  2842.             }
  2843.         }
  2844.     };
  2845.  
  2846.     self.mpdReady
  2847.         .then(function() {
  2848.             var cmd = libMpd.cmd;
  2849.             self.clientMpd.sendCommand(cmd("find genre \"" + genreName + "\"", []), function (err, msg) {
  2850.                 var albums=[];
  2851.                 var albumsArt=[];
  2852.                 var artists=[];
  2853.                 var artistArt=[];
  2854.  
  2855.                 var list = [];
  2856.                 if (msg) {
  2857.                     var path;
  2858.                     var name;
  2859.                     var lines = msg.split('\n');
  2860.                     for (var i = 0; i < lines.length; i++) {
  2861.                         var line = lines[i];
  2862.                         if (line.indexOf('file:') === 0) {
  2863.                             var path = line.slice(6);
  2864.                             var name = path.split('/').pop();
  2865.  
  2866.                             var artist = self.searchFor(lines, i + 1, 'Artist:');
  2867.                             var album = self.searchFor(lines, i + 1, 'Album:');
  2868.                             var title = self.searchFor(lines, i + 1, 'Title:');
  2869.                             var albumart = self.getAlbumArt({artist: artist, album: album}, self.getParentFolder(path),'fa-tags');
  2870.  
  2871.                             if (title) {
  2872.                                 title = title;
  2873.                             } else {
  2874.                                 title = name;
  2875.                             }
  2876.  
  2877.                             if(title!=='')
  2878.                             {
  2879.                                 response.navigation.lists[2].items.push({
  2880.                                     service: 'mpd',
  2881.                                     type: 'song',
  2882.                                     title: title,
  2883.                                     artist: artist,
  2884.                                     album: album,
  2885.                                     albumart: albumart,
  2886.                                     uri: 'music-library/' + path
  2887.                                 });
  2888.                             }
  2889.  
  2890.                             if(albums.indexOf(album)===-1)
  2891.                             {
  2892.                                 albums.push(album);
  2893.                                 albumsArt.push(albumart);
  2894.  
  2895.                                 if(album!=='')
  2896.                                     response.navigation.lists[1].items.push({service:'mpd',type: 'folder', title: album, albumart: albumart,
  2897.                                         uri: 'genres://' + nodetools.urlEncode(genreName)+'//'+nodetools.urlEncode(album)});
  2898.                             }
  2899.  
  2900.                             if(artists.indexOf(artist)===-1)
  2901.                             {
  2902.                                 artists.push(artist);
  2903.                                 artistArt.push()
  2904.  
  2905.                                 if(artist!=='')
  2906.                                     response.navigation.lists[0].items.push({service:'mpd',type: 'folder', title: artist, albumart: self.getAlbumArt({artist: artist}, self.getParentFolder('/mnt/' + path),'fa-users'),
  2907.                                         uri: 'genres://' + nodetools.urlEncode(genreName)+'/'+nodetools.urlEncode(artist)});
  2908.                             }
  2909.  
  2910.                         }
  2911.  
  2912.                     }
  2913.  
  2914.  
  2915.                     defer.resolve(response);
  2916.  
  2917.                 }
  2918.                 else
  2919.                 {
  2920.                     self.logger.info(err);
  2921.                     defer.reject(new Error());
  2922.                 }
  2923.  
  2924.  
  2925.             });
  2926.         });
  2927.     return defer.promise;
  2928.  
  2929. };
  2930.  
  2931.  
  2932. ControllerMpd.prototype.getMixerControls = function () {
  2933.     var self = this;
  2934.  
  2935.     var cards = self.commandRouter.executeOnPlugin('audio_interface', 'alsa_controller', 'getMixerControls', '1');
  2936.  
  2937.     cards.then(function (data) {
  2938.         console.log(data);
  2939.     })
  2940.         .fail(function () {
  2941.             console.log(data);
  2942.         });
  2943.  
  2944.     //console.log(cards)
  2945.  
  2946. };
  2947.  
  2948. ControllerMpd.prototype.getParentFolder = function (file) {
  2949.     var index=file.lastIndexOf('/');
  2950.  
  2951.     if(index>-1)
  2952.     {
  2953.         return file.substring(0,index);
  2954.     }
  2955.     else return '';
  2956. };
  2957.  
  2958. ControllerMpd.prototype.getAlbumArtPathFromUri = function (uri) {
  2959.     var self = this;
  2960.     var startIndex = 0;
  2961.  
  2962.     var splitted = uri.split('/');
  2963.  
  2964.     while (splitted[startIndex] === '') {
  2965.         startIndex = startIndex + 1;
  2966.     }
  2967.  
  2968.  
  2969.     if (splitted[startIndex] === 'mnt') {
  2970.         startIndex = startIndex + 1;
  2971.     }
  2972.  
  2973.     var result = '';
  2974.  
  2975.     for (var i = startIndex; i < splitted.length - 1; i++) {
  2976.  
  2977.         result = result + '/' + splitted[i];
  2978.     }
  2979.  
  2980.     return result;
  2981.  
  2982. }
  2983.  
  2984. ControllerMpd.prototype.prefetch = function (trackBlock) {
  2985.     var self=this;
  2986.     this.logger.info("DOING PREFETCH IN MPD");
  2987.     var uri=this.sanitizeUri(trackBlock.uri);
  2988.     this.logger.info(uri);
  2989.  
  2990.     return this.sendMpdCommand('add "'+uri+'"',[])
  2991.         .then(function(){
  2992.             return self.sendMpdCommand('consume 1',[]);
  2993.         });
  2994. }
  2995.  
  2996. ControllerMpd.prototype.goto=function(data){
  2997.     if(data.type=='artist')
  2998.         return this.listArtist('artists://'+nodetools.urlEncode(data.value),2,'')
  2999.     else
  3000.         return this.listAlbumSongs("albums://"+nodetools.urlEncode(data.value),2);
  3001.  
  3002. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement