Permalink
Browse files

Merge branch 'buffers'

  • Loading branch information...
2 parents c1dc443 + e99682e commit 8e9fdb55c36d24955a0ceee351e69075f2c7d20c @nikhilm committed May 29, 2012
Showing with 589 additions and 77 deletions.
  1. +21 −3 README.md
  2. +259 −0 spec/buffersSpec.js
  3. +72 −0 src/bufferstream.cc
  4. +37 −0 src/bufferstream.h
  5. +66 −20 src/tag.cc
  6. +0 −1 src/tag.h
  7. +116 −49 src/taglib.cc
  8. +15 −1 src/taglib.h
  9. +1 −1 test.sh
  10. +2 −2 wscript
View
@@ -58,6 +58,7 @@ The `examples` show usage.
## API
### read(path, callback)
+### read(buffer, format, callback)
The function you will most likely want to use. `callback` should have signature
`callback(err, tag, audioProperties)` where `tag` and `audioProperties` are
@@ -90,7 +91,11 @@ integers:
Writing audio properties is not supported.
+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
@@ -99,11 +104,18 @@ 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)
-Read the tag from the file at `path` _synchronously_. Returns a `Tag`. If
+Read the tags from the file at `path` _synchronously_. Returns a `Tag`. If
errors occurred, throws an exception.
+Read the tags from `buffer` assuming that it is a `format` file. See
+[Formats](#formats)
+
### Tag
**NOTE: A Tag object should *NOT* be created using `new`. Instead use `tag()`
@@ -135,7 +147,8 @@ will be `null` if the save was successful, otherwise it will be an object with
### Tag.saveSync()
-Save any changes in the Tag meta-data to disk _synchronously_.
+Save any changes in the Tag meta-data to disk _synchronously_. Throws an
+exception if the save failed.
### Tag.isEmpty()
@@ -149,7 +162,12 @@ last resolver will be called first. Multiple calls to `addResolvers` are
allowed.
Each resolver must be a JavaScript function which takes a `filename` parameter
-and returns a format `string`. The string must be one of (case-insensitive):
+and returns a format `string`. List of [formats](#formats).
+
+### Formats {#formats}
+
+Any place where `node-taglib` expects a format can be passed on of these
+(case-insensitive):
"MPEG"
"OGG" - Ogg Vorbis
View
@@ -0,0 +1,259 @@
+var assert = require('assert'),
+ vows = require('vows'),
+ fs = require('fs'),
+ Taglib = require(__dirname + '/../taglib');
+
+vows.describe('taglib bindings: Buffers')
+.addBatch({
+ 'reading metadata from mp3 buffer': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.read(buf, 'mpeg', this.callback);
+ },
+
+ 'should be called with three arguments': function (err, tag, props) {
+ assert.isNull(err);
+ assert.isObject(tag);
+ assert.isObject(props);
+ },
+
+ 'reading tags': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.read(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.");
+ }
+ },
+
+ 'reading audioProperties': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/blip.mp3');
+ Taglib.read(buf, 'mpeg', this.callback);
+ },
+
+ 'should have length 1 second': function(err, _, prop) {
+ assert.equal(prop.length, 1);
+ },
+ 'should have bitrate 128kbps': function(err, _, prop) {
+ assert.equal(prop.bitrate, 128);
+ },
+ 'should have sampleRate 44100Hz': function(err, _, prop) {
+ assert.equal(prop.sampleRate, 44100);
+ },
+ 'should have 2 channels': function(err, _, prop) {
+ assert.equal(prop.channels, 2);
+ }
+ },
+ },
+
+ 'reading data from a buffer with unknown format': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.read(buf, '', this.callback);
+ },
+
+ 'should raise an error': function(err, _, _) {
+ assert.isNotNull(err);
+ assert.match(err.message, /Unknown file format/);
+ }
+ },
+
+ 'reading data from a buffer with wrong format': {
+ topic: function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ Taglib.read(buf, 'ogg', this.callback);
+ },
+
+ 'should raise an error': function(err, _, _) {
+ assert.isNotNull(err);
+ assert.match(err.message, /Failed to extract tags/);
+ }
+ },
+
+ 'reading data from empty buffer': {
+ topic: function() {
+ var buf = new Buffer(0);
+ Taglib.read(buf, 'mpeg', this.callback);
+ },
+
+ 'should lead to empty tags and properties': function(err, tag, prop) {
+ assert.isNull(err);
+ assert.isEmpty(tag);
+ assert.isObject(prop);
+ }
+ },
+
+ /* * 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() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ return Taglib.tagSync(buf, 'mpeg');
+ },
+
+ '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.");
+ }
+ },
+
+ 'tagSync data from a buffer with unknown format': {
+ topic: function() {
+ return function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ return Taglib.tagSync(buf, '', this.callback);
+ }
+ },
+
+ 'should raise an error': function(topic) {
+ assert.throws(topic, /Unknown file format/);
+ }
+ },
+
+ 'tagSync data from a buffer with wrong format': {
+ topic: function() {
+ return function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ return Taglib.tagSync(buf, 'ogg');
+ }
+ },
+
+ 'should raise an error': function(topic) {
+ assert.throws(topic, /Failed to extract tags/);
+ }
+ },
+
+ 'tagSync data from empty buffer': {
+ topic: function() {
+ var buf = new Buffer(0);
+ return Taglib.tagSync(buf, 'mpeg');
+ },
+
+ 'should lead to empty tags': function(tag) {
+ assert.isObject(tag);
+ }
+ },
+
+ 'writing to a tag from a buffer': {
+ topic: function() {
+ return function() {
+ var buf = fs.readFileSync(__dirname+'/sample.mp3');
+ var tag = Taglib.tagSync(buf, 'mpeg');
+ tag.artist = 'nsm';
+ tag.saveSync();
+ }
+ },
+
+ 'should fail': function(topic) {
+ assert.throws(topic);
+ }
+ }
+}).export(module);
View
@@ -0,0 +1,72 @@
+#include "bufferstream.h"
+
+#include <node_buffer.h>
+
+#include "taglib.h"
+
+using namespace v8;
+using namespace node;
+using namespace node_taglib;
+
+namespace node_taglib {
+BufferStream::BufferStream(Handle<Object> buffer)
+ : TagLib::IOStream()
+ , m_data(Buffer::Data(buffer))
+ , m_length(Buffer::Length(buffer))
+ , m_offset(0)
+{
+}
+
+BufferStream::~BufferStream()
+{
+}
+
+TagLib::ByteVector BufferStream::readBlock(TagLib::ulong length) {
+ long start = m_offset;
+ m_offset += length;
+ return TagLib::ByteVector(m_data, m_length).mid(start, length);
+}
+
+void BufferStream::writeBlock(const TagLib::ByteVector &data) {
+ fprintf(stderr, "writeBlock called aborting\n");
+ abort();
+}
+
+void BufferStream::insert(const TagLib::ByteVector &data, TagLib::ulong start, TagLib::ulong replace) {
+ fprintf(stderr, "insert called aborting\n");
+ abort();
+}
+
+void BufferStream::removeBlock(TagLib::ulong start, TagLib::ulong length) {
+ fprintf(stderr, "removeBlock called aborting\n");
+ abort();
+}
+
+void BufferStream::seek(long offset, TagLib::IOStream::Position p) {
+ if (p == TagLib::IOStream::Beginning) {
+ m_offset = offset;
+ }
+ else if (p == TagLib::IOStream::Current) {
+ m_offset += offset;
+ }
+ else if (p == TagLib::IOStream::End) {
+ m_offset = length() + offset;
+ }
+}
+
+void BufferStream::clear() {
+}
+
+long BufferStream::tell() const {
+ return m_offset;
+}
+
+long BufferStream::length() {
+ return m_length;
+}
+
+void BufferStream::truncate(long length) {
+ fprintf(stderr, "truncate called aborting\n");
+ abort();
+}
+}
Oops, something went wrong.

0 comments on commit 8e9fdb5

Please sign in to comment.