changeset 0:363600705376 default tip

Initial commit.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 23 Aug 2011 18:43:15 -0700
parents
children
files config.js lib.js xmpp.js
diffstat 3 files changed, 209 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/config.js
@@ -0,0 +1,2 @@
+exports.jid = 'you@example.org';
+exports.password = 'yourPassword';
new file mode 100644
--- /dev/null
+++ b/lib.js
@@ -0,0 +1,159 @@
+var net = require('net');
+var sys = require('sys');
+
+function MPD(server, port) {
+  if (!port) port = '6600';
+  if (!server) server = '::';
+  
+  this.connect(port, server);
+}
+
+MPD.prototype = {
+  stream: null,
+  is_connected: false,
+  updateTimer: null,
+  
+  status: {},
+  cs: {},
+  
+  _callbacks: {},
+  
+  _callback: function() {
+    this._callback = null;
+  },
+  
+  close: function() {
+    this.stream.end();
+    this.is_connected = false;
+  },
+  
+  connect: function(port, server) {
+    if (this.is_connected == true) {
+      this.close();
+    }
+    
+    this.stream = net.createConnection(port, server);
+    
+    this.stream.setEncoding('utf8');
+    
+    this.stream.on('connect', this.connected());
+    this.stream.on('data', this.data());
+    this.stream.on('close', this.closed());
+    
+    this.stream.on('end', function() {
+      this.end();
+    });
+  },
+  
+  connected: function() {
+    var self = this;
+    
+    return function() {
+      self.is_connected = true;
+      if (self.debug) console.log('MPD connection opened');
+      
+      /*self.updateTimer = setInterval(function() {
+        if (self.is_connected == true) {
+          self.send('currentsong', function(cs) {          
+            for (var v in cs) {
+              if (self.cs[v] != cs[v]) {
+                self.callback(v, cs[v]);
+                self.cs[v] = cs[v];
+              }
+            }
+          });
+          
+          self.send('status', function(status) {          
+            for (var v in status) {
+              if (self.status[v] != status[v]) {
+                self.callback(v, status[v]);
+                self.status[v] = status[v];
+              }
+            }
+          });
+        } else {
+          clearInterval(self.updateTimer);
+        }
+      }, 1000);*/
+      
+      self.callback('connect');
+    };
+  },
+  
+  data: function() {
+    var self = this;
+    
+    var packet = [];
+    
+    return function(data) {
+      var data = data.toString();
+      var commands = data.split('\n');
+      
+      for (var i = 0; i < commands.length; i++) {
+        if (commands[i].length >= 2) {
+          packet.push(commands[i]);
+          
+          var command = commands[i].split(' ');
+          
+          switch (command[0]) {
+            case 'ACK':
+            case 'OK':
+              if (command[1] == 'MPD') {
+                self.version = command[2];
+              } else {
+                self._callback.call(self, self._parsePacket(packet));
+                packet = [];
+                this._callback = null;
+              }
+            break;
+          }
+        }
+      }
+    };
+  },
+  
+  closed: function() {
+    var self = this;
+    
+    return function(had_error) {
+      if (self.debug) console.log('MPD connection closed');
+      self.callback('close');
+    };
+  },
+  
+  _parsePacket: function(packet) {
+    var p = {};
+    
+    for (var i = 0; i < packet.length; i++) {
+      var regx = /^(\w+):\s?(.*)$/i;
+      var result = regx.exec(packet[i]);
+      
+      if (result !== null) {
+        p[result[1]] = result[2];
+      }
+    }
+    
+    return p;
+  },
+  
+  send: function(str, cb) {
+    this._callback = cb;
+    this.stream.write(str + '\n');
+  },
+  
+  on: function(type, cb) {
+    if (!this._callbacks[type]) this._callbacks[type] = [];
+    
+    this._callbacks[type].push(cb);
+  },
+  
+  callback: function(type, data) {
+    if (this._callbacks[type]) {
+      for (var c = 0; c < this._callbacks[type].length; c++) {
+        this._callbacks[type][c].call(this, data);
+      }
+    }
+  }
+};
+
+module.exports = MPD;
new file mode 100755
--- /dev/null
+++ b/xmpp.js
@@ -0,0 +1,48 @@
+#!/usr/bin/env node
+
+var MPD = require('./lib');
+var xmpp = require('node-xmpp');
+var config = require('./config');
+
+var mpd = new MPD();
+var conn = new xmpp.Client(config);
+var id = 0;
+var NS = 'http://jabber.org/protocol/tune';
+
+var publish = function() {
+  mpd.send('status', function(s) {
+    mpd.send('currentsong', function(cs) {
+      var tune = new xmpp.Element('tune', {xmlns: NS});
+     
+      if (cs.file && s.state === 'play') {
+        // Don't publish "rating" and "uri".
+        if (cs.Artist)
+          tune.c('artist').t(cs.Artist);
+        if (cs.Time)
+          tune.c('length').t(cs.Time);
+        if (cs.Album)
+          tune.c('source').t(cs.Album);
+        if (cs.Title)
+          tune.c('title').t(cs.Title);
+        if (cs.Track)
+          tune.c('track').t(cs.Track);
+      }
+     
+      conn.send(new xmpp.Element('iq', {type: 'set', id: 'mpd-'+(++id)})
+        .c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'})
+          .c('publish', {node: NS})
+            .c('item')
+              .cnode(tune).up()
+            .up()
+          .up()
+        .up());
+     
+      mpd.send('idle player', publish);
+    });
+  });
+};
+
+// We suppose that the XMPP connection will be open after the MPD one.
+conn.on('online', publish);
+
+// vim: sts=2 et sw=2