Skip to content

Commit

Permalink
v0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
erkstruwe committed Mar 13, 2016
1 parent 2da8507 commit fa4830d
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ node_modules

# Optional REPL history
.node_repl_history

# IDE
.idea
264 changes: 264 additions & 0 deletions chromecast-cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
#!/usr/bin/env node

var app = require('commander');
var async = require('async');
var lodash = require('lodash');
var Client = require('castv2-client').Client;
var Receiver = require('castv2-client').DefaultMediaReceiver;

var connect = function(host, cb) {
var client = new Client();
client.on('error', function(e) {
console.error('Client error', e);
client.close();
});
client.on('message', function(message) {
console.log('Client message', message);
});
client.on('close', function() {
console.error('Client closed');
});

return client.connect(host, function() {
return cb(null, client);
});
};

app
.version('0.0.1')
.option('-H, --host <host>', 'IP address or hostname of Chromecast (required)');

app
.command('play <src>')
.description('Play file at <src>')
// TODO .option('-r, --repeat-mode <repeat-mode>', 'Set repeat mode (REPEAT_OFF, REPEAT_ONE or REPEAT_ALL)', /^(REPEAT_OFF|REPEAT_ONE|REPEAT_ALL)$/i, 'REPEAT_OFF')
.option('-f, --force', 'Force play even if Chromecast is already casting')
.action(function(src, options) {
if (!app.host)
throw new Error('--host option is required');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
status: ['client', function(cb, r) {
return r.client.receiver.getStatus(cb);
}],
receiver: ['client', 'status', function(cb, r) {
if (!options.force && lodash.get(r.status, 'applications.0'))
return cb(new Error('Already casting. Use --force option to override.'));
return r.client.launch(Receiver, cb);
}],
media: ['receiver', function(cb, r) {
var media = {
contentId: src
};
r.receiver.load(media, {autoplay: true, repeatMode: options.repeatMode}, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.media.playerState, r.media.media, r.media.repeatMode);
return process.exit();
});
});

app
.command('volume <volume>')
.description('Set the volume to <volume>')
.action(function(volume) {
if (!app.host)
throw new Error('--host option is required');

volume = parseFloat(volume);
if (!volume)
throw new Error('Invalid volume parameter. Has to be float between 0.0 and 1.0.');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
volume: ['client', function(cb, r) {
r.client.receiver.setVolume({level: volume, muted: false}, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.volume);
return process.exit();
});
});

app
.command('volumeStepUp <volumeStep>')
.description('Set the volume <volumeStep> higher')
.action(function(volumeStep) {
if (!app.host)
throw new Error('--host option is required');

volumeStep = parseFloat(volumeStep);
if (!volumeStep)
throw new Error('Invalid volumeStep parameter. Has to be float between 0.0 and 1.0.');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
oldVolume: ['client', function(cb, r) {
r.client.receiver.getVolume(cb);
}],
newVolume: ['client', 'oldVolume', function(cb, r) {
var volume = r.oldVolume.level;
volume += volumeStep;
volume = volume > 1 ? 1 : volume;
r.client.receiver.setVolume({level: volume, muted: false}, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.newVolume);
return process.exit();
});
});

app
.command('volumeStepDown <volumeStep>')
.description('Set the volume <volumeStep> lower')
.action(function(volumeStep) {
if (!app.host)
throw new Error('--host option is required');

volumeStep = parseFloat(volumeStep);
if (!volumeStep)
throw new Error('Invalid volumeStep parameter. Has to be float between 0.0 and 1.0.');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
oldVolume: ['client', function(cb, r) {
r.client.receiver.getVolume(cb);
}],
newVolume: ['client', 'oldVolume', function(cb, r) {
var volume = r.oldVolume.level;
volume -= volumeStep;
volume = volume < 0 ? 0 : volume;
r.client.receiver.setVolume({level: volume, muted: false}, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.newVolume);
return process.exit();
});
});

app
.command('mute')
.description('Mute')
.action(function() {
if (!app.host)
throw new Error('--host option is required');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
volume: ['client', function(cb, r) {
r.client.receiver.setVolume({muted: true}, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.volume);
return process.exit();
});
});

app
.command('unmute')
.description('Unmute')
.action(function() {
if (!app.host)
throw new Error('--host option is required');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
volume: ['client', function(cb, r) {
r.client.receiver.setVolume({muted: false}, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.volume);
return process.exit();
});
});

app
.command('stop')
.description('Stop playback')
.action(function() {
if (!app.host)
throw new Error('--host option is required');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
stop: ['client', function(cb, r) {
return r.client.receiver.stop(null, cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
return process.exit();
});
});

app
.command('status')
.description('Get Chromecast status')
.action(function() {
if (!app.host)
throw new Error('--host option is required');

return async.auto({
client: function(cb) {
return connect(app.host, cb);
},
status: ['client', function(cb, r) {
return r.client.receiver.getStatus(cb);
}]
}, function(e, r) {
if (e) {
console.error(e);
return process.exit(1);
}
console.log(r.status);
return process.exit();
});
});

app
.parse(process.argv);

if (!process.argv.slice(2).length) {
app.help();
}
35 changes: 35 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "chromecast-cli",
"version": "0.0.1",
"description": "Command line interface for Google Chromecast",
"author": "Erk Struwe <[email protected]>",
"license": "GPL-3.0",
"main": "chromecast-cli.js",
"engines": {
"node": "5.8.0"
},
"homepage": "https://github.com/erkstruwe/chromecast-cli#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/erkstruwe/chromecast-cli.git"
},
"bugs": {
"url": "https://github.com/erkstruwe/chromecast-cli/issues"
},
"scripts": {
"test": "jshint chromecast-cli.js",
"start": "node chromecast-cli.js --help"
},
"jshintConfig": {
"esversion": 6
},
"dependencies": {
"async": "^1.5.2",
"castv2-client": "~1.1.1",
"commander": "^2.9.0",
"lodash": "^4.6.1"
},
"devDependencies": {
"jshint": "~2.9.1"
}
}

0 comments on commit fa4830d

Please sign in to comment.