diff --git a/app.js b/app.js index 434b9c0..4cb22b7 100644 --- a/app.js +++ b/app.js @@ -91,9 +91,16 @@ app.get('/callback', function (req, res) { refresh_token = body.refresh_token; // we can also pass the token to the browser to make requests from there - res.send('') + res.redirect('/#' + + querystring.stringify({ + access_token: access_token, + refresh_token: refresh_token + })); } else { - res.send('') + res.redirect('/#' + + querystring.stringify({ + error: 'invalid_token' + })); } }); } diff --git a/public/index.html b/public/index.html index 2fcd3b1..905efbe 100644 --- a/public/index.html +++ b/public/index.html @@ -9,50 +9,17 @@ - -
- -
+
- - - - + + + + - + diff --git a/public/partials/dups.html b/public/partials/dups.html deleted file mode 100644 index b8b63d7..0000000 --- a/public/partials/dups.html +++ /dev/null @@ -1,8 +0,0 @@ -

Duplicates in {{playlistName}}

-
Loading...
-
No duplicate found
-
-
- {{t.track.name}} - {{artist == t.track.artists[0]?'':', '}}{{artist.name}} -
-
\ No newline at end of file diff --git a/public/partials/home.html b/public/partials/home.html deleted file mode 100644 index c80bb30..0000000 --- a/public/partials/home.html +++ /dev/null @@ -1 +0,0 @@ -

Please connect to Spotify to access to the app.

\ No newline at end of file diff --git a/public/partials/logged.html b/public/partials/logged.html deleted file mode 100644 index 050450b..0000000 --- a/public/partials/logged.html +++ /dev/null @@ -1,4 +0,0 @@ -
-
-
-
\ No newline at end of file diff --git a/public/partials/playlist.html b/public/partials/playlist.html deleted file mode 100644 index 09b8638..0000000 --- a/public/partials/playlist.html +++ /dev/null @@ -1,8 +0,0 @@ -
-

Playlist

-
-
- - {{playlist.name}} - -
\ No newline at end of file diff --git a/public/script.js b/public/script.js index c139d1a..0ec532e 100644 --- a/public/script.js +++ b/public/script.js @@ -1,156 +1,293 @@ 'use strict'; -(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; +} - var app = angular.module('app',['ui.router', 'ngStorage']); - - app.config(['$stateProvider','$urlRouterProvider',function($stateProvider, $urlRouterProvider){ - $stateProvider - .state('finder_public',{ - templateUrl:'partials/home.html', - url: '/', - controller: 'HomeCtrl' - }) - .state('finder',{ - abstract: true, - templateUrl:'partials/logged.html', - url: '/finder', - controller: 'MainCtrl' - }) - .state('finder.playlist',{ - url: '/playlist', - views: { - playlist:{ - templateUrl: 'partials/playlist.html', - controller: 'PlaylistCtrl' - }, - dups:{ - template: '' - } - } - }) - .state('finder.playlist.dups',{ - url: '/:uid/:id/:playlist', - views: { - 'dups@finder': { - templateUrl: 'partials/dups.html', - controller: 'DupsCtrl' - } - } - }); - $urlRouterProvider.otherwise("/"); - }]); - - app.run(['$rootScope', '$state', '$localStorage',function($rootScope, $state, $localStorage){ - $rootScope.$storage = $localStorage.$default({ - access_token: "", - refresh_token: "" +var Duplicate = React.createClass({ + render: function () { + var authors = ""; + this.props.track.artists.forEach(function (item, index) { + if (index != 0) { + authors += ', '; + } + authors += item.name; }); - $rootScope.access_token = $rootScope.$storage.access_token; - $rootScope.refresh_token = $rootScope.$storage.refresh_token; + return ( +
{this.props.track.name} - {authors}
+ ); + } +}); - $rootScope.$watch('access_token', function(newVal, oldVal, scope){ +var DuplicatesBox = React.createClass({ + render: function () { + if (this.props.dups && this.props.dups.length > 0) { + var duplicates = this.props.dups.map(function (duplicate) { + return ( + + ); + }); + return ( +
+ {duplicates} +
+ ); + } + else { + return ( +

No duplicate found

+ ); + } + } +}); - $rootScope.$storage.access_token = $rootScope.access_token; - $rootScope.$storage.refresh_token = $rootScope.refresh_token; - if(oldVal == "" && newVal != ""){ - $state.go('finder.playlist'); - } else if (oldVal != "" && newVal == ""){ - $state.go('finder_public'); +var PlaylistBox = React.createClass({ + getInitialState: function () { + return { + currentId: null + }; + }, + clickOnItem: function (id, uid) { + this.setState({currentId: id}); + this.props.handleClick(id, uid); + }, + render: function () { + var currentId = this.state.currentId; + var playlists; + if (this.props.playlists) { + playlists = this.props.playlists.map(function (pl) { + var id = pl.id; + var classes = "list-group-item" + (currentId == id ? " active" : ""); + return ( + {pl.name} + ); + }, this); + } + return ( +
+ {playlists} +
+ ); + } +}); + +var DuplicateFinderBox = React.createClass({ + getInitialState: function () { + return { + currentId: null, + currentUId: null, + dups: null, + dupsLoading: false + }; + }, + handlePlaylistClick: function (id, uid) { + this.setState({ + currentId: id, + currentUId: uid, + dupsLoading: true + }); + var self = this; + + $.ajax({ + url: "/pl/" + uid + "/" + id, + data: { + 'access_token': self.props.auth.access_token + }, + success: function (data) { + var dups = data.data; + self.setState({ + dups: dups, + dupsLoading: false + }); + }, + error: function (xhr, response, err) { + console.error(response, err); } }); - $rootScope.$on('$stateChangeStart', - function (event, toState) { - if ((toState.name != "finder_public") && $rootScope.access_token == "") { - event.preventDefault(); - $state.go('finder_public'); - } - }); - }]); - - app.controller("HomeCtrl",['$scope',function($scope){ - - }]); - - app.controller("MainCtrl",['$scope', '$state',function($scope, $state){ - $scope.current = {playlistId: undefined}; - }]); - - app.controller("PlaylistCtrl",['$scope', '$http', '$state',function($scope, $http, $state){ - $scope.playlists = []; - $scope.load = function(){ - $http.get('/get_playlists', { - params:{ - access_token: $scope.access_token - } - }).then(function(result){ - var r = result.data; - if(r.data){ - $scope.playlists = r.data; - } - }) - }; - $scope.open = function(playlist) { - $scope.current.playlistId = playlist.id; - $state.go('finder.playlist.dups',{uid: playlist.owner.id, id: playlist.id, playlist: encodeURIComponent(playlist.name)}) - }; - $scope.load(); - }]); - - app.controller("DupsCtrl",['$scope', '$stateParams', '$http',function($scope, $stateParams, $http){ - $scope.uid = $stateParams['uid']; - $scope.id = $stateParams['id']; - $scope.playlistName = decodeURIComponent($stateParams.playlist); - $scope.current.playlistId = $scope.id; - $scope.tracks = []; - $scope.loaded = false; - $scope.load = function () { - $http.get('/pl/' + $scope.uid + '/' + $scope.id, { - params: { - access_token: $scope.access_token - } - }).then(function(result) { - var r = result.data; - $scope.tracks = r.data; - $scope.loaded = true; - }); - }; - $scope.load(); - }]); - - app.controller('AuthCtrl',['$scope', '$rootScope', '$interval', '$http', function($scope, $rootScope, $interval, $http){ - $scope.login = function(){ - var openUrl = '/login'; - window.$windowScope = $scope; - $scope.popup = window.open(openUrl, "Authenticate Account", "width=500, height=500"); - var checker = $interval(function(){ - if($scope.popup.closed){ - $interval.cancel(checker); - } else if ($scope.popup.token != undefined && $scope.popup.token != null) { - $rootScope.access_token = $scope.popup.token.access_token; - $rootScope.refresh_token = $scope.popup.token.refresh_token; - $scope.popup.close(); - $interval.cancel(checker); - } - }, 500); - return false; - }; - $scope.logout = function(){ - $rootScope.refresh_token = ""; - $rootScope.access_token = ""; - }; - $scope.refresh = function(){ - if($rootScope.refresh_token) - $http.get('/refresh_token',{params: {refresh_token: $rootScope.refresh_token}}) - .then(function(result){ - $rootScope.access_token = result.data.access_token || ""; - }, function(failResult){ - $rootScope.access_token = ""; - $rootScope.refresh_token = ""; - }); - return false; + }, + render: function () { + var duplicates =

Loading...

; + if (!this.state.dupsLoading) { + duplicates = ; } - }]) + var playlistBox =

Loading...

; + if (!this.props.playlistsLoading) { + playlistBox = ; + } + return ( +
+
+

Playlists

+ {playlistBox} +
+
+

Duplicates

+ {duplicates} +
+
+ ); + } +}); -})(); \ No newline at end of file +var Authenticate = React.createClass({ + logout: function () { + this.props.refreshAuth(null, null); + }, + refreshToken: function (event) { + event.preventDefault(); + var self = this; + $.ajax({ + url: '/refresh_token', + data: { + 'refresh_token': self.props.auth.refresh_token + }, + success: function (data) { + self.props.refreshAuth(data.access_token, self.props.auth.refresh_token); + }, + error: function (xhr, status, err) { + console.error(status, err); + } + }); + }, + render: function () { + var auth; + if (this.props.auth.access_token == null) { + auth = ( + + ); + } + else { + auth = ( + + ); + } + + return ( + + ); + } +}); + +var App = React.createClass({ + getInitialState: function () { + var params = getHashParams(); + var access_token = params.access_token || null; + var refresh_token = params.refresh_token || null; + + return { + access_token: access_token, + refresh_token: refresh_token, + playlists: null, + playlistsLoading: true + }; + }, + getPlaylists: function () { + this.setState({ + playlistsLoading: true + }); + var self = this; + $.ajax({ + url: '/get_playlists', + data: { + 'access_token': this.state.access_token + }, + success: function (data) { + var pl = data.data; + self.setState({ + playlists: pl, + playlistsLoading: false + }); + }, + error: function (xhr, response, err) { + console.error(response, err); + } + }); + }, + isLoggedIn: function () { + return !(this.state.access_token == null && this.state.refresh_token == null); + }, + refreshAuth: function (access, refresh) { + this.setState({ + access_token: access, + refresh_token: refresh + }); + + if (!(access == null && refresh == null)) { + this.getPlaylists(); + } + }, + componentDidMount: function () { + if (this.isLoggedIn()) { + this.getPlaylists(); + } + }, + render: function () { + var auth = { + access_token: this.state.access_token, + refresh_token: this.state.refresh_token + }; + var content =

Please log in with Spotify :)

; + if (this.isLoggedIn()) { + var playlistsLoading = this.state.playlistsLoading; + content = ( + + ); + } + + return ( +
+ +
+ {content} +
+
+ ); + } +}); + +ReactDOM.render( + , + document.getElementById('content') +);