Permalink
Browse files

badass roku tech

  • Loading branch information...
contra committed Aug 15, 2013
1 parent 2309e36 commit ce2655aa3a9db17ece5de5c95b2c56f021078338
Showing with 210 additions and 89 deletions.
  1. +67 −22 README.md
  2. +18 −1 examples/roku.js
  3. +1 −52 lib/App.js
  4. +3 −1 lib/Device.js
  5. +1 −1 lib/Finder.js
  6. +59 −2 lib/devices/chromecast.js
  7. +59 −5 lib/devices/roku.js
  8. +2 −5 package.json
View
@@ -16,13 +16,7 @@
</tr>
</table>
-This library has been tested with ChromeCast, Roku, and a Panasonic Viera TV. It fully supports any device that uses the DIAL protocol. Support for custom device functionality is supported in some cases (See Custom Devices section below).
-
-## How this works
-
-![DIAL](http://geeknizer.com/wp-content/uploads/2013/07/dial-discovery.jpg)
-
-This uses the DIAL discovery protocol over SSDP to discover devices. Once you get a device, you can access applications on it using the DIAL relaxation protocol.
+This library fully supports any device that uses the DIAL discovery protocol. Support for custom device functionality is supported in some cases (See Custom Devices section below). This library has been tested with ChromeCast, Roku, and a Panasonic Viera TV. Any device that lets you send YouTube videos to it will have the DIAL protocol.
## Example
@@ -34,22 +28,11 @@ var devices = nodecast.find();
devices.once('device', function(device) {
var yt = device.app('YouTube');
- yt.info(function(err, info){
- // returns info about the app
- // who wrote it, capabilities, etc.
- });
-
yt.start('v=12345', function(err) {
// starts the app on the device
// also optionally takes data to pass to the app
// (for example: youtube takes v=id to launch with a video)
});
-
- yt.stop(function(err){});
-
- // RAMP stuff
- yt.connect();
- yt.send('hey youtube');
});
```
@@ -104,13 +87,75 @@ network.on('device', function(device){
});
```
-## Command Line
+## Application
+
+#### .info(cb)
+
+Callback is optional. Result data is the parsed XML of whatever the device vendor and application vendor chose to put on their page.
+
+Example:
+
+```javascript
+var network = nodecast.find();
+
+network.on('device', function(device){
+ var yt = device.app('YouTube');
+
+ yt.info(function(err, info){
+
+ });
+});
+```
+
+#### .start(data, cb)
-This comes with two demo command line tools.
+Data and callback are both optional. The format of data may depend on the device or the app you are interfacing with.
-`rollcast` will play rick roll on every device in your network.
+Example:
-`ytcast <video url>` will play a youtube video of your choice on every device in your network.
+```javascript
+var network = nodecast.find();
+
+network.on('device', function(device){
+ var yt = device.app('YouTube');
+
+ // all below are valid
+ yt.start('v=12345', function(err){
+
+ });
+
+ yt.start({v:"12345"}, function(err){
+
+ });
+
+ yt.start(function(err){
+
+ });
+
+ yt.start();
+});
+```
+
+#### .stop(cb)
+
+Callback is optional. Stops the app. Some devices do not support this.
+
+Example:
+
+```javascript
+var network = nodecast.find();
+
+network.on('device', function(device){
+ var yt = device.app('YouTube');
+
+ // all below are valid
+ yt.stop(function(err){
+
+ });
+
+ yt.stop();
+});
+```
## Custom Devices
View
@@ -1,13 +1,30 @@
#!/usr/bin/env node
var nodecast = require('../');
+var async = require('async');
var stream = nodecast.find('roku');
stream.on('device', function(device) {
console.log('Found device', device.name);
+ device.press('Home');
device.apps(function(err, apps){
if (err) return console.log(err);
- console.log(apps);
+ console.log("Found", apps.length, "apps:");
+ apps.forEach(function(app){
+ console.log(app.name, '=', app.id);
+ });
+
+ var spotify = device.app('Spotify');
+ spotify.start(function(){
+ // wait for load screen
+ setTimeout(function(){
+ // search for songs
+ device.press(['Select', 'Select'], function(){
+ device.type("elaquent");
+ });
+ }, 6000);
+ });
+
});
});
View
@@ -44,7 +44,7 @@ App.prototype.start = function(data, cb) {
}
request.end(function(err, res){
- cb(err);
+ if (cb) cb(err);
});
return this;
};
@@ -59,55 +59,4 @@ App.prototype.stop = function(cb) {
return this;
};
-// TODO: only have WS for RAMP protocol
-// support standard DIAL protocol
-// support specifying a custom protocol
-App.prototype.send = function(data) {
- this.socket.send(JSON.stringify([this.name, data]));
- return this;
-};
-
-App.prototype.getConnection = function(cb) {
- this.info(function(err, info) {
- if (err) return cb(err);
- var svcUrl = info.servicedata.connectionSvcURL;
- var request = superagent.post(svcUrl);
- request.type('json');
- request.end(function(err, res) {
- if (err) return cb(err);
- cb(null, res.body.URL);
- });
- });
-};
-
-App.prototype.connect = function(cb) {
- var that = this;
- this.getConnection(function(err, sockUrl) {
- if (err && cb) return cb(err);
- that.socket = new WS(sockUrl);
-
- // RAMP parser
- that.socket.on('message', function(data) {
- var parsed = JSON.parse(data);
- if (Array.isArray(parsed)) { // command
- var protocol = parsed[0];
- var msg = parsed[1];
- that.emit('command', protocol, msg);
- that.emit(protocol+':command', msg);
- }
- });
-
- // handle system events
- that.on('cm:command', function(msg) {
- if (msg.type === "ping") {
- that.send('cm', {type: "pong"});
- that.emit('ping');
- }
- });
-
- if (cb) that.socket.on('open', cb);
- });
- return this;
-};
-
module.exports = App;
View
@@ -19,7 +19,7 @@ util.inherits(Device, EventEmitter);
Device.prototype.app = function(appName) {
if (!this._apps[appName]) {
- this._apps[appName] = new App(this, appName);
+ this._apps[appName] = new this.App(this, appName);
}
return this._apps[appName];
};
@@ -28,4 +28,6 @@ Device.prototype.is = function(deviceName) {
return this.types.indexOf(deviceName.toLowerCase()) !== -1;
};
+Device.prototype.App = App;
+
module.exports = Device;
View
@@ -57,7 +57,7 @@ Finder.prototype.add = function(msg, info){
address: info.address,
port: urlParts.port,
appsBase: url.format(urlParts),
- httpBase: urlParts.host
+ httpBase: (urlParts.protocol+"//"+urlParts.host)
};
// Check for custom devices
View
@@ -1,4 +1,5 @@
var Device = require('../Device');
+var App = require('../App');
var util = require('util');
var superagent = require('superagent');
@@ -9,16 +10,72 @@ function ChromeCast() {
util.inherits(ChromeCast, Device);
ChromeCast.prototype.reboot = function(cb) {
- var request = superagent.post("http://"+this.httpBase+"/setup/reboot");
+ var request = superagent.post(this.httpBase+"/setup/reboot");
request.buffer();
request.type('json');
request.end(function(err, res) {
- cb(err, res);
+ if (cb) cb(err, res);
});
};
ChromeCast.matches = function(device) {
return device.info.modelName === "Eureka Dongle";
};
+// Override default app
+function ChromeCastApp() {
+ App.apply(this, arguments);
+}
+util.inherits(ChromeCastApp, App);
+
+ChromeCastApp.prototype.send = function(data) {
+ this.socket.send(JSON.stringify([this.name, data]));
+ return this;
+};
+
+ChromeCastApp.prototype.getConnection = function(cb) {
+ this.info(function(err, info) {
+ if (err) return cb(err);
+ var svcUrl = info.servicedata.connectionSvcURL;
+ var request = superagent.post(svcUrl);
+ request.type('json');
+ request.end(function(err, res) {
+ if (err) return cb(err);
+ cb(null, res.body.URL);
+ });
+ });
+};
+
+ChromeCastApp.prototype.connect = function(cb) {
+ var that = this;
+ this.getConnection(function(err, sockUrl) {
+ if (err && cb) return cb(err);
+ that.socket = new WS(sockUrl);
+
+ // RAMP parser
+ that.socket.on('message', function(data) {
+ var parsed = JSON.parse(data);
+ if (Array.isArray(parsed)) { // command
+ var protocol = parsed[0];
+ var msg = parsed[1];
+ that.emit('command', protocol, msg);
+ that.emit(protocol+':command', msg);
+ }
+ });
+
+ // handle system events
+ that.on('cm:command', function(msg) {
+ if (msg.type === "ping") {
+ that.send('cm', {type: "pong"});
+ that.emit('ping');
+ }
+ });
+
+ if (cb) that.socket.on('open', cb);
+ });
+ return this;
+};
+
+ChromeCast.prototype.App = ChromeCastApp;
+
module.exports = ChromeCast;
Oops, something went wrong.

0 comments on commit ce2655a

Please sign in to comment.