').appendTo($player),
$controls = $('').appendTo($player),
$list = $('').appendTo($player);
// add the classes of the source node to the player itself
// the players can be indvidually styled this way
if(sourceClasses || opts.customClass){
$player.addClass(sourceClasses).addClass(opts.customClass);
}
// adding controls to the player
$player
.find('.sc-controls')
.append('PlayPause')
.end()
.append('Info')
.append('')
.find('.sc-scrubber')
.append('
')
.append('
')
.append('
|
');
// load and parse the track data from SoundCloud API
loadTracksData($player, links, opts.apiKey);
// init the player GUI, when the tracks data was laoded
$player.bind('onTrackDataLoaded.scPlayer', function(event) {
// log('onTrackDataLoaded.scPlayer', event.playerObj, playerId, event.target);
var tracks = event.playerObj.tracks;
if (opts.randomize) {
tracks = shuffle(tracks);
}
// create the playlist
$.each(tracks, function(index, track) {
var active = index === 0;
// create an item in the playlist
$('
').data('sc-track', {id:index}).toggleClass('active', active).appendTo($list);
// create an item in the artwork list
$('')
.append(artworkImage(track, index >= opts.loadArtworks))
.appendTo($artworks)
.toggleClass('active', active)
.data('sc-track', track);
});
// update the element before rendering it in the DOM
$player.each(function() {
if($.isFunction(opts.beforeRender)){
opts.beforeRender.call(this, tracks);
}
});
// set the first track's duration
$('.sc-duration', $player)[0].innerHTML = timecode(tracks[0].duration);
$('.sc-position', $player)[0].innerHTML = timecode(0);
// set up the first track info
updateTrackInfo($player, tracks[0]);
// if continous play enabled always skip to the next track after one finishes
if (opts.continuePlayback) {
$player.bind('onPlayerTrackFinish', function(event) {
onSkip($player);
});
}
// announce the succesful initialization
$player
.removeClass('loading')
.trigger('onPlayerInit');
// if auto play is enabled and it's the first player, start playing
if(opts.autoPlay && !didAutoPlay){
onPlay($player);
didAutoPlay = true;
}
});
// replace the DOM source (if there's one)
$source.each(function(index) {
$(this).replaceWith($player);
});
return $player;
};
// stop all players, might be useful, before replacing the player dynamically
$.scPlayer.stopAll = function() {
$('.sc-player.playing a.sc-pause').click();
};
// destroy all the players and audio engine, usefull when reloading part of the page and audio has to stop
$.scPlayer.destroy = function() {
$('.sc-player, .sc-player-engine-container').remove();
};
// plugin wrapper
$.fn.scPlayer = function(options) {
// reset the auto play
didAutoPlay = false;
// create the players
this.each(function() {
$.scPlayer(options, this);
});
return this;
};
// default plugin options
$.scPlayer.defaults = $.fn.scPlayer.defaults = {
customClass: null,
// do something with the dom object before you render it, add nodes, get more data from the services etc.
beforeRender : function(tracksData) {
var $player = $(this);
},
// initialization, when dom is ready
onDomReady : function() {
$('a.sc-player, div.sc-player').scPlayer();
},
autoPlay: false,
continuePlayback: true,
randomize: false,
loadArtworks: 5,
// the default Api key should be replaced by your own one
// get it here http://soundcloud.com/you/apps/new
apiKey: 'htuiRd1JP11Ww0X72T1C3g'
};
// the GUI event bindings
//--------------------------------------------------------
// toggling play/pause
$(document).on('click','a.sc-play, a.sc-pause', function(event) {
var $list = $(this).closest('.sc-player').find('ol.sc-trackslist');
// simulate the click in the tracklist
$list.find('li.active').click();
return false;
});
// displaying the info panel in the player
$(document).on('click','a.sc-info-toggle, a.sc-info-close', function(event) {
var $link = $(this);
$link.closest('.sc-player')
.find('.sc-info').toggleClass('active').end()
.find('a.sc-info-toggle').toggleClass('active');
return false;
});
// selecting tracks in the playlist
$(document).on('click','.sc-trackslist li', function(event) {
var $track = $(this),
$player = $track.closest('.sc-player'),
trackId = $track.data('sc-track').id,
play = $player.is(':not(.playing)') || $track.is(':not(.active)');
if (play) {
onPlay($player, trackId);
}else{
onPause($player);
}
$track.addClass('active').siblings('li').removeClass('active');
$('.artworks li', $player).each(function(index) {
$(this).toggleClass('active', index === trackId);
});
return false;
});
var scrub = function(node, xPos) {
var $scrubber = $(node).closest('.sc-time-span'),
$buffer = $scrubber.find('.sc-buffer'),
$available = $scrubber.find('.sc-waveform-container img'),
$player = $scrubber.closest('.sc-player'),
relative = Math.min($buffer.width(), (xPos - $available.offset().left)) / $available.width();
onSeek($player, relative);
};
var onTouchMove = function(ev) {
if (ev.targetTouches.length === 1) {
scrub(ev.target, ev.targetTouches && ev.targetTouches.length && ev.targetTouches[0].clientX);
ev.preventDefault();
}
};
// seeking in the loaded track buffer
$(document)
.on('click','.sc-time-span', function(event) {
scrub(this, event.pageX);
return false;
})
.on('touchstart','.sc-time-span', function(event) {
this.addEventListener('touchmove', onTouchMove, false);
event.originalEvent.preventDefault();
})
.on('touchend','.sc-time-span', function(event) {
this.removeEventListener('touchmove', onTouchMove, false);
event.originalEvent.preventDefault();
});
// changing volume in the player
var startVolumeTracking = function(node, startEvent) {
var $node = $(node),
originX = $node.offset().left,
originWidth = $node.width(),
getVolume = function(x) {
return Math.floor(((x - originX)/originWidth)*100);
},
update = function(event) {
$doc.trigger({type: 'scPlayer:onVolumeChange', volume: getVolume(event.pageX)});
};
$node.bind('mousemove.sc-player', update);
update(startEvent);
};
var stopVolumeTracking = function(node, event) {
$(node).unbind('mousemove.sc-player');
};
$(document)
.on('mousedown','.sc-volume-slider', function(event) {
startVolumeTracking(this, event);
})
.on('mouseup','.sc-volume-slider', function(event) {
stopVolumeTracking(this, event);
});
$doc.bind('scPlayer:onVolumeChange', function(event) {
$('span.sc-volume-status').css({width: event.volume + '%'});
});
// -------------------------------------------------------------------
// the default Auto-Initialization
$(function() {
if($.isFunction($.scPlayer.defaults.onDomReady)){
$.scPlayer.defaults.onDomReady();
}
});
})(jQuery);