2014-03-12 14:52:47 +01:00
|
|
|
/*
|
|
|
|
|
|
|
|
Jappix - An open social platform
|
|
|
|
These are the music JS scripts for Jappix
|
|
|
|
|
|
|
|
-------------------------------------------------
|
|
|
|
|
|
|
|
License: AGPL
|
|
|
|
Author: Valérian Saliou
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Bundle
|
|
|
|
var Music = (function () {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alias of this
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
var self = {};
|
|
|
|
|
|
|
|
|
2014-04-08 20:14:28 +02:00
|
|
|
/**
|
2014-03-12 14:52:47 +01:00
|
|
|
* Opens the music bubble
|
|
|
|
* @public
|
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
self.open = function() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
var path = '.music-content';
|
|
|
|
|
|
|
|
// Show the music bubble
|
|
|
|
Bubble.show(path);
|
|
|
|
|
|
|
|
$(document).oneTime(10, function() {
|
|
|
|
$(path + ' input').focus();
|
|
|
|
});
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.open', e);
|
|
|
|
} finally {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses the music search XML
|
|
|
|
* @public
|
|
|
|
* @param {string} xml
|
|
|
|
* @param {string} type
|
|
|
|
* @return {undefined}
|
|
|
|
*/
|
|
|
|
self.parse = function(xml, type) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
var path = '.music-content ';
|
|
|
|
var content = path + '.list';
|
|
|
|
var path_type = content + ' .' + type;
|
|
|
|
|
|
|
|
// Create the result container
|
|
|
|
if(!Common.exists(path_type)) {
|
|
|
|
var code = '<div class="' + type + '"></div>';
|
|
|
|
|
2014-11-25 20:12:58 +01:00
|
|
|
if(type == 'local') {
|
2014-03-12 14:52:47 +01:00
|
|
|
$(content).prepend(code);
|
2014-11-25 20:12:58 +01:00
|
|
|
} else {
|
2014-03-12 14:52:47 +01:00
|
|
|
$(content).append(code);
|
2014-11-25 20:12:58 +01:00
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fill the results
|
|
|
|
$(xml).find('track').each(function() {
|
|
|
|
// Parse the XML
|
2014-11-25 20:12:58 +01:00
|
|
|
var this_sel = $(this);
|
|
|
|
|
|
|
|
var id = this_sel.find('id').text() || hex_md5(uri);
|
|
|
|
var title = this_sel.find('name').text();
|
|
|
|
var artist = this_sel.find('artist').text();
|
|
|
|
var source = this_sel.find('source').text();
|
|
|
|
var duration = this_sel.find('duration').text();
|
|
|
|
var uri = this_sel.find('url').text();
|
|
|
|
var mime = this_sel.find('type').text() || 'audio/ogg';
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// Local URL?
|
2014-11-25 20:12:58 +01:00
|
|
|
if(type == 'local') {
|
2014-03-12 14:52:47 +01:00
|
|
|
uri = Utils.generateURL(uri);
|
2014-11-25 20:12:58 +01:00
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// Append the HTML code
|
|
|
|
$(path_type).append('<a href="#" class="song" data-id="' + id + '">' + title + '</a>');
|
|
|
|
|
|
|
|
// Current playing song?
|
|
|
|
var current_song = $(path_type + ' a[data-id="' + id + '"]');
|
|
|
|
|
2014-11-25 20:12:58 +01:00
|
|
|
if(Common.exists('.music-audio[data-id="' + id + '"]')) {
|
2014-03-12 14:52:47 +01:00
|
|
|
current_song.addClass('playing');
|
2014-11-25 20:12:58 +01:00
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// Click event
|
|
|
|
current_song.click(function() {
|
|
|
|
return self.add(id, title, artist, source, duration, uri, mime, type);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// The search is finished
|
|
|
|
if(Common.exists(content + ' .jamendo') && Common.exists(content + ' .local')) {
|
|
|
|
// Get the result values
|
|
|
|
var jamendo = $(content + ' .jamendo').text();
|
|
|
|
var local = $(content + ' .local').text();
|
|
|
|
|
|
|
|
// Enable the input
|
|
|
|
$(path + 'input').val('').removeAttr('disabled');
|
|
|
|
|
|
|
|
// No result
|
2014-11-25 20:12:58 +01:00
|
|
|
if(!jamendo && !local) {
|
2014-03-12 14:52:47 +01:00
|
|
|
$(path + '.no-results').show();
|
2014-11-25 20:12:58 +01:00
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// We must put a separator between the categories
|
2014-11-25 20:12:58 +01:00
|
|
|
if(jamendo && local) {
|
2014-03-12 14:52:47 +01:00
|
|
|
$(content + ' .local').addClass('special');
|
2014-11-25 20:12:58 +01:00
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
}
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.parse', e);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends the music search requests
|
|
|
|
* @public
|
|
|
|
* @return {undefined}
|
|
|
|
*/
|
|
|
|
self.search = function() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
var path = '.music-content ';
|
|
|
|
|
|
|
|
// We get the input string
|
|
|
|
var string = $(path + 'input').val();
|
|
|
|
|
|
|
|
// We lock the search input
|
|
|
|
$(path + 'input').attr('disabled', true);
|
|
|
|
|
|
|
|
// We reset the results
|
|
|
|
$(path + '.list div').remove();
|
|
|
|
$(path + '.no-results').hide();
|
|
|
|
|
|
|
|
// Get the Jamendo results
|
|
|
|
$.get('./server/music-search.php', {searchquery: string, location: 'jamendo'}, function(data) {
|
|
|
|
self.parse(data, 'jamendo');
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get the local results
|
2014-11-25 20:12:58 +01:00
|
|
|
$.get('./server/music-search.php', {
|
|
|
|
searchquery: string,
|
|
|
|
location: JAPPIX_LOCATION
|
|
|
|
}, function(data) {
|
2014-03-12 14:52:47 +01:00
|
|
|
self.parse(data, 'local');
|
|
|
|
});
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.search', e);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs an action on the music player
|
|
|
|
* @public
|
|
|
|
* @param {string} action
|
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
self.action = function(action) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Initialize
|
2014-11-25 20:12:58 +01:00
|
|
|
var audio_sel = document.getElementById('top-content').getElementsByTagName('audio')[0];
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// Nothing to play, exit
|
2014-11-25 20:12:58 +01:00
|
|
|
if(!audio_sel) {
|
2014-03-12 14:52:47 +01:00
|
|
|
return false;
|
2014-11-25 20:12:58 +01:00
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
var stopButton = $('#top-content a.stop');
|
|
|
|
|
|
|
|
// User play a song
|
|
|
|
if(action == 'play') {
|
|
|
|
stopButton.show();
|
2014-11-25 20:12:58 +01:00
|
|
|
audio_sel.load();
|
|
|
|
audio_sel.play();
|
|
|
|
|
|
|
|
audio_sel.addEventListener('ended', function() {
|
2014-03-12 14:52:47 +01:00
|
|
|
self.action('stop');
|
|
|
|
}, true);
|
|
|
|
|
|
|
|
Console.log('Music is now playing.');
|
2014-11-25 20:12:58 +01:00
|
|
|
} else if(action == 'stop') {
|
|
|
|
// User stop the song / end of song
|
2014-03-12 14:52:47 +01:00
|
|
|
stopButton.hide();
|
2014-11-25 20:12:58 +01:00
|
|
|
audio_sel.pause();
|
|
|
|
|
2014-03-12 14:52:47 +01:00
|
|
|
$('#top-content .music').removeClass('actived');
|
|
|
|
$('.music-content .list a').removeClass('playing');
|
|
|
|
$('.music-audio').remove();
|
2014-11-25 20:12:58 +01:00
|
|
|
|
2014-03-12 14:52:47 +01:00
|
|
|
self.publish();
|
|
|
|
|
|
|
|
Console.log('Music is now stopped.');
|
|
|
|
}
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.action', e);
|
|
|
|
} finally {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Publishes the current title over PEP
|
|
|
|
* @public
|
|
|
|
* @param {string} title
|
|
|
|
* @param {string} artist
|
|
|
|
* @param {string} source
|
|
|
|
* @param {string} duration
|
|
|
|
* @param {string} uri
|
|
|
|
* @return {undefined}
|
|
|
|
*/
|
|
|
|
self.publish = function(title, artist, source, duration, uri) {
|
|
|
|
|
|
|
|
/* REF: http://xmpp.org/extensions/xep-0118.html */
|
|
|
|
|
|
|
|
try {
|
|
|
|
// We share the tune on PEP if enabled
|
|
|
|
if(Features.enabledPEP()) {
|
|
|
|
var iq = new JSJaCIQ();
|
|
|
|
iq.setType('set');
|
|
|
|
|
|
|
|
// Create the main PubSub nodes
|
|
|
|
var pubsub = iq.appendNode('pubsub', {'xmlns': NS_PUBSUB});
|
|
|
|
var publish = pubsub.appendChild(iq.buildNode('publish', {'node': NS_TUNE, 'xmlns': NS_PUBSUB}));
|
|
|
|
var item = publish.appendChild(iq.buildNode('item', {'xmlns': NS_PUBSUB}));
|
|
|
|
var tune = item.appendChild(iq.buildNode('tune', {'xmlns': NS_TUNE}));
|
|
|
|
|
|
|
|
// Enough data?
|
|
|
|
if(title || artist || source || uri) {
|
2014-11-25 20:12:58 +01:00
|
|
|
var music_data = {
|
|
|
|
'title': title,
|
|
|
|
'artist': artist,
|
|
|
|
'source': source,
|
|
|
|
'length': length,
|
|
|
|
'uri': uri
|
|
|
|
};
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// Create the children nodes
|
2014-11-25 20:12:58 +01:00
|
|
|
var cur_value;
|
|
|
|
|
|
|
|
for(var cur_name in music_data) {
|
|
|
|
cur_value = music_data[cur_name];
|
|
|
|
|
|
|
|
if(cur_value) {
|
|
|
|
tune.appendChild(iq.buildNode(cur_name, {
|
|
|
|
'xmlns': NS_TUNE
|
|
|
|
}, cur_value));
|
2014-03-12 14:52:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
con.send(iq);
|
|
|
|
|
|
|
|
Console.info('New tune sent: ' + title);
|
|
|
|
}
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.publish', e);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-04-08 20:14:28 +02:00
|
|
|
/**
|
2014-03-12 14:52:47 +01:00
|
|
|
* Adds a music title to the results
|
|
|
|
* @public
|
|
|
|
* @param {string} id
|
|
|
|
* @param {string} title
|
|
|
|
* @param {string} artist
|
|
|
|
* @param {string} source
|
|
|
|
* @param {string} duration
|
|
|
|
* @param {string} uri
|
|
|
|
* @param {string} mime
|
|
|
|
* @param {string} type
|
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
self.add = function(id, title, artist, source, duration, uri, mime, type) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
var path = '.music-content ';
|
2014-11-25 20:12:58 +01:00
|
|
|
var music_audio_sel = $('.music-audio');
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// We remove & create a new audio tag
|
2014-11-25 20:12:58 +01:00
|
|
|
music_audio_sel.remove();
|
2014-03-12 14:52:47 +01:00
|
|
|
$(path + '.player').prepend('<audio class="music-audio" type="' + mime + '" data-id="' + id + '" />');
|
|
|
|
|
|
|
|
// We apply the new source to the player
|
2014-11-25 20:12:58 +01:00
|
|
|
if(type == 'jamendo') {
|
|
|
|
music_audio_sel.attr('src', 'http://api.jamendo.com/get2/stream/track/redirect/?id=' + id + '&streamencoding=ogg2');
|
|
|
|
} else {
|
|
|
|
music_audio_sel.attr('src', uri);
|
|
|
|
}
|
2014-03-12 14:52:47 +01:00
|
|
|
|
|
|
|
// We play the target sound
|
|
|
|
self.action('play');
|
|
|
|
|
|
|
|
// We set the actived class
|
|
|
|
$('#top-content .music').addClass('actived');
|
|
|
|
|
|
|
|
// We set a current played track indicator
|
|
|
|
$(path + '.list a').removeClass('playing');
|
|
|
|
$(path + 'a[data-id="' + id + '"]').addClass('playing');
|
|
|
|
|
|
|
|
// We publish what we listen
|
|
|
|
self.publish(title, artist, source, duration, uri);
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.add', e);
|
|
|
|
} finally {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Plugin launcher
|
|
|
|
* @public
|
|
|
|
* @param {type} name
|
|
|
|
* @return {undefined}
|
|
|
|
*/
|
|
|
|
self.instance = function() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
// When music search string submitted
|
|
|
|
$('.music-content input').keyup(function(e) {
|
|
|
|
// Enter : send
|
|
|
|
if(e.keyCode == 13 && $(this).val()) {
|
|
|
|
self.search();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Escape : quit
|
|
|
|
if(e.keyCode == 27) {
|
|
|
|
Bubble.close();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch(e) {
|
|
|
|
Console.error('Music.instance', e);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return class scope
|
|
|
|
*/
|
|
|
|
return self;
|
|
|
|
|
|
|
|
})();
|