2016-04-17 11:21:26 +02:00
<!doctype html>
< html >
< head >
< title > Spotify Duplicate Finder< / title >
< link rel = "stylesheet" href = "//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" >
2016-04-17 15:35:54 +02:00
< link rel = "stylesheet" href = "https://netdna.bootstrapcdn.com/font-awesome/3.0.2/css/font-awesome.css" >
2016-04-17 11:21:26 +02:00
< style type = "text/css" >
#login, #loggedin {
display: none;
}
.text-overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 500px;
}
2016-04-17 15:35:54 +02:00
.spinner {
display: inline-block;
opacity: 0;
width: 0;
-webkit-transition: opacity 0.25s, width 0.25s;
-moz-transition: opacity 0.25s, width 0.25s;
-o-transition: opacity 0.25s, width 0.25s;
transition: opacity 0.25s, width 0.25s;
}
.has-spinner.loading .spinner {
opacity: 1;
width: auto; /* This doesn't work, just fix for unkown width elements */
}
.has-spinner.btn-mini.loading .spinner {
width: 10px;
}
.has-spinner.btn-small.loading .spinner {
width: 13px;
}
.has-spinner.btn.loading .spinner {
width: 16px;
}
.has-spinner.btn-large.loading .spinner {
width: 19px;
}
2016-04-17 11:21:26 +02:00
< / style >
< / head >
< body >
< div class = "container" >
< div id = "login" >
< h1 > This is an example of the Authorization Code flow< / h1 >
< a href = "/login" class = "btn btn-primary" > Log in with Spotify< / a >
< / div >
< div id = "loggedin" >
< div id = "user-profile" >
< / div >
< h1 > Duplicates finder< / h1 >
2016-04-17 15:35:54 +02:00
< button class = "btn btn-default has-spinner" id = "get-playlists" > Get playlists < span class = "spinner" > < i class = "icon-spin icon-refresh" > < / i > < / span > < / button >
2016-04-17 12:46:27 +02:00
< div class = "media" >
< div class = "pull-left" >
< div id = "playlists" >
< / div >
< / div >
< div class = "media-body" >
< div id = "dups" >
< / div >
2016-04-17 11:21:26 +02:00
< / div >
< / div >
< / div >
< / div >
< script id = "user-profile-template" type = "text/x-handlebars-template" >
< h1 > Logged in as {{display_name}}< / h1 >
2016-04-17 12:46:27 +02:00
< div id = "oauth" >
2016-04-17 11:21:26 +02:00
< / div >
2016-04-17 15:35:54 +02:00
< button class = "btn btn-default has-spinner" id = "obtain-new-token" > Obtain new token using the refresh token < span class = "spinner" > < i class = "icon-spin icon-refresh" > < / i > < / span > < / button >
2016-04-17 11:21:26 +02:00
< / script >
< script id = "oauth-template" type = "text/x-handlebars-template" >
< h2 > oAuth info< / h2 >
< dl class = "dl-horizontal" >
< dt > Access token< / dt >
< dd class = "text-overflow" > {{access_token}}< / dd >
< dt > Refresh token< / dt >
< dd class = "text-overflow" > {{refresh_token}}>< / dd >
< / dl >
< / script >
< script id = "dups-template" type = "text/x-handlebars-template" >
< h2 > Duplicates in {{pl_name}}< / h2 >
{{message}}
2016-04-17 12:55:53 +02:00
{{#list dups}}< div class = "list-group-item" > {{dup_trackname}} - {{dup_artist}}< / div > {{/list}}
2016-04-17 11:21:26 +02:00
< / script >
< script id = "playlists-template" type = "text/x-handlebars-template" >
< h2 > Playlists< / h2 >
2016-04-17 15:35:54 +02:00
{{#list playlists}}< a class = "pl_item list-group-item btn has-spinner" href = "/pl/{{pl_uid}}/{{pl_id}}" > {{pl_name}} < span class = "spinner" > < i class = "icon-spin icon-refresh" > < / i > < / span > < / a > {{/list}}
2016-04-17 11:21:26 +02:00
< / script >
< script src = "//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0-alpha.1/handlebars.min.js" > < / script >
< script src = "https://code.jquery.com/jquery-1.12.3.min.js" > < / script >
< script >
(function () {
/**
* Obtains parameters from the hash of the URL
* @return Object
*/
function getHashParams() {
var hashParams = {};
var e, r = /([^&; =]+)=?([^&; ]*)/g,
q = window.location.hash.substring(1);
while (e = r.exec(q)) {
hashParams[e[1]] = decodeURIComponent(e[2]);
}
return hashParams;
}
Handlebars.registerHelper('list', function (items, options) {
2016-04-17 12:55:53 +02:00
var out = "< div class = 'list-group' > ";
2016-04-17 11:21:26 +02:00
for (var i = 0, l = items.length; i < l ; i + + ) {
2016-04-17 12:55:53 +02:00
out = out + options.fn(items[i]);
2016-04-17 11:21:26 +02:00
}
2016-04-17 12:55:53 +02:00
return out + "< / div > ";
2016-04-17 11:21:26 +02:00
});
var userProfileSource = document.getElementById('user-profile-template').innerHTML,
userProfileTemplate = Handlebars.compile(userProfileSource),
userProfilePlaceholder = document.getElementById('user-profile');
var playlistsSource = document.getElementById('playlists-template').innerHTML,
playlistsTemplate = Handlebars.compile(playlistsSource),
playlistsPlaceholder = document.getElementById('playlists');
var dupsSource = document.getElementById('dups-template').innerHTML,
dupsTemplate = Handlebars.compile(dupsSource),
dupsPlaceholder = document.getElementById('dups');
2016-04-17 12:46:27 +02:00
var oauthSource;
var oauthTemplate;
var oauthPlaceholder;
2016-04-17 11:21:26 +02:00
var params = getHashParams();
var access_token = params.access_token,
refresh_token = params.refresh_token,
error = params.error;
if (error) {
alert('There was an error during the authentication');
} else {
if (access_token) {
$.ajax({
url: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': 'Bearer ' + access_token
},
success: function (response) {
userProfilePlaceholder.innerHTML = userProfileTemplate(response);
2016-04-17 12:46:27 +02:00
oauthSource = document.getElementById('oauth-template').innerHTML;
oauthTemplate = Handlebars.compile(oauthSource);
oauthPlaceholder = document.getElementById('oauth');
// render oauth info
oauthPlaceholder.innerHTML = oauthTemplate({
access_token: access_token,
refresh_token: refresh_token
});
2016-04-17 11:21:26 +02:00
$('#login').hide();
$('#loggedin').show();
}
});
} else {
// render initial screen
$('#login').show();
$('#loggedin').hide();
}
document.getElementById('get-playlists').addEventListener('click', function () {
2016-04-17 15:35:54 +02:00
var currentElement = $(this);
currentElement.addClass('loading');
2016-04-17 11:21:26 +02:00
$.ajax({
url: '/get_playlists',
data: {
'access_token': access_token
}
}).done(function (data) {
var pl = data.data.map(function (item, index, array) {
return {
2016-04-17 12:46:27 +02:00
pl_uid: item.owner.id,
pl_name: item.name,
pl_id: item.id
2016-04-17 11:21:26 +02:00
}
});
2016-04-17 15:35:54 +02:00
currentElement.removeClass('loading');
2016-04-17 11:21:26 +02:00
playlistsPlaceholder.innerHTML = playlistsTemplate({
playlists: pl
});
})
}, false);
$(document).on('click', '.pl_item', function (e) {
e.preventDefault();
var pl_name = $(this).text();
2016-04-17 12:59:12 +02:00
$('.pl_item').removeClass('active');
2016-04-17 15:35:54 +02:00
var currentElement = $(this);
currentElement.addClass('active');
currentElement.addClass('loading');
2016-04-17 11:21:26 +02:00
$.ajax({
url: $(this).attr('href'),
data: {
'access_token': access_token
}
}).done(function (data) {
var dups = data.data.map(function (item) {
return {
dup_trackname: item.track.name,
dup_artist: item.track.artists[0].name
}
});
2016-04-17 15:35:54 +02:00
currentElement.removeClass('loading');
2016-04-17 11:21:26 +02:00
if (data.data.length > 0) {
dupsPlaceholder.innerHTML = dupsTemplate({
2016-04-17 12:46:27 +02:00
dups: dups,
pl_name: pl_name
2016-04-17 11:21:26 +02:00
});
}
else {
dupsPlaceholder.innerHTML = dupsTemplate({
2016-04-17 12:46:27 +02:00
dups: [],
2016-04-17 11:21:26 +02:00
message: "No duplicate found.",
pl_name: pl_name
});
}
})
});
2016-04-17 12:46:27 +02:00
$(document).on('click', '#obtain-new-token', function () {
2016-04-17 15:35:54 +02:00
var button = $(this);
button.addClass('loading');
2016-04-17 11:21:26 +02:00
$.ajax({
url: '/refresh_token',
data: {
'refresh_token': refresh_token
}
}).done(function (data) {
access_token = data.access_token;
2016-04-17 15:35:54 +02:00
button.removeClass('loading');
2016-04-17 11:21:26 +02:00
oauthPlaceholder.innerHTML = oauthTemplate({
access_token: access_token,
refresh_token: refresh_token
});
});
2016-04-17 12:46:27 +02:00
});
2016-04-17 11:21:26 +02:00
}
})();
< / script >
< / body >
< / html >