Permalink
Browse files

Add buffer support to tag()

  • Loading branch information...
1 parent ecf3b1a commit e99682e4c08b302bd01790c1b531daf74f926daa @nikhilm committed May 29, 2012
Showing with 119 additions and 12 deletions.
  1. +4 −0 README.md
  2. +77 −0 spec/buffersSpec.js
  3. +36 −10 src/tag.cc
  4. +2 −2 src/taglib.cc
View
@@ -95,6 +95,7 @@ In the second variant, which can read from a buffer, `format` should be
a string as specified in [Formats](#formats).
### tag(path, callback)
+### tag(buffer, format, callback)
Read the tag from the file at `path` _asynchronously_. The callback should have
signature `(err, tag)`. On success, `err` will be `null` and `tag` will be
@@ -103,6 +104,9 @@ a `Tag`. If errors occurred, `err` will contain the error and
integer error code (`errno.h`) and field `message` will have a string
representation.
+In the second variant, which can read from a buffer, `format` should be
+a string as specified in [Formats](#formats).
+
### tagSync(path)
### tagSync(buffer, format)
View
@@ -101,6 +101,83 @@ vows.describe('taglib bindings: Buffers')
}
},
+ /* * T A G * */
+ 'tag metadata from mp3 buffer': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.tag(buf, 'mpeg', this.callback);
+ },
+
+ 'should be called with two arguments': function (err, tag) {
+ assert.equal(arguments.length, 2);
+ assert.isNull(err);
+ assert.isObject(tag);
+ },
+
+ 'reading tags': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.tag(buf, 'mpeg', this.callback);
+ },
+
+ 'title should be `A bit-bucket full of tags`': function (tag) {
+ assert.equal(tag.title, 'A bit-bucket full of tags');
+ },
+ 'artist should be by `gitzer\'s`': function (tag) {
+ assert.equal(tag.artist, 'gitzer\'s');
+ },
+ 'album should be on `Waffles for free!`': function (tag) {
+ assert.equal(tag.album, "Waffles for free!");
+ },
+ 'track should be the first': function (tag) {
+ assert.equal(tag.track, 1);
+ },
+ 'should be from 2011': function (tag) {
+ assert.equal(tag.year, 2011);
+ },
+ 'should have a silly comment': function(tag) {
+ assert.equal(tag.comment, "Salami Wiglet.");
+ }
+ }
+ },
+
+ 'tag data from a buffer with unknown format': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.tag(buf, '', this.callback);
+ },
+
+ 'should raise an error': function(err, _) {
+ assert.isNotNull(err);
+ assert.match(err.message, /Unknown file format/);
+ }
+ },
+
+ 'tag data from a buffer with wrong format': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.tag(buf, 'ogg', this.callback);
+ },
+
+ 'should raise an error': function(err, _) {
+ assert.isNotNull(err);
+ assert.match(err.message, /Failed to extract tags/);
+ }
+ },
+
+ 'tag data from empty buffer': {
+ topic: function() {
+ var buf = new Buffer(0);
+ Taglib.tag(buf, 'mpeg', this.callback);
+ },
+
+ 'should lead to empty tags and properties': function(err, tag) {
+ assert.isNull(err);
+ assert.isObject(tag);
+ }
+ },
+
+
/* * T A G S Y N C * */
'tagSync metadata from mp3 buffer': {
topic: function() {
View
@@ -187,23 +187,44 @@ Handle<Value> Tag::SyncTag(const Arguments &args) {
v8::Handle<v8::Value> Tag::AsyncTag(const v8::Arguments &args) {
HandleScope scope;
- if (args.Length() < 1 || !args[0]->IsString())
- return ThrowException(String::New("Expected string 'path' as first argument"));
+ if (args.Length() < 1) {
+ return ThrowException(String::New("Expected string or buffer as first argument"));
+ }
- String::Utf8Value path(args[0]->ToString());
+ if (args[0]->IsString()) {
+ if (args.Length() < 2 || !args[1]->IsFunction())
+ return ThrowException(String::New("Expected callback function as second argument"));
- if (args.Length() < 2 || !args[1]->IsFunction())
- return ThrowException(String::New("Expected callback function as second argument"));
+ }
+ else if (Buffer::HasInstance(args[0])) {
+ if (args.Length() < 2 || !args[1]->IsString())
+ return ThrowException(String::New("Expected string 'format' as second argument"));
+ if (args.Length() < 3 || !args[2]->IsFunction())
+ return ThrowException(String::New("Expected callback function as third argument"));
+ }
+ else {
+ return ThrowException(String::New("Expected string or buffer as first argument"));
+ }
- Local<Function> callback = Local<Function>::Cast(args[1]);
AsyncBaton *baton = new AsyncBaton;
baton->request.data = baton;
- baton->path = strdup(*path);
+ baton->path = 0;
baton->tag = NULL;
- baton->callback = Persistent<Function>::New(callback);
baton->error = 0;
+ if (args[0]->IsString()) {
+ String::Utf8Value path(args[0]->ToString());
+ baton->path = strdup(*path);
+ baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
+
+ }
+ else {
+ baton->format = NodeStringToTagLibString(args[1]->ToString());
+ baton->stream = new BufferStream(args[0]->ToObject());
+ baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
+ }
+
uv_queue_work(uv_default_loop(), &baton->request, Tag::AsyncTagRead, Tag::AsyncTagReadAfter);
return Undefined();
@@ -213,9 +234,14 @@ void Tag::AsyncTagRead(uv_work_t *req) {
AsyncBaton *baton = static_cast<AsyncBaton*>(req->data);
TagLib::FileRef *f;
- int error;
- baton->error = node_taglib::CreateFileRefPath(baton->path, &f);
+ if (baton->path) {
+ baton->error = node_taglib::CreateFileRefPath(baton->path, &f);
+ }
+ else {
+ assert(baton->stream);
+ baton->error = node_taglib::CreateFileRef(baton->stream, baton->format, &f);
+ }
if (baton->error == 0) {
baton->tag = new Tag(f);
View
@@ -178,11 +178,12 @@ v8::Handle<v8::Value> AsyncReadFile(const v8::Arguments &args) {
}
AsyncBaton *baton = new AsyncBaton;
+ baton->request.data = baton;
baton->path = 0;
baton->format = TagLib::String::null;
baton->stream = 0;
+ baton->error = 0;
- baton->request.data = baton;
if (args[0]->IsString()) {
String::Utf8Value path(args[0]->ToString());
baton->path = strdup(*path);
@@ -194,7 +195,6 @@ v8::Handle<v8::Value> AsyncReadFile(const v8::Arguments &args) {
baton->stream = new BufferStream(args[0]->ToObject());
baton->callback = Persistent<Function>::New(Local<Function>::Cast(args[2]));
}
- baton->error = 0;
uv_queue_work(uv_default_loop(), &baton->request, AsyncReadFileDo, AsyncReadFileAfter);

0 comments on commit e99682e

Please sign in to comment.