diff --git a/.gitignore b/.gitignore index c2658d7..f26df0f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,83 @@ node_modules/ + +# Created by https://www.gitignore.io/api/webstorm,node + +### WebStorm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..f6c6870 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node bin/www diff --git a/app.js b/app.js new file mode 100644 index 0000000..4a08b9b --- /dev/null +++ b/app.js @@ -0,0 +1,200 @@ +/** + * This is an example of a basic node.js script that performs + * the Authorization Code oAuth2 flow to authenticate against + * the Spotify Accounts. + * + * For more information, read + * https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow + */ + +var express = require('express'); // Express web server framework +var request = require('request'); // "Request" library +var querystring = require('querystring'); +var cookieParser = require('cookie-parser'); + +var client_id = process.env.CLIENT_ID; // Your client id +var client_secret = process.env.CLIENT_SECRET; // Your client secret +var redirect_uri = process.env.CALLBACK; // Your redirect uri + +/** + * Generates a random string containing numbers and letters + * @param {number} length The length of the string + * @return {string} The generated string + */ +var generateRandomString = function (length) { + var text = ''; + var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + + for (var i = 0; i < length; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +}; + +var stateKey = 'spotify_auth_state'; + +var app = express(); + +app.use(express.static(__dirname + '/public')) + .use(cookieParser()); + +app.get('/login', function (req, res) { + + var state = generateRandomString(16); + res.cookie(stateKey, state); + + // your application requests authorization + var scope = 'user-read-private user-read-email playlist-modify-private playlist-read-private playlist-read-collaborative'; + res.redirect('https://accounts.spotify.com/authorize?' + + querystring.stringify({ + response_type: 'code', + client_id: client_id, + scope: scope, + redirect_uri: redirect_uri, + state: state + })); +}); + +app.get('/callback', function (req, res) { + + // your application requests refresh and access tokens + // after checking the state parameter + + var code = req.query.code || null; + var state = req.query.state || null; + var storedState = req.cookies ? req.cookies[stateKey] : null; + + if (state === null || state !== storedState) { + res.redirect('/#' + + querystring.stringify({ + error: 'state_mismatch' + })); + } else { + res.clearCookie(stateKey); + var authOptions = { + url: 'https://accounts.spotify.com/api/token', + form: { + code: code, + redirect_uri: redirect_uri, + grant_type: 'authorization_code' + }, + headers: { + 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) + }, + json: true + }; + + request.post(authOptions, function (error, response, body) { + if (!error && response.statusCode === 200) { + + var access_token = body.access_token, + refresh_token = body.refresh_token; + + // we can also pass the token to the browser to make requests from there + res.redirect('/#' + + querystring.stringify({ + access_token: access_token, + refresh_token: refresh_token + })); + } else { + res.redirect('/#' + + querystring.stringify({ + error: 'invalid_token' + })); + } + }); + } +}); + +app.get('/refresh_token', function (req, res) { + + // requesting access token from refresh token + var refresh_token = req.query.refresh_token; + var authOptions = { + url: 'https://accounts.spotify.com/api/token', + headers: {'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))}, + form: { + grant_type: 'refresh_token', + refresh_token: refresh_token + }, + json: true + }; + + request.post(authOptions, function (error, response, body) { + if (!error && response.statusCode === 200) { + var access_token = body.access_token; + res.send({ + 'access_token': access_token + }); + } + }); +}); + +app.get('/get_playlists', function (req, res) { + // requesting access token from refresh token + var access_token = req.query.access_token; + var next = req.query.next; + var authOptions = { + url: next ? next : 'https://api.spotify.com/v1/me/playlists', + headers: {'Authorization': 'Bearer ' + access_token}, + json: true + }; + + getAllPages(authOptions, [], function(data) { + res.send({ + 'data': data + }); + }); +}); + +app.get('/pl/:uId/:plId', function (req, res) { + var plId = req.params.plId; + var userId = req.params.uId; + var access_token = req.query.access_token; + var fields = querystring.stringify({ + fields: 'items(track(id,name,artists(id,name))),next' + }); + var authOptions = { + url: 'https://api.spotify.com/v1/users/' + userId + '/playlists/' + plId + '/tracks?' + fields, + headers: {'Authorization': 'Bearer ' + access_token}, + json: true + }; + + getAllPages(authOptions, [], function (data) { + var dups = []; + data.forEach(function (item, index, array) { + var i = index + 1; + while (i < array.length) { + var other = array[i]; + if (item.track.id == other.track.id) { + dups.push(item); + } + else if (item.track.name.toLowerCase() == other.track.name.toLowerCase() && item.track.artists[0].id == other.track.artists[0].id) { + dups.push(item); + } + i++; + } + array.forEach(function (other, otherIndex) { + }); + }); + res.send({ + 'data': dups + }); + }); +}); + +function getAllPages(authOptions, data, callback) { + request.get(authOptions, function (error, response, body) { + if (!error && response.statusCode === 200) { + if (body.next) { + authOptions.url = body.next; + getAllPages(authOptions, data.concat(body.items), callback); + } + else { + callback(data.concat(body.items)); + } + } + }); +} + +module.exports = app; diff --git a/authorization_code/app.js b/authorization_code/app.js deleted file mode 100644 index 588dea1..0000000 --- a/authorization_code/app.js +++ /dev/null @@ -1,145 +0,0 @@ -/** - * This is an example of a basic node.js script that performs - * the Authorization Code oAuth2 flow to authenticate against - * the Spotify Accounts. - * - * For more information, read - * https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow - */ - -var express = require('express'); // Express web server framework -var request = require('request'); // "Request" library -var querystring = require('querystring'); -var cookieParser = require('cookie-parser'); - -var client_id = '03ffe0cac0a0401aa6673c3cf6d02ced'; // Your client id -var client_secret = 'a57c43efb9644574a96d6623fb8bfbc2'; // Your client secret -var redirect_uri = 'http://localhost:8888/callback'; // Your redirect uri - -/** - * Generates a random string containing numbers and letters - * @param {number} length The length of the string - * @return {string} The generated string - */ -var generateRandomString = function(length) { - var text = ''; - var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - - for (var i = 0; i < length; i++) { - text += possible.charAt(Math.floor(Math.random() * possible.length)); - } - return text; -}; - -var stateKey = 'spotify_auth_state'; - -var app = express(); - -app.use(express.static(__dirname + '/public')) - .use(cookieParser()); - -app.get('/login', function(req, res) { - - var state = generateRandomString(16); - res.cookie(stateKey, state); - - // your application requests authorization - var scope = 'user-read-private user-read-email'; - res.redirect('https://accounts.spotify.com/authorize?' + - querystring.stringify({ - response_type: 'code', - client_id: client_id, - scope: scope, - redirect_uri: redirect_uri, - state: state - })); -}); - -app.get('/callback', function(req, res) { - - // your application requests refresh and access tokens - // after checking the state parameter - - var code = req.query.code || null; - var state = req.query.state || null; - var storedState = req.cookies ? req.cookies[stateKey] : null; - - if (state === null || state !== storedState) { - res.redirect('/#' + - querystring.stringify({ - error: 'state_mismatch' - })); - } else { - res.clearCookie(stateKey); - var authOptions = { - url: 'https://accounts.spotify.com/api/token', - form: { - code: code, - redirect_uri: redirect_uri, - grant_type: 'authorization_code' - }, - headers: { - 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) - }, - json: true - }; - - request.post(authOptions, function(error, response, body) { - if (!error && response.statusCode === 200) { - - var access_token = body.access_token, - refresh_token = body.refresh_token; - - var options = { - url: 'https://api.spotify.com/v1/me', - headers: { 'Authorization': 'Bearer ' + access_token }, - json: true - }; - - // use the access token to access the Spotify Web API - request.get(options, function(error, response, body) { - console.log(body); - }); - - // we can also pass the token to the browser to make requests from there - res.redirect('/#' + - querystring.stringify({ - access_token: access_token, - refresh_token: refresh_token - })); - } else { - res.redirect('/#' + - querystring.stringify({ - error: 'invalid_token' - })); - } - }); - } -}); - -app.get('/refresh_token', function(req, res) { - - // requesting access token from refresh token - var refresh_token = req.query.refresh_token; - var authOptions = { - url: 'https://accounts.spotify.com/api/token', - headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) }, - form: { - grant_type: 'refresh_token', - refresh_token: refresh_token - }, - json: true - }; - - request.post(authOptions, function(error, response, body) { - if (!error && response.statusCode === 200) { - var access_token = body.access_token; - res.send({ - 'access_token': access_token - }); - } - }); -}); - -console.log('Listening on 8888'); -app.listen(8888); diff --git a/authorization_code/public/index.html b/authorization_code/public/index.html deleted file mode 100644 index fc6edfb..0000000 --- a/authorization_code/public/index.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - Example of the Authorization Code flow with Spotify - - - - - -
-
-

This is an example of the Authorization Code flow

- Log in with Spotify -
-
-
-
-
-
- -
-
- - - - - - - - - - - diff --git a/bin/www b/bin/www new file mode 100644 index 0000000..9530354 --- /dev/null +++ b/bin/www @@ -0,0 +1,24 @@ +#!/usr/bin/env node +'use strict'; +require('dotenv').config({silent: true}); +var throng = require('throng'); +var WORKERS = process.env.WEB_CONCURRENCY || 1; + + +function start() { + var app = require('../app'); + // Specify listen port + app.set('port', process.env.PORT || 3000); + + // Start listening + var server = app.listen(app.get('port'), function () { + var port = server.address().port; + console.log('Listening on %s', port); + }); +} + +throng({ + workers: WORKERS, + lifetime: Infinity, + start: start +}); diff --git a/client_credentials/app.js b/client_credentials/app.js deleted file mode 100644 index 634596f..0000000 --- a/client_credentials/app.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * This is an example of a basic node.js script that performs - * the Client Credentials oAuth2 flow to authenticate against - * the Spotify Accounts. - * - * For more information, read - * https://developer.spotify.com/web-api/authorization-guide/#client_credentials_flow - */ - -var request = require('request'); // "Request" library - -var client_id = '03ffe0cac0a0401aa6673c3cf6d02ced'; // Your client id -var client_secret = 'a57c43efb9644574a96d6623fb8bfbc2'; // Your client secret -var redirect_uri = 'http://localhost:8888/callback'; // Your redirect uri - -// your application requests authorization -var authOptions = { - url: 'https://accounts.spotify.com/api/token', - headers: { - 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) - }, - form: { - grant_type: 'client_credentials' - }, - json: true -}; - -request.post(authOptions, function(error, response, body) { - if (!error && response.statusCode === 200) { - - // use the access token to access the Spotify Web API - var token = body.access_token; - var options = { - url: 'https://api.spotify.com/v1/users/jmperezperez', - headers: { - 'Authorization': 'Bearer ' + token - }, - json: true - }; - request.get(options, function(error, response, body) { - console.log(body); - }); - } -}); diff --git a/implicit_grant/app.js b/implicit_grant/app.js deleted file mode 100644 index 436cd46..0000000 --- a/implicit_grant/app.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * This is an example of a basic node.js script that performs - * the Implicit Grant oAuth2 flow to authenticate against - * the Spotify Accounts. - * - * For more information, read - * https://developer.spotify.com/web-api/authorization-guide/#implicit_grant_flow - */ - -var express = require('express'); // Express web server framework -var app = express(); -app.use(express.static(__dirname + '/public')); -console.log('Listening on 8888'); -app.listen(8888); diff --git a/implicit_grant/public/index.html b/implicit_grant/public/index.html deleted file mode 100644 index b275305..0000000 --- a/implicit_grant/public/index.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - Example of the Implicit Grant flow with Spotify - - - - - -
-
-

This is an example of the Implicit Grant flow

- -
-
-
-
-
-
-
-
- - - - - - - - - diff --git a/package.json b/package.json index 056a120..9494243 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,10 @@ "main": "app.js", "dependencies": { "cookie-parser": "1.3.2", + "dotenv": "^2.0.0", "express": "~4.0.0", "querystring": "~0.2.0", - "request": "~2.34.0" + "request": "~2.34.0", + "throng": "^4.0.0" } } diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..74325e4 --- /dev/null +++ b/public/index.html @@ -0,0 +1,241 @@ + + + + Spotify Duplicate Finder + + + + + +
+
+

This is an example of the Authorization Code flow

+ Log in with Spotify +
+
+
+
+
+
+ + +

Duplicates finder

+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + +