A basic api wrapper for the spotify api covering the oauth routes.
npm install lunify.js



⚠️ In development, breaking changes ⚠️
If you need help using this package, join our Discord Server.
If you run node.js v18 or higher, use
``bash`With npm
npm install lunify.jsWith yarn
yarn add lunify.jsWith pnpm
pnpm add lunify.js
node.js v17 or lower is currently not supported.
All examples are written for TypeScript, if you use JavaScript please use the commonJS import method. Please note that every update could contain breaking changes during 0.x.x phase.
ts
import { Lunify } from 'lunify.js';const api = new Lunify({
clientId: '898e127e95f24f578fdbfec93ae203cd',
clientSecret: 'dc302ea39cefbdf875f42f59e721e898',
// If you want to have access to oauth2
oauth: {
redirectUri: 'http://10.0.0.50:7654/callback'
}
});
`$3
You can generate a url for users to login like shown bellow, learn more about for what you need scopes here, if you are unsure what scopes you need for what, use the spotify docs references.
`ts
const url = api.oauth.generateUrl([Scopes.Streaming, Scopes.UserModifyPlaybackState, Scopes.UserReadPlaybackState]);
`
From the callback urls query params you get a code with is used to fetch users access token from spotify.
`ts
const access = await api.oauth.fetchToken(code);
`
If you want to just play music or do other things with a user's player, you can create a PartialUser like that:
`ts
const user = new PartialUser(api, access);
user.player.play("4cOdK2wGLETKBW3PvgPWqT");
`
If you want to access to user's data you can just get it from the previously gotten access class
`ts
const user = await access.fetchUser();
user.player.play("4cOdK2wGLETKBW3PvgPWqT");console.log(user.displayName)
`$3
Getting a single track, note that all fetched data gets cached to not spam the api as much
`ts
const track = await api.tracks.fetch("4cOdK2wGLETKBW3PvgPWqT");// or if you want to skip the cache
const track = await api.tracks.fetch("4cOdK2wGLETKBW3PvgPWqT", { force: true });
`Example
`ts
import fastify from 'fastify';
import { Lunify, UserOauth, Scopes, PartialUser } from 'lunify.js';const app = fastify();
const api = new Lunify({
clientId: '898e127e95f24f578fdbfec93ae203cd',
clientSecret: 'dc302ea39cefbdf875f42f59e721e898',
oauth: {
redirectUri: 'http://localhost:3000/callback'
}
});
// Login and authorize this app to access your spotify account
// GET http://localhost:3000/login
app.get('/login', (req, res) => {
const url = api.oauth.generateUrl([Scopes.Streaming, Scopes.UserModifyPlaybackState, Scopes.UserReadPlaybackState]);
res.redirect(url);
});
let access: UserOauth | undefined;
// Callback to get your authorization code and fetch your user credentials (NOT spotify login credentials)
// GET http://localhost:3000/callback
app.get('/callback', async (req) => {
const code = (req.query as Record).code || null;
const state = (req.query as Record).state || null;
const error = (req.query as Record).error || null;
if (error) return error;
if (!state) return 'Invalud state';
access = await api.oauth.fetchToken(code);
console.log(access)
return 'OK';
});
// Play a track on your current device, provide a track as query param (don't forget to remove all of spotifies tracking queries from their links)
// GET http://localhost:3000/play?track=https://open.spotify.com/track/0ZVjgfaC2Ptrod9v6p9KFP
app.get('/play', (req) => {
if (!access) return "You need to go to /login first"
const track = (req.query as Record).track?.split('/track/')?.[1]?.split('?')[0];
if (!track) return 'No track id';
// We use PartialUser so we do not have to fetch user data to use it's player
const user = new PartialUser(api, access);
user.player.play(track);
return 'OK';
});
// Get your user data
// GET http://localhost:3000/me
app.get('/me', async () => {
if (!access) return "You need to go to /login first"
const user = await access.fetchUser();
console.log(user);
return 'OK';
});
// Fetch a track, provide a track as query param (don't forget to remove all of spotifies tracking queries from their links)
// GET http://localhost:3000/track?track=https://open.spotify.com/track/0ZVjgfaC2Ptrod9v6p9KFP
app.get('/track', async (req) => {
const trackId = (req.query as Record).track?.split('/track/')?.[1]?.split('?')[0];
if (!trackId) return 'No track id';
const track = await api.tracks.fetch(trackId);
console.log(track);
return 'OK';
});
// Let the webserver listen to that port
app.listen({ host: 'localhost', port: 3000 }, (err, address) => {
if (err) console.log(err);
console.log(
Listening to ${address});
});
``