Hacky, but working spotify skipping.
This commit is contained in:
parent
fecd3db3bc
commit
64f1d76778
|
@ -13,6 +13,7 @@
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"pkg": "^5.8.1",
|
"pkg": "^5.8.1",
|
||||||
|
"spotify-web-api-node": "^5.0.2",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -434,6 +435,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
|
},
|
||||||
"node_modules/at-least-node": {
|
"node_modules/at-least-node": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||||
|
@ -648,6 +654,22 @@
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/component-emitter": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||||
|
},
|
||||||
"node_modules/content-disposition": {
|
"node_modules/content-disposition": {
|
||||||
"version": "0.5.4",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||||
|
@ -699,6 +721,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/cookiejar": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
|
||||||
|
},
|
||||||
"node_modules/core-util-is": {
|
"node_modules/core-util-is": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
@ -755,6 +782,14 @@
|
||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
@ -955,6 +990,11 @@
|
||||||
"node": ">=8.6.0"
|
"node": ">=8.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-safe-stringify": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
|
||||||
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
"version": "1.15.0",
|
"version": "1.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
|
||||||
|
@ -1018,6 +1058,28 @@
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/formidable": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==",
|
||||||
|
"deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://ko-fi.com/tunnckoCore/commissions"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||||
|
@ -2143,6 +2205,14 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/spotify-web-api-node": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/spotify-web-api-node/-/spotify-web-api-node-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-r82dRWU9PMimHvHEzL0DwEJrzFk+SMCVfq249SLt3I7EFez7R+jeoKQd+M1//QcnjqlXPs2am4DFsGk8/GCsrA==",
|
||||||
|
"dependencies": {
|
||||||
|
"superagent": "^6.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
@ -2199,6 +2269,52 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/superagent": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==",
|
||||||
|
"deprecated": "Please upgrade to v7.0.2+ of superagent. We have fixed numerous issues with streams, form-data, attach(), filesystem errors not bubbling up (ENOENT on attach()), and all tests are now passing. See the releases tab for more information at <https://github.com/visionmedia/superagent/releases>.",
|
||||||
|
"dependencies": {
|
||||||
|
"component-emitter": "^1.3.0",
|
||||||
|
"cookiejar": "^2.1.2",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"fast-safe-stringify": "^2.0.7",
|
||||||
|
"form-data": "^3.0.0",
|
||||||
|
"formidable": "^1.2.2",
|
||||||
|
"methods": "^1.1.2",
|
||||||
|
"mime": "^2.4.6",
|
||||||
|
"qs": "^6.9.4",
|
||||||
|
"readable-stream": "^3.6.0",
|
||||||
|
"semver": "^7.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/superagent/node_modules/mime": {
|
||||||
|
"version": "2.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
|
||||||
|
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
|
||||||
|
"bin": {
|
||||||
|
"mime": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/superagent/node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/supports-color": {
|
"node_modules/supports-color": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.6",
|
||||||
"pkg": "^5.8.1",
|
"pkg": "^5.8.1",
|
||||||
|
"spotify-web-api-node": "^5.0.2",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -3,31 +3,36 @@ const {input} = require("@inquirer/prompts");
|
||||||
const querystring = require("querystring");
|
const querystring = require("querystring");
|
||||||
const {nanoid} = require("nanoid");
|
const {nanoid} = require("nanoid");
|
||||||
const express = require('express')
|
const express = require('express')
|
||||||
const {setAuth, hasAuth, authFile} = require("../utilities/authentication");
|
const {spotify, spotifyCredentialsFile, hasSpotifyCredentials, saveSpotifyCredentials} = require("../utilities/spotify");
|
||||||
|
|
||||||
exports.command = 'authenticate'
|
exports.command = 'authenticate'
|
||||||
exports.description = 'starts the Spotity authentication process'
|
exports.description = 'starts the Spotity authentication process'
|
||||||
exports.builder = function (argv) {
|
exports.builder = (argv) => argv
|
||||||
return argv.option('client-id')
|
.option('client-id', {
|
||||||
}
|
description: 'The Spotify app client id',
|
||||||
;
|
type: 'string'
|
||||||
|
})
|
||||||
|
.option('client-secret', {
|
||||||
|
description: 'The Spotify app client secret',
|
||||||
|
type: 'string'
|
||||||
|
})
|
||||||
exports.handler = async function (argv) {
|
exports.handler = async function (argv) {
|
||||||
if (hasAuth()) {
|
if (hasSpotifyCredentials()) {
|
||||||
console.log(`spotify.local is already authenticated, remove "${authFile}" is you want to log out.`);
|
console.log(`spotify.local is already authenticated, remove "${spotifyCredentialsFile}" is you want to log out.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = await findAvailablePort();
|
const port = await findAvailablePort();
|
||||||
|
|
||||||
const authenticateRoute = 'authenticate';
|
const authenticateRoute = 'authenticate';
|
||||||
const authenticateUrl = `http://localhost:${port}/${authenticateRoute}`;
|
const redirectUri = `http://localhost:${port}/${authenticateRoute}`;
|
||||||
|
|
||||||
const tutorial = [
|
const tutorial = [
|
||||||
'Visit https://developer.spotify.com/dashboard and click "Create app"',
|
'Visit https://developer.spotify.com/dashboard and click "Create app"',
|
||||||
'Set the "App name" as "spotify.local"',
|
'Set the "App name" as "spotify.local"',
|
||||||
'Set the "App description" as "My spotify.local"',
|
'Set the "App description" as "My spotify.local"',
|
||||||
'Set the "Website" as "https://code.tmp.dev/ian/spotify.local"',
|
'Set the "Website" as "https://code.tmp.dev/ian/spotify.local"',
|
||||||
`Set the "Redirect URI" as "${authenticateUrl}"`,
|
`Set the "Redirect URI" as "${redirectUri}"`,
|
||||||
'Select under "Which API/SDKs are you planning to use?" the "Web API"',
|
'Select under "Which API/SDKs are you planning to use?" the "Web API"',
|
||||||
'Sign your life away by agreeing with the "Developer Terms of Service and Design Guidelines"',
|
'Sign your life away by agreeing with the "Developer Terms of Service and Design Guidelines"',
|
||||||
'Click on the "Save" button',
|
'Click on the "Save" button',
|
||||||
|
@ -36,12 +41,18 @@ exports.handler = async function (argv) {
|
||||||
|
|
||||||
tutorial.forEach((string, index) => console.log(`${index+1} ${string}`));
|
tutorial.forEach((string, index) => console.log(`${index+1} ${string}`));
|
||||||
|
|
||||||
const clientId = argv.clientId ?? await input({ message: `${tutorial.length}. Paste the clientId here` })
|
const clientId = argv.clientId ?? await input({ message: `${tutorial.length}. Paste the client id here` })
|
||||||
|
const clientSecret = argv.clientSecret ?? await input({ message: `${tutorial.length}. Paste the client secret here` })
|
||||||
const originalState = nanoid();
|
const originalState = nanoid();
|
||||||
const redirectUrl = new URL('https://accounts.spotify.com/authorize');
|
|
||||||
redirectUrl.search = querystring.stringify({
|
spotify.setClientId(clientId);
|
||||||
|
spotify.setClientSecret(clientSecret);
|
||||||
|
spotify.setRedirectURI(redirectUri);
|
||||||
|
|
||||||
|
const authUrl = new URL('https://accounts.spotify.com/authorize');
|
||||||
|
authUrl.search = querystring.stringify({
|
||||||
response_type: 'code',
|
response_type: 'code',
|
||||||
client_id: clientId,
|
client_id: spotify.getClientId(),
|
||||||
scope: [
|
scope: [
|
||||||
'user-library-read',
|
'user-library-read',
|
||||||
'user-read-private',
|
'user-read-private',
|
||||||
|
@ -59,28 +70,35 @@ exports.handler = async function (argv) {
|
||||||
'user-read-currently-playing',
|
'user-read-currently-playing',
|
||||||
'user-read-playback-position'
|
'user-read-playback-position'
|
||||||
].join(' '),
|
].join(' '),
|
||||||
redirect_uri: authenticateUrl,
|
redirect_uri: spotify.getRedirectURI(),
|
||||||
state: originalState
|
state: originalState
|
||||||
});
|
});
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
app.get(`/${authenticateRoute}`, (req, res) => {
|
app.get(`/${authenticateRoute}`, async (req, res) => {
|
||||||
const {state, code} = req.query;
|
const {state, code, error = null} = req.query;
|
||||||
if (originalState === state) {
|
if (!error && originalState === state) {
|
||||||
setAuth(code);
|
const { body } = await spotify.authorizationCodeGrant(code)
|
||||||
|
const {access_token, refresh_token, expires_in} = body;
|
||||||
|
spotify.setExpired((new Date).getTime() + expires_in);
|
||||||
|
spotify.setAccessToken(access_token);
|
||||||
|
spotify.setRefreshToken(refresh_token);
|
||||||
|
saveSpotifyCredentials();
|
||||||
|
|
||||||
res.send('<script>(() => close())()</script>');
|
res.send('<script>(() => close())()</script>');
|
||||||
|
|
||||||
server?.close();
|
server?.close();
|
||||||
|
|
||||||
console.log(`${tutorial.length+2}. Spotify.local has been authenticated`);
|
console.log(`${tutorial.length+2}. Spotify.local has been authenticated`);
|
||||||
} else {
|
|
||||||
res.status(400);
|
return;
|
||||||
res.send('NO')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.status(400);
|
||||||
|
res.send('NO');
|
||||||
});
|
});
|
||||||
|
|
||||||
server = app.listen(port, () => console.log(`${tutorial.length+1}. Follow the following URL to authenticate: ${redirectUrl}`));
|
server = app.listen(port, () => console.log(`${tutorial.length+1}. Follow the following URL to authenticate: ${authUrl}`));
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
const { spotify} = require('../utilities/spotify')
|
||||||
|
|
||||||
|
exports.command = 'next'
|
||||||
|
exports.handler = async () => {
|
||||||
|
spotify.ensure()
|
||||||
|
.then(spotify => spotify.skipToNext())
|
||||||
|
.catch(e => console.error(e.message))
|
||||||
|
};
|
|
@ -1,16 +0,0 @@
|
||||||
const { existsSync, mkdirSync, writeFileSync, readFileSync } = require('fs');
|
|
||||||
const { homedir } = require('os');
|
|
||||||
|
|
||||||
const configDir = `${homedir()}/.spotify-local`
|
|
||||||
const authenticationFile = `${configDir}/authentication`
|
|
||||||
|
|
||||||
const ensure = () => {
|
|
||||||
if (!existsSync(configDir)) mkdirSync(configDir);
|
|
||||||
if (!existsSync(authenticationFile)) writeFileSync(authenticationFile, '');
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.authFile = authenticationFile;
|
|
||||||
exports.setAuth = (code) => ensure() && writeFileSync(authenticationFile, code);
|
|
||||||
exports.getAuth = () => ensure() && readFileSync(authenticationFile).toString();
|
|
||||||
exports.hasAuth = () => ensure() && readFileSync(authenticationFile).toString() !== '';
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
const SpotifyWebApi = require('spotify-web-api-node');
|
||||||
|
const {homedir} = require("os");
|
||||||
|
const {existsSync, mkdirSync, writeFileSync, readFileSync} = require("fs");
|
||||||
|
|
||||||
|
const configDir = `${homedir()}/.spotify-local`
|
||||||
|
const spotifyCredentialsFile = `${configDir}/credentials.json`
|
||||||
|
|
||||||
|
const ensure = () => {
|
||||||
|
if (!existsSync(configDir)) mkdirSync(configDir);
|
||||||
|
if (!existsSync(spotifyCredentialsFile)) writeFileSync(spotifyCredentialsFile, '{}');
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
SpotifyWebApi.prototype.setExpired = function (expiresIn) {
|
||||||
|
const expired = (new Date).getTime() + expiresIn;
|
||||||
|
|
||||||
|
this._setCredential('expired', expired);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpotifyWebApi.prototype.getExpired = function () {
|
||||||
|
return this._getCredential('expired') ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise<SpotifyWebApi>}
|
||||||
|
*/
|
||||||
|
SpotifyWebApi.prototype.ensure = async function () {
|
||||||
|
const timeExpired = this.getExpired();
|
||||||
|
const time = (new Date).getTime();
|
||||||
|
if (time > timeExpired) {
|
||||||
|
const { body } = await this.refreshAccessToken();
|
||||||
|
const { access_token, expires_in } = body;
|
||||||
|
this.setAccessToken(access_token);
|
||||||
|
this.setExpired((new Date).getTime() + expires_in);
|
||||||
|
saveSpotifyCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const spotify = new SpotifyWebApi();
|
||||||
|
|
||||||
|
const saveSpotifyCredentials = () => ensure() && writeFileSync(spotifyCredentialsFile, JSON.stringify(spotify.getCredentials()));
|
||||||
|
const restoreSpotifyCredentials = () => ensure() && spotify.setCredentials(JSON.parse(readFileSync(spotifyCredentialsFile).toString()));
|
||||||
|
const hasSpotifyCredentials = () => existsSync(spotifyCredentialsFile);
|
||||||
|
|
||||||
|
if (existsSync(spotifyCredentialsFile)) restoreSpotifyCredentials();
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
spotify,
|
||||||
|
spotifyCredentialsFile,
|
||||||
|
saveSpotifyCredentials,
|
||||||
|
restoreSpotifyCredentials,
|
||||||
|
hasSpotifyCredentials,
|
||||||
|
}
|
Loading…
Reference in New Issue