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
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Duplicates finder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+