Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

beginning on searches

  • Loading branch information...
commit 59acc0122eda8d6370395a417d5940bbe85256aa 1 parent c4c0515
@Floby authored
View
70 lib/Search.js
@@ -0,0 +1,70 @@
+var b = require('bindings')('spotify.node');
+var Session = require('./Session');
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var format = require('format').format;
+
+/**
+ * This class allows to run searches on the spotify database
+ * You can either create it from a string or specify single fields
+ * with the adequate methods
+ * @constructor
+ * @param {Session} session, the session to attach this search to (optional)
+ * @param {String} search, a query to run (optional)
+ */
+function Search (session, query) {
+ if(session && session instanceof Session) {
+ this._session = session;
+ }
+ else {
+ this._session = Session.currentSession;
+ }
+
+ this._query = query || (typeof session == 'string') ? session : null;
+
+ this._sp_search = null;
+}
+util.inherits(Search, EventEmitter);
+
+/**
+ * actually run the search. When the search is complete
+ * the event 'ready' is triggered
+ */
+Search.prototype.execute = function execute() {
+ this._sp_search = b.search_create(
+ this._session._sp_session,
+ this._query,
+ this.trackOffset || 0,
+ this.trackCount || 1,
+ this.albumOffset || 0,
+ this.albumCount || 0,
+ this.artistOffset || 0,
+ this.artistCount || 0,
+ this.playlistOffset || 0,
+ this.playlistCount || 0
+ );
+
+ var self = this;
+ this._sp_search.on_search_complete = function(err, search) {
+ if(err) {
+ return self.emit('error', err);
+ }
+ if(search != self._sp_search) {
+ return;
+ }
+
+ self._processResults(search);
+
+ return self.emit('ready', self);
+ }
+};
+
+Search.prototype._processResults = function _processResults(search) {
+ this.tracks = new Array(b.search_num_tracks(this._sp_search));
+ this.artists = [];
+ this.albums = [];
+ this.playlists = [];
+};
+
+
+module.exports = Search;
View
17 lib/Session.js
@@ -118,9 +118,11 @@ function sessionCallback (session, cb) {
Session.prototype._setupNativeCallbacks = function _setupNativeCallbacks() {
var self = this;
this._sp_session.logged_in = sessionCallback(this, function(err) {
+ self._logged_in = true;
self.emit('login', err);
});
this._sp_session.logged_out = sessionCallback(this, function() {
+ self._logged_in = false;
self.emit('logout');
});
};
@@ -135,10 +137,8 @@ Session.prototype._startProcessingEvents = function _startProcessingEvents() {
if(this._process_events_timeout) return;
var self = this;
this._process_events_timeout = setInterval(sessionCallback(this, function() {
- //console.log('processing events', id);
var next_timeout = b.session_process_events(self._sp_session);
- //console.log('processing again in %d', next_timeout);
- }), 800);
+ }), 10);
};
/**
@@ -159,13 +159,20 @@ Session.prototype.isClosed = function isClosed() {
};
/**
- * tests if the current sessino is open
+ * tests if the current session is open
*/
Session.prototype.isOpen = function isOpen() {
return !this.isClosed();
};
/**
+ * tests if the current session is logged in
+ */
+Session.prototype.isLoggedIn = function isLoggedIn() {
+ return this._logged_in == true;
+};
+
+/**
* try to login with the given credentials
* when this request is processed by libspotify, the 'login' event is
* fired with an error or null as first argument
@@ -186,7 +193,7 @@ Session.prototype.login = function login(login, password) {
Session.prototype.logout = function logout(cb) {
b.session_logout(this._sp_session);
if(typeof cb === 'function') {
- this.on('logout', cb)
+ this.once('logout', cb)
}
};
View
1  lib/libspotify.js
@@ -1,2 +1,3 @@
exports.Session = require('./Session');
+exports.Search = require('./Search');
View
1  src/binding.cc
@@ -27,6 +27,7 @@ extern "C" {
// initializing all modules
nsp::init_session(target);
+ nsp::init_search(target);
}
}
View
4 src/common.h
@@ -123,6 +123,10 @@ namespace nsp {
* init the session related functions to the target module exports
*/
void init_session(v8::Handle<v8::Object> target);
+ /**
+ * init the search related functions to the target module exports
+ */
+ void init_search(v8::Handle<v8::Object> target);
/**
* This utility class allows to keep track of a C pointer that we attached
View
112 src/search.cc
@@ -0,0 +1,112 @@
+/*
+ * =====================================================================================
+ *
+ * Filename: search.cc
+ *
+ * Description: bindings to the spotify search submodule
+ *
+ * Version: 1.0
+ * Created: 23/12/2012 16:59:00
+ * Revision: none
+ * Compiler: gcc
+ *
+ * Author: Florent Jaby (FJ), florent.jaby@gmail.com
+ * Company: Florent Jaby
+ *
+ * =====================================================================================
+ */
+
+
+#include "common.h"
+
+using namespace v8;
+using namespace nsp;
+
+/**
+ * Spotify callback when a search query completed
+ */
+static void on_search_complete(sp_search* result, void* userdata) {
+ ObjectHandle<sp_search>* search = static_cast<ObjectHandle<sp_search>* >(userdata);
+ Handle<Value> cbv = search->object->Get(String::New("on_search_complete"));
+ if(!cbv->IsFunction()) {
+ return;
+ }
+
+ Handle<Function> cb = Local<Function>(Function::Cast(*cbv));
+ const unsigned int argc = 2;
+ sp_error error = sp_search_error(result);
+ Handle<Value> err = Null();
+ if(error != SP_ERROR_OK) {
+ err = Exception::Error(String::New(sp_error_message(error)));
+ }
+ Local<Value> argv[argc] = { Local<Value>::New(err), Local<Object>::New(search->object) };
+ cb->Call(Context::GetCurrent()->Global(), argc, argv);
+
+ return;
+}
+
+/**
+ * JS search_create implementation. calls sp_search_create
+ */
+static Handle<Value> Search_Create(const Arguments& args) {
+ HandleScope scope;
+
+ // check arguments sanity
+ assert(args.Length() == 10);
+ assert(args[0]->IsObject());
+ assert(args[1]->IsString());
+ assert(args[2]->IsNumber());
+ assert(args[3]->IsNumber());
+ assert(args[4]->IsNumber());
+ assert(args[5]->IsNumber());
+ assert(args[6]->IsNumber());
+ assert(args[7]->IsNumber());
+ assert(args[8]->IsNumber());
+ assert(args[9]->IsNumber());
+
+ // unwrap the session handle from the given object
+ ObjectHandle<sp_session>* session = ObjectHandle<sp_session>::Unwrap(args[0]);
+
+ // create the new handle for the sp_search we are creating
+ ObjectHandle<sp_search>* search = new ObjectHandle<sp_search>("sp_search");
+ String::Utf8Value query(args[1]);
+
+ // actually call sp_search_create
+ search->pointer = sp_search_create(
+ session->pointer,
+ *query,
+ args[2]->ToNumber()->Int32Value(),
+ args[3]->ToNumber()->Int32Value(),
+ args[4]->ToNumber()->Int32Value(),
+ args[5]->ToNumber()->Int32Value(),
+ args[6]->ToNumber()->Int32Value(),
+ args[7]->ToNumber()->Int32Value(),
+ args[8]->ToNumber()->Int32Value(),
+ args[9]->ToNumber()->Int32Value(),
+ SP_SEARCH_STANDARD,
+ &on_search_complete,
+ search
+ );
+
+ return scope.Close(search->object);
+}
+
+/**
+ * JS search_num_tracks implementation.
+ */
+static Handle<Value> Search_Num_Tracks(const Arguments& args) {
+ HandleScope scope;
+
+ assert(args.Length() == 1);
+ assert(args[0]->IsObject());
+
+ ObjectHandle<sp_search>* search = ObjectHandle<sp_search>::Unwrap(args[0]);
+ int num = sp_search_num_tracks(search->pointer);
+
+ return scope.Close(Number::New(num));
+}
+
+void nsp::init_search(Handle<Object> target) {
+ NODE_SET_METHOD(target, "search_create", Search_Create);
+ NODE_SET_METHOD(target, "search_num_tracks", Search_Num_Tracks);
+}
View
10 test/test-010-session02-login.js
@@ -19,15 +19,15 @@ exports.testLoginIsSucessful = function(test) {
session.name = 'chose';
session.login(cred.login, cred.password);
console.log('trying to login, this may take a while');
- var logged = false;
- setTimeout(function() {
- if(!logged) {
+ var log_timeout = setTimeout(function() {
+ if(!session.isLoggedIn()) {
test.done(new Error("Waited too long for login"));
}
}, 10000);
session.on('login', function(err) {
- test.equal(null, err, err + ' occured on login');
- logged = true;
+ if(err) test.done(err);
+ test.ok(session.isLoggedIn(), 'session should now it is now logged in');
+ clearTimeout(log_timeout);
session.logout(function() {
session.close();
test.done();
View
38 test/test-020-search-01-create.js
@@ -0,0 +1,38 @@
+var sp = require('../lib/libspotify');
+var cred = require('../spotify_key/passwd');
+var testutil = require('./util');
+var trycatch = require('trycatch');
+
+var session = null;
+
+var search = {
+ setUp: function(cb) {
+ testutil.getDefaultTestSession(function(s) {
+ session = s;
+ cb();
+ })
+ },
+
+ testSearchFromString: function(test) {
+ var search = null;
+ test.doesNotThrow(function() {
+ search = new sp.Search("Bogus search terms");
+ search.on('ready', function() {
+ test.ok(search.tracks.length == 0, "there should be not many results");
+ test.done();
+ });
+ search.execute();
+ });
+ },
+
+ testSearchGuillemotsSongFound: function(test) {
+ var search = new sp.Search('artist:"Guillemots" track:"Fleet"');
+ search.on('ready', function() {
+ test.ok(search.tracks.length > 0, "the search should return at least one result");
+ test.done();
+ });
+ search.execute();
+ },
+};
+
+exports.search = search;
View
12 test/test-999-cleanup.js
@@ -0,0 +1,12 @@
+var u = require('./util');
+
+exports.cleanup = function(test) {
+ u.getDefaultTestSession(function(s) {
+ s.logout(function() {
+ s.close();
+ test.done();
+ })
+ });
+
+}
+
View
24 test/util.js
@@ -0,0 +1,24 @@
+var sp = require('../lib/libspotify');
+var cred = require('../spotify_key/passwd');
+
+var session = null
+exports.getDefaultTestSession = function(cb) {
+ if(session instanceof sp.Session) {
+ if(session.isLoggedIn()) {
+ setTimeout(function() {
+ cb(session);
+ });
+ return;
+ }
+ }
+ else {
+ session = new sp.Session({
+ applicationKey: __dirname + '/../spotify_key/spotify_appkey.key'
+ });
+ session.login(cred.login, cred.password);
+ }
+ session.once('login', function(err) {
+ if(err) throw err;
+ cb(session);
+ });
+}
Please sign in to comment.
Something went wrong with that request. Please try again.