%PDF- %PDF-
| Direktori : /data/www_bck/varak.net_bck/gnufm.varak.net/js/ |
| Current File : //data/www_bck/varak.net_bck/gnufm.varak.net/js/player.js |
/*
GNU FM -- a free network service for sharing your music listening habits
Copyright (C) 2009 Free Software Foundation, Inc
@licstart The following is the entire license notice for the
JavaScript code in this page.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
@licend The above is the entire license notice
for the JavaScript code in this page.
*/
var audio;
var dlbutton;
var scrobbled, now_playing, tracktoptags;
var artist, album, track, trackpage, radio_key, ws_key, api_key, station;
var playlist = [], current_song = 0;
var player_ready = false;
var playable_songs = false;
var streaming = false;
var error_count = 0;
var base_url = base_url || "";
/**
* Initialises the javascript player (player.tpl must also be included on the target page)
*
* @param array list A playlist in the form ([artist, album, track, trackurl, trackpage], [...]) or false if playing a radio stream
* @param string wk Web service session key or false if the user isn't logged in
* @param string rk Radio session key or false if streaming isn't required or user is logged in
* @param string stationurl Station to tune to if user is logged in.
* @param string gnufm_key GNU FM api key (should be set in config.php)
*/
function playerInit(list, ws, rk, stationurl, gnufm_key) {
audio = document.getElementById("audio");
dlbutton = document.getElementById("dlbutton");
if (!list) {
// We're playing a stream instead of a playlist
streaming = true;
}
api_key = gnufm_key;
ws_key = ws;
radio_key = ws_key || rk;
station = stationurl || false;
if(typeof audio.duration == "undefined") {
//Browser doesn't support <audio>
if(streaming) {
$("#audio").replaceWith("<p>Sorry, you need a browser capable of using the HTML 5 <audio> element to enjoy the streaming service via the Javascript player.</p>");
}
return;
}
// Get rid of the fallback embed, otherwise some html5 browsers will play it in addition to the js player
$("#fallbackembed").remove();
// Make "Player problems?" clickable and hide problems box
$('#toggleproblems').css({'text-decoration' : 'underline', 'cursor':'pointer'});
$('#toggleproblems').on('click', function() {
$('#player #problems').slideToggle(500);
});
$('#player #problems').hide();
// Display a message while waiting for player to get ready
$('#player #loading').text('Readying player and fetching playlist, this may take a while..');
if (streaming) {
// Logged in users need to tune to station
if(!rk && station) {
tune(station);
} else {
// Get playlist from radio service
getRadioPlaylist();
}
} else {
// Otherwise we have a static playlist
playlist = list;
playerReady();
}
}
/**
* Finishes the player initialisation when the playlist has been loaded
*/
function playerReady() {
populatePlaylist();
if(!playable_songs) {
return;
}
loadSong(0);
audio.pause();
audio.addEventListener("ended", songEnded, false);
audio.addEventListener("error", songError, false);
updateProgress();
/**
* Set initial element properties
*/
$('#skipback').on('click', skipBack);
$('#seekback').on('click', seekBack);
$('#seekback').fadeTo("normal", 0.5);
//$('#seekback').hide();
$('#seekforward').on('click', seekForward);
$('#seekforward').fadeTo("normal", 0.5);
//$('#seekforward').hide();
$('#skipforward').on('click', skipForward);
$('#showplaylist').on('click', togglePlaylist);
$('#playlist').hide();
$('#hideplaylist').on('click', togglePlaylist);
$('#hideplaylist').hide();
$('#scrobbled').hide();
$('#play').on('click', play);
$("#play").fadeTo("normal", 1);
$('#pause').on('click', pause);
$("#pause").hide();
$('#volume').on('click', toggleVolume);
$("#volume").fadeTo("normal", 1);
$('#volume-box').hide();
$("#volume-slider").slider({range: "min", min: 0, max: 100, value: 60, slide: setVolume});
loadVolume();
$("#progress-slider").slider({
value:0, range: "min", min:0, max:100, slide: function(event, progress) {
setProgress(progress.value);
}
});
if (ws_key) {
// Logged in
$('#artistname').addClass('tunebutton');
$('#artistname').prop('title', 'Tune to artist station');
$('#artistname').on('click', function(event) {
var artistname = event.target.textContent;
var artiststation = 'librefm://artist/' + artistname;
tune(artiststation);
});
$('#tracktags ul').on('click', 'li', function(event) {
var tagname = event.target.textContent;
var tagstation = 'librefm://globaltags/' + tagname;
tune(tagstation);
});
$("#ban").fadeTo("normal", 1);
$('#ban').on('click', ban);
$('#love').on('click', love);
$("#love").fadeTo("normal", 1);
$('#open_tag').on('click', toggleTag);
$("#open_tag").fadeTo("normal", 1);
$('#close_tag').on('click', toggleTag);
$('#close_tag').hide();
$('#tag_input').on('submit', function(event) {
event.preventDefault();
tag();
});
$('#tag_input').hide();
} else {
// Not logged in
$('#tracktags').remove();
$('#ban').remove();
$('#love').remove();
$('#close_tag').remove();
$('#open_tag').remove();
$('#tag_input').remove();
}
$('#player #loading').remove();
$("#player > #interface").show();
player_ready = true;
}
/**
* Set progress of currently loaded track
*
* @param value Number between 0 and 100
*/
function setProgress(value) {
try {
audio.currentTime = audio.duration * (value / 100);
} catch (e) {}
}
/**
* Begins playback
*/
function play() {
audio.play();
$("#play").hide();
$("#pause").show();
$("#seekforward").fadeTo("normal", 1);
$("#seekback").fadeTo("normal", 1);
}
/**
* Pauses playback
*/
function pause() {
audio.pause();
$("#play").show();
$("#pause").hide();
$("#seekforward").fadeTo("normal", 0.5);
$("#seekback").fadeTo("normal", 0.5);
}
/**
* Seeks backwards 10 seconds in the current song
*/
function seekBack() {
try {
audio.currentTime = audio.currentTime - 10;
} catch (e) {}
}
/**
* Seeks forwards 10 seconds in the current song
*/
function seekForward() {
try {
audio.currentTime = audio.currentTime + 10;
} catch (e) {}
}
/**
* Updates the progress bar every 900 milliseconds
*/
function updateProgress() {
if (audio.duration > 0) {
$("#progress-slider").slider('option', 'value', (audio.currentTime / audio.duration) * 100);
$("#duration").text(friendlyTime(audio.duration));
} else {
$("#duration").text(friendlyTime(0));
}
if(!now_playing && audio.currentTime > 0) {
error_count = 0;
nowPlaying();
}
if(ws_key && !tracktoptags) {
trackGetTopTags();
tracktoptags = true;
}
if (!scrobbled && audio.currentTime > audio.duration / 2) {
scrobble();
}
$("#currenttime").text(friendlyTime(audio.currentTime));
setTimeout("updateProgress()", 900)
}
/**
* Called automatically when a song finished. Loads the next song if there is one
*/
function songEnded() {
if(current_song == playlist.length - 1) {
pause();
} else {
loadSong(current_song+1);
play();
}
}
/**
* Called automatically when a song returns an error.
* Loads the next song after a delay or does nothing if there has been several song errors in a row.
*/
function songError() {
if (error_count < 10 ) {
error_count = error_count + 1;
setTimeout("songEnded()", 3000);
}
}
/**
* Outputs the HTML playlist
*/
function populatePlaylist() {
var i, url;
//Clear the list
$("#playlist > #songs").text("");
for(i = 0; i < playlist.length; i++) {
url = playlist[i]["url"];
// Remove non-streamable tracks
if (url == "") {
playlist.pop(song); // hur, pop song.
} else {
playable_songs = true;
}
$("#playlist > #songs").append("<li id='song-" + i + "'><a href='#' onclick='playSong(" + i + "); return false;'>" + playlist[i]["artist"] + " - " + playlist[i]["track"] + "</li>");
}
$("#song-" + current_song).css({fontWeight : "bold"});
}
/**
* Shows/Hides the HTML playlist display
*/
function togglePlaylist() {
$("#playlist").slideToggle(1000);
$("#showplaylist").toggle();
$("#hideplaylist").toggle();
}
/**
* Submits a scrobble for the current song if a scrobble session key has been
* provided. Makes use of a simple proxy to support installations where the
* gnukebox installation is at a different domain/sub-domain to the nixtape
* installation.
*/
function scrobble() {
var timestamp;
scrobbled = true;
if(!ws_key) {
//Not authenticated
return;
}
timestamp = Math.round(new Date().getTime() / 1000);
$.post(base_url + '/2.0/', { 'method':'track.scrobble', 'artist':artist, 'album':album, 'track':track, 'duration':audio.duration, 'timestamp':timestamp, 'sk':ws_key, 'api_key':api_key, 'format':'json'},
function(data){
if('scrobbles' in data) {
$("#scrobbled").text("Scrobbled");
$("#scrobbled").fadeIn(5000, function() { $("#scrobbled").fadeOut(5000) } );
} else {
$("#scrobbled").text(data);
$("#scrobbled").fadeIn(1000);
}
}, 'json');
}
/**
* Submits 'now playing' data to the gnukebox server. Like scrobble() this
* makes use of a proxy.
*/
function nowPlaying() {
var timestamp;
now_playing = true;
if(!ws_key) {
//Not authenticated
return;
}
timestamp = Math.round(new Date().getTime() / 1000);
$.post(base_url + '/2.0/', { 'method':'track.updatenowplaying', 'artist':artist, 'album':album, 'track':track, 'duration':audio.duration, 'sk':ws_key, 'api_key':api_key}, function(data) {}, "text");
}
/**
* Tune to a station
*
* @param string station Station URL
*/
function tune(station) {
$.post(base_url + '/2.0/', {'method' : 'radio.tune', 'sk' : ws_key, 'station' : station, 'format' : 'json'},
function(data) {
if ('station' in data) {
// remove any future tracks in playlist and add tracks from new station
playlist = playlist.slice(0, current_song + 1);
getRadioPlaylist();
// set streaming to true to get player to fetch more songs if needed
streaming = true;
}
}, 'json');
}
/**
* Get top tags for current track
*
*/
function trackGetTopTags() {
$.get(base_url + '/2.0/', {'method' : 'track.gettoptags', 'artist' : artist, 'track' : track, 'format' : 'json'}, function(data) {
if('toptags' in data) {
var tag_items = data.toptags.tag;
if ('name' in tag_items) {
// not an array
var tagname = tag_items.name;
$('#tracktags ul').append('<li class="tunebutton" title="Tune to tag station">' + tagname + '</li>');
}else{
var i;
var max_length = 50;
var tags_length = 0;
for(i in tag_items) {
var tagname = tag_items[i].name;
tags_length = tags_length + tagname.length + 1;
//limit total length for tags
if (tags_length <= max_length) {
$('#tracktags ul').append('<li class="tunebutton" title="Tune to tag station">' + tagname + '</li>');
}else{
break;
}
}
}
}
}, 'json');
}
/**
* Loads a song and beings playing it.
*
* @param int song The song number in the playlist that should be played
*/
function playSong(song) {
loadSong(song);
play();
}
/**
* Loads a song
*
* @param int song The song number in the playlist that should be loaded
*/
function loadSong(song) {
try {
var url = playlist[song]["url"];
artist = playlist[song]["artist"];
album = playlist[song]["album"];
track = playlist[song]["track"];
trackpage = playlist[song]["trackpage"];
} catch (e) {
// Handle a possible TypeError when song < 0 or song >= playlist.length
return;
}
// Highlight current song in the playlist
$("#song-" + current_song).css({fontWeight : "normal"});
$("#song-" + song).css({fontWeight : "bold"});
current_song = song;
scrobbled = false;
now_playing = false;
audio.src = url;
dlbutton.href = url;
audio.load();
if(streaming && current_song > playlist.length - 3) {
//Update the playlist before the user reaches the end
getRadioPlaylist();
}
if(current_song > 0) {
$("#skipback").fadeTo("normal", 1.0);
} else {
$("#skipback").fadeTo("normal", 0.5);
}
if(current_song < playlist.length - 1) {
$("#skipforward").fadeTo("normal", 1.0);
} else {
$("#skipforward").fadeTo("normal", 0.5);
}
$("#trackinfo > #artistname").text(artist);
$("#trackinfo > #trackname").text(track);
$("#ban").fadeTo("normal", 1);
$("#love").fadeTo("normal", 1);
if($("#flattrstream")) {
$.getJSON(base_url + '/2.0/', {'method' : 'artist.getflattr', 'artist' : artist, 'format' : 'json'}, updateFlattr);
}
// remove tags for previous track
$('#tracktags ul li').remove();
tracktoptags = false;
}
function updateFlattr(data) {
var flattr_uid = data.flattr.flattr_uid;
if (flattr_uid) {
$("#flattr").empty();
$("#flattr").html('<a class="FlattrButton" style="display:none;" title="' + artist + ' - ' + track + '" rev="flattr;uid:' + flattr_uid + ';category:audio;tags:music,creative commons,free,libre.fm;" href="' + trackpage + '">' + artist + ' is making ' + track + ' freely available on Libre.fm for you to listen to, share and remix however you like.</a>');
FlattrLoader.setup();
$("#flattrstream").show(1000);
} else {
$("#flattrstream").hide(1000);
}
}
/**
* Retrieves a playlist from the radio streaming service.
* A radio session key must be supplied when initialising
* the play for this to work.
*/
function getRadioPlaylist() {
var tracks, artist, album, title, url, extension, trackpage_url, i;
$.get(base_url + "/2.0/", {'method' : 'radio.getPlaylist', 'sk' : radio_key}, function(data) {
parser=new DOMParser();
xmlDoc=parser.parseFromString(data,"text/xml");
tracks = xmlDoc.getElementsByTagName("track")
for(i = 0; i < tracks.length; i++) {
try {
artist = tracks[i].getElementsByTagName("creator")[0].childNodes[0].nodeValue;
title = tracks[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
album = tracks[i].getElementsByTagName("album")[0].childNodes[0].nodeValue;
url = tracks[i].getElementsByTagName("location")[0].childNodes[0].nodeValue;
trackpage_url = tracks[i].getElementsByTagName("trackpage")[0].childNodes[0].nodeValue;
if(checkDupe(playlist, artist, title) === false) {
playlist.push({"artist" : artist, "album" : album, "track" : title, "url" : url, "trackpage" : trackpage_url});
}
} catch(err) {
}
}
if(!player_ready) {
playerReady();
} else {
populatePlaylist();
// Re-enable the skip forward button now that we have more tracks
$("#skipforward").fadeTo("normal", 1.0);
}
}, "text");
}
/**
* Check if track is already in playlist
*
* @param array Playlist array
* @param creator Track creator (artist name)
* @param title Track title
*/
function checkDupe(playlist, creator, title) {
var i;
var pl = playlist.slice(-40); //only check against 40 latest tracks in playlist
for(i in pl) {
if(pl[i].artist === creator && pl[i].track === title) {
return i;
}
}
return false;
}
/**
* Plays the song previous to the current one in the playlist
*/
function skipBack() {
playSong(current_song - 1);
}
/**
* Plays the song after the current one in the playlist
*/
function skipForward() {
playSong(current_song + 1);
}
/**
* Converts a timestamp to "MM:SS" format.
*
* @param int timestamp A timestamp in seconds.
* @return string The provided time in "MM:SS" format
*/
function friendlyTime(timestamp) {
mins = Math.floor(timestamp / 60);
sec = String(Math.floor(timestamp % 60));
if(sec.length == 1) { sec = "0" + sec }
return mins + ":" + sec
}
function love() {
$.post(base_url + "/2.0/", {'method' : 'track.love', 'artist' : artist, 'track' : track, 'sk' : ws_key}, function(data) {}, "text");
$("#love").fadeTo("normal", 0.5);
$("#scrobbled").text("Loved");
$("#scrobbled").fadeIn(5000, function() { $("#scrobbled").fadeOut(5000) } );
}
function ban() {
$.post(base_url + "/2.0/", {'method' : 'track.ban', 'artist' : artist, 'track' : track, 'sk' : ws_key}, function(data) {}, "text");
$("#ban").fadeTo("normal", 0.5);
skipForward();
}
function toggleTag() {
$("#tag_input").slideToggle(500);
$("#open_tag").toggle();
$("#close_tag").toggle();
}
function tag() {
var tags = $("#tags").val();
if (tags != "") {
$.post(base_url + "/2.0/", {'method' : 'track.addtags', 'artist' : artist, 'track' : track, 'tags' : tags, 'sk' : ws_key}, function(data) {}, "text");
toggleTag();
$("#tags").val("");
}
}
/**
* Toggle visibility of the volume slider
*/
function toggleVolume() {
$("#volume-box").slideToggle(500);
}
/**
* Set the player volume and store it in a cookie for future sessions
*/
function setVolume(event, vol) {
audio.volume = parseFloat(vol.value / 100);
var date = new Date();
date.setTime(date.getTime()+(315360000000)); // Remember for 10 years
document.cookie='volume=' + audio.volume + '; expires='+date.toGMTString()+ '; path=/';
}
/**
* Load the player volume from a cookie
*/
function loadVolume() {
volume = getCookie('volume');
if(volume == undefined) {
return;
}
volume = parseFloat(volume);
$("#volume-slider").slider('value', volume * 100);
audio.volume = volume;
}
/**
* Retrieve the contents of a cookie
*/
function getCookie(c_name)
{
var i,x,y,ARRcookies=document.cookie.split(";");
for (i=0;i<ARRcookies.length;i++)
{
x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
x=x.replace(/^\s+|\s+$/g,"");
if (x==c_name)
{
return unescape(y);
}
}
}