Socket
Socket
Sign inDemoInstall

graphql-spotify

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphql-spotify - npm Package Compare versions

Comparing version 0.4.141 to 0.43.0

.travis.yml

382

dist/lib.js

@@ -85,3 +85,3 @@ module.exports =

var _resolvers = __webpack_require__(14);
var _resolvers = __webpack_require__(19);

@@ -160,2 +160,22 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var _Category = __webpack_require__(14);
var _Category2 = _interopRequireDefault(_Category);
var _RecommendationParameters = __webpack_require__(15);
var _RecommendationParameters2 = _interopRequireDefault(_RecommendationParameters);
var _RecommendationsResponse = __webpack_require__(16);
var _RecommendationsResponse2 = _interopRequireDefault(_RecommendationsResponse);
var _RecommendationsSeedObject = __webpack_require__(17);
var _RecommendationsSeedObject2 = _interopRequireDefault(_RecommendationsSeedObject);
var _RootQuery = __webpack_require__(18);
var _RootQuery2 = _interopRequireDefault(_RootQuery);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -170,36 +190,4 @@

const RootQuery = `
type RootQuery {
featuredPlaylists(limit: Int, offset: Int): Paging
"""
Returns the most recent 50 tracks played by a user
"""
recentlyPlayed: [PlayHistory]
"""
Get a playlist owned by a Spotify user
"""
playlist(userId: String!, playlistId: String!): Playlist
"""
Get an artist
"""
artist(artistId: String!): Artist
"""
Get audio features of a track
"""
audioFeatures(id: String!): AudioFeatures
"""
Get a track
"""
track(id: String!): Track
}
type Mutation {
"""
"""
saveTrack(trackId: String!): Track
}
`;
const typeDefs = [SchemaDefinition, _RootQuery2.default, _Playlist2.default, _Image2.default, _User2.default, _PlaylistTrack2.default, _Track2.default, _Album2.default, _Artist2.default, _Paging2.default, _AudioFeatures2.default, _PlayHistory2.default, _Category2.default, _RecommendationParameters2.default, _RecommendationsResponse2.default, _RecommendationsSeedObject2.default, _ExternalUrls2.default];
const typeDefs = [SchemaDefinition, RootQuery, _Playlist2.default, _Image2.default, _User2.default, _PlaylistTrack2.default, _Track2.default, _Album2.default, _Artist2.default, _Paging2.default, _AudioFeatures2.default, _PlayHistory2.default, _ExternalUrls2.default];
exports.default = typeDefs;

@@ -397,2 +385,3 @@

saved in the user's library
Required Scope: **user-library-read**
"""

@@ -476,3 +465,3 @@ saved: Boolean

const Paging = `
union Item = Playlist | PlaylistTrack
union Item = Playlist | PlaylistTrack | Category
type Paging {

@@ -575,5 +564,179 @@ href: String

});
const Category = `
type Category {
"""
A link to the Web API endpoint returning full details of the category.
"""
href: String
icons: [Image]
id: String
name: String
"""
Get a list of Spotify playlists tagged with a particular category
limit: Default: 20. Minimum: 1. Maximum: 50
"""
playlists(country: String, limit: Int, offset: Int): Paging
}
`;
exports.default = Category;
/***/ }),
/* 15 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
// TODO after all parameters on targting attributes from https://beta.developer.spotify.com/documentation/web-api/reference/browse/get-recommendations/
const RecommendationParameters = `
input RecommendationParameters {
limit: Int
seed_artists: [String]
seed_genres: [String]
seed_tracks: [String]
}
`;
exports.default = RecommendationParameters;
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const RecommendationsResponse = `
type RecommendationsResponse {
seeds: [RecommendationsSeedObject]
"""
An array of track object (simplified) ordered according to the parameters supplied
"""
tracks: [Track]
}
`;
exports.default = RecommendationsResponse;
/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const RecommendationsSeedObject = `
type RecommendationsSeedObject {
"""
The number of tracks available after min_* and max_* filters have been applied
"""
afterFilteringSize: Int
"""
The number of tracks available after relinking for regional availability.
"""
afterRelinkingSize: Int
"""
A link to the full track or artist data for this seed. For tracks this will be a link to a Track Object. For artists a link to an Artist Object. For genre seeds, this value will be null.
"""
href: String
"""
The id used to select this seed. This will be the same as the string used in the seed_artists , seed_tracks or seed_genres parameter
"""
id: String
"""
The number of recommended tracks available for this seed.
"""
initialPoolSize: Int
"""
The entity type of this seed. One of artist , track or genre
"""
type: String
}
`;
exports.default = RecommendationsSeedObject;
/***/ }),
/* 18 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const RootQuery = `
type RootQuery {
featuredPlaylists(limit: Int, offset: Int): Paging
"""
Returns the most recent 50 tracks played by a user
Required Scope: **user-read-recently-played**
"""
recentlyPlayed: [PlayHistory]
"""
Get a playlist owned by a Spotify user
"""
playlist(userId: String!, playlistId: String!): Playlist
"""
Get an artist
"""
artist(artistId: String!): Artist
"""
Get audio features of a track
"""
audioFeatures(id: String!): AudioFeatures
"""
Get a track
"""
track(id: String!): Track
"""
https://beta.developer.spotify.com/documentation/web-api/reference/browse/get-list-categories/
Get a list of categories used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab).
"""
categories(limit: Int, offset: Int, country: String, locale: String): Paging
"""
Get a single category used to tag items in Spotify (on, for example, the Spotify player’s “Browse” tab)
https://beta.developer.spotify.com/documentation/web-api/reference/browse/get-category/
"""
category(id: String!): Category
"""
Save one or more tracks to the current user’s ‘Your Music’ library
Required Scope: **user-library-modify**
"""
recommendations(parameters: RecommendationParameters): RecommendationsResponse
}
type Mutation {
"""
"""
saveTrack(trackId: String!): Track
}
`;
exports.default = RootQuery;
/***/ }),
/* 19 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.makeResolvers = makeResolvers;
var _SpotifyWebApi = __webpack_require__(15);
var _SpotifyWebApi = __webpack_require__(20);

@@ -583,3 +746,4 @@ function makeResolvers(token) {

PlaylistLoader, PlaylistTracksLoader, AlbumsLoader, UserLoader, ArtistsLoader,
AudioFeaturesLoader, SavedContainsLoader, TracksLoader
AudioFeaturesLoader, SavedContainsLoader, TracksLoader, CategoriesLoader, RecommendationsLoader,
CategoryPlaylistLoader, CategoryLoader
} = (0, _SpotifyWebApi.makeLoaders)(token);

@@ -608,2 +772,13 @@

return await AudioFeaturesLoader.load(id);
},
categories: async (obj, args) => {
const res = await CategoriesLoader.load(args);
return res.categories;
},
category: async (obj, args) => {
const res = await CategoryLoader.load(args.id);
return res;
},
recommendations: async (obj, args) => {
return await RecommendationsLoader.load(args.parameters);
}

@@ -633,3 +808,5 @@ },

// otherwise always fetch all of the tracks
let currentOffset = items.length;
// when resolving a full playlist there are already items
let allItems = items || [];
let currentOffset = allItems.length;
let fetches = [];

@@ -641,3 +818,2 @@ while (currentOffset < total) {

const fetchResults = await Promise.all(fetches);
let allItems = items;
fetchResults.forEach(result => {

@@ -704,2 +880,8 @@ allItems = allItems.concat(result.items);

},
Category: {
playlists: async (category, args) => {
const { playlists } = await CategoryPlaylistLoader.load({ id: category.id, queryParams: args });
return playlists;
}
},
Item: {

@@ -717,2 +899,3 @@ __resolveType(object, context, info) {

}
return 'Category';
}

@@ -725,3 +908,3 @@ }

/***/ }),
/* 15 */
/* 20 */
/***/ (function(module, exports, __webpack_require__) {

@@ -738,2 +921,6 @@

exports.getFeaturedPlaylists = getFeaturedPlaylists;
exports.getCategoryPlaylists = getCategoryPlaylists;
exports.getRecommendations = getRecommendations;
exports.getCategories = getCategories;
exports.getCategory = getCategory;
exports.getRecentlyPlayed = getRecentlyPlayed;

@@ -747,3 +934,2 @@ exports.getPlaylist = getPlaylist;

exports.getAudioFeatures = getAudioFeatures;
exports.makeLoaders = makeLoaders;
exports.makeUserLoader = makeUserLoader;

@@ -757,6 +943,11 @@ exports.makePlaylistLoader = makePlaylistLoader;

exports.makeAudioFeaturesLoader = makeAudioFeaturesLoader;
exports.makeCategoriesLoader = makeCategoriesLoader;
exports.makeCategoryLoader = makeCategoryLoader;
exports.makeCategoriesPlaylistsLoader = makeCategoriesPlaylistsLoader;
exports.makeRecommendationsLoader = makeRecommendationsLoader;
exports.makeLoaders = makeLoaders;
__webpack_require__(16);
__webpack_require__(21);
var _dataloader = __webpack_require__(17);
var _dataloader = __webpack_require__(22);

@@ -775,2 +966,6 @@ var _dataloader2 = _interopRequireDefault(_dataloader);

function cacheKeyFnForQueryKeys(key) {
return JSON.stringify(key);
}
function serializeToURLParameters(obj) {

@@ -807,2 +1002,38 @@ return Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&');

async function getCategoryPlaylists(token, id, queryParams = {}) {
let res = await fetch(`https://api.spotify.com/v1/browse/categories/${id}/playlists?${serializeToURLParameters(queryParams)}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
async function getRecommendations(token, queryParams) {
let res = await fetch(`https://api.spotify.com/v1/recommendations?${serializeToURLParameters(queryParams)}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
async function getCategories(token, queryParams = {}) {
let res = await fetch(`https://api.spotify.com/v1/browse/categories?${serializeToURLParameters(queryParams)}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
async function getCategory(token, id) {
let res = await fetch(`https://api.spotify.com/v1/browse/categories/${id}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
async function getRecentlyPlayed(token) {

@@ -881,15 +1112,2 @@ const url = "https://api.spotify.com/v1/me/player/recently-played?limit=50";

function makeLoaders(token) {
return {
UserLoader: makeUserLoader(token),
PlaylistLoader: makePlaylistLoader(token),
PlaylistTracksLoader: makePlaylistTracksLoader(token),
AlbumsLoader: makeAlbumsLoader(token),
ArtistsLoader: makeArtistsLoader(token),
TracksLoader: makeTracksLoader(token),
SavedContainsLoader: makeSavedContainsLoader(token),
AudioFeaturesLoader: makeAudioFeaturesLoader(token)
};
}
function makeUserLoader(token) {

@@ -947,4 +1165,3 @@ const batchLoadFn = async ([key]) => {

const batchLoadFn = async keys => {
const saved = await getSavedContains(token, keys);
return saved;
return await getSavedContains(token, keys);
};

@@ -962,4 +1179,49 @@ return new _dataloader2.default(batchLoadFn, { maxBatchSize: 50 });

function makeCategoriesLoader(token) {
const batchLoadFn = async ([key]) => {
return [await getCategories(token, key)];
};
return new _dataloader2.default(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys });
}
function makeCategoryLoader(token) {
const batchLoadFn = async ([key]) => {
const category = await getCategory(token, key);
return [category];
};
return new _dataloader2.default(batchLoadFn, { batch: false });
}
function makeCategoriesPlaylistsLoader(token) {
const batchLoadFn = async ([{ id, queryParams }]) => {
return [await getCategoryPlaylists(token, id, queryParams)];
};
return new _dataloader2.default(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys });
}
function makeRecommendationsLoader(token) {
const batchLoadFn = async ([key]) => {
return [await getRecommendations(token, key)];
};
return new _dataloader2.default(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys });
}
function makeLoaders(token) {
return {
UserLoader: makeUserLoader(token),
PlaylistLoader: makePlaylistLoader(token),
PlaylistTracksLoader: makePlaylistTracksLoader(token),
AlbumsLoader: makeAlbumsLoader(token),
ArtistsLoader: makeArtistsLoader(token),
TracksLoader: makeTracksLoader(token),
SavedContainsLoader: makeSavedContainsLoader(token),
AudioFeaturesLoader: makeAudioFeaturesLoader(token),
CategoriesLoader: makeCategoriesLoader(token),
RecommendationsLoader: makeRecommendationsLoader(token),
CategoryPlaylistLoader: makeCategoriesPlaylistsLoader(token),
CategoryLoader: makeCategoryLoader(token)
};
}
/***/ }),
/* 16 */
/* 21 */
/***/ (function(module, exports) {

@@ -970,3 +1232,3 @@

/***/ }),
/* 17 */
/* 22 */
/***/ (function(module, exports) {

@@ -973,0 +1235,0 @@

4

package.json
{
"name": "graphql-spotify",
"version": "0.4.141",
"version": "0.43.0",
"description": "GraphQL Schema And Resolvers For Spotify Web API",

@@ -12,3 +12,3 @@ "main": "dist/lib.js",

},
"author": "Sitian Liu",
"author": "Sitian Liu <goldensunliu@gmail.com> (https://www.sitianliu.com/)",
"license": "MIT",

@@ -15,0 +15,0 @@ "devDependencies": {

import {
getFeaturedPlaylists, getRecentlyPlayed, makeLoaders, saveTrackToLib
getFeaturedPlaylists, getRecentlyPlayed, makeLoaders, saveTracksToLib, followPlaylist, unfollowPlaylist,
removeTracksFromLib
} from './SpotifyWebApi'
const MAX_PLAYLIST_TRACKS_FETCH_LIMIT = 100
const MAX_TOP_TYPE_FETCH_LIMIT = 50
const MAX_PLAYLIST_FOLLOWERS_CONTAINS_LIMIT = 5;
const makePlaylistResolver = ({ PlaylistLoader, PlaylistTracksLoader, PlaylistFollowersContainsLoader, MeLoader }) => {
return {
description: async (object) => {
const {id: playlistId , owner: { id: userId }} = object
const playlistFull = await PlaylistLoader.load({ playlistId, userId })
return playlistFull.description
},
totalTracks: async ({ tracks: { total }}) => {
return total
},
followerCount: (obj) => {
return obj.followers.total
},
tracks: async (obj, args) => {
const { id: playlistId , owner: { id: userId }, tracks: { total, offset, items }} = obj
// fetch with limit and offset when specified
if (args.limit && args.offset) {
return await PlaylistTracksLoader.load({playlistId, userId, ...args })
}
// otherwise always fetch all of the tracks
// when resolving a full playlist, tracks are set the first 100 tracks
let allItems = items || []
let currentOffset = allItems.length
let fetches = []
while (currentOffset < total ) {
const fetchSize = Math.min(MAX_PLAYLIST_TRACKS_FETCH_LIMIT, total - currentOffset);
fetches.push(PlaylistTracksLoader.load({playlistId, userId, limit: fetchSize, offset: currentOffset }))
currentOffset = currentOffset + fetchSize;
}
const fetchResults = await Promise.all(fetches);
fetchResults.forEach((result) => {
allItems = allItems.concat(result.items)
})
return { total, items: allItems, limit: total, offset }
},
followersContains: async (obj, { userIds }) => {
const { id: playlistId , owner: { id: playlistUserId } } = obj
let currentOffset = 0
let fetches = []
let total = userIds.length
while (currentOffset < total ) {
const fetchSize = Math.min(MAX_PLAYLIST_FOLLOWERS_CONTAINS_LIMIT, total - currentOffset);
fetches.push(PlaylistFollowersContainsLoader.load({ playlistUserId, playlistId,
userIds: userIds.slice(currentOffset, currentOffset + fetchSize)
}))
currentOffset = currentOffset + fetchSize;
}
const fetchResults = await Promise.all(fetches);
return fetchResults.reduce((accu, value) => { return accu.concat(value) }, [])
},
following: async (obj) => {
if (obj.following || obj.following === false) return obj.following
const { id: playlistId , owner: { id: playlistUserId } } = obj
const me = await MeLoader.load()
const userIds = [me.id]
const [following] = await PlaylistFollowersContainsLoader.load({ playlistUserId, playlistId, userIds })
return following
},
}
}
export function makeResolvers(token) {
const {
PlaylistLoader, PlaylistTracksLoader, AlbumsLoader, UserLoader, ArtistsLoader,
AudioFeaturesLoader, SavedContainsLoader, TracksLoader
AudioFeaturesLoader, SavedContainsLoader, TracksLoader, CategoriesLoader, RecommendationsLoader,
CategoryPlaylistLoader, CategoryLoader, TopTypeLoader, PlaylistFollowersContainsLoader, MeLoader
} = makeLoaders(token);

@@ -32,43 +99,67 @@

return await AudioFeaturesLoader.load(id)
}
},
Mutation: {
saveTrack: async (obj, {trackId}) => {
await saveTrackToLib(token, [trackId])
return { id: trackId, saved: true }
}
},
Playlist: {
description: async (object) => {
const {id: playlistId , owner: { id: userId }} = object
const playlistFull = await PlaylistLoader.load({ playlistId, userId })
return playlistFull.description
},
totalTracks: async ({ tracks: { total }}) => {
return total
categories: async (obj, args) => {
const res = await CategoriesLoader.load(args)
return res.categories
},
tracks: async (obj, args) => {
const { id: playlistId , owner: { id: userId }, tracks: { total, offset, items, limit }} = obj
// fetch with limit and offset when specified
if (args.limit && args.offset) {
return await PlaylistTracksLoader.load({playlistId, userId, ...args })
category: async (obj, args) => {
const res = await CategoryLoader.load(args.id)
return res
},
recommendations: async (obj, args) => {
return await RecommendationsLoader.load(args.parameters)
},
top: async (obj, args) => {
const { type, limit, offset, time_range } = args
const result = await TopTypeLoader.load({ type, limit, offset, time_range })
if (result.items.length >= limit) {
return result
}
// otherwise always fetch all of the tracks
let currentOffset = items.length;
let allItems = result.items
const totalFetchSize = Math.min(limit, result.total)
let currentOffset = allItems.length
let fetches = []
while (currentOffset < total ) {
fetches.push(PlaylistTracksLoader.load({playlistId, userId, limit, offset: currentOffset }))
currentOffset = currentOffset + limit;
while (currentOffset < totalFetchSize) {
const fetchSize = Math.min(MAX_TOP_TYPE_FETCH_LIMIT, totalFetchSize - currentOffset);
fetches.push(TopTypeLoader.load({type, time_range, limit: fetchSize, offset: currentOffset }))
currentOffset = currentOffset + fetchSize;
}
const fetchResults = await Promise.all(fetches);
let allItems = items
fetchResults.forEach((result) => {
allItems = allItems.concat(result.items)
})
return { total, items: allItems, limit: total, offset }
return { total: result.total, items: allItems, limit: allItems.length, offset }
}
},
Mutation: {
saveTrack: async (obj, {trackId}) => {
const res = await saveTracksToLib(token, [trackId])
if (res.status !== 200) return;
return { id: trackId, saved: true }
},
saveTracks: async (obj, {trackIds}) => {
const res = await saveTracksToLib(token, trackIds)
if (res.status !== 200) return;
return trackIds.map(id => ({ id, saved: true }))
},
removeTracks: async (obj, {trackIds}) => {
const res = await removeTracksFromLib(token, trackIds)
if (res.status !== 200) return;
return trackIds.map(id => ({ id, saved: false }))
},
followPlaylist: async (obj, { ownerId, playlistId, isPublic }) => {
const res = await followPlaylist(token, { ownerId, playlistId, isPublic })
if (res.status !== 200) return;
return { id: playlistId, following: true }
},
unfollowPlaylist: async (obj, { ownerId, playlistId }) => {
const res = await unfollowPlaylist(token, { ownerId, playlistId })
if (res.status !== 200) return;
return { id: playlistId, following: false }
}
},
Playlist: makePlaylistResolver({ PlaylistLoader, PlaylistTracksLoader, PlaylistFollowersContainsLoader, MeLoader }),
Track: {
audio_features: async ({ id }) => {
return await AudioFeatureLoader.load(id)
return await AudioFeaturesLoader.load(id)
},

@@ -126,2 +217,8 @@ saved: async ({id}) => {

},
Category: {
playlists: async(category, args) => {
const { playlists } = await CategoryPlaylistLoader.load({ id: category.id, queryParams: args })
return playlists
}
},
Item: {

@@ -133,2 +230,8 @@ __resolveType(object, context, info){

}
if (type === 'artist') {
return 'Artist'
}
if (type === 'track') {
return 'Track'
}
if (type === 'playlist') {

@@ -140,2 +243,3 @@ return 'Playlist'

}
return 'Category'
}

@@ -142,0 +246,0 @@ }

@@ -12,2 +12,3 @@ const Artist = `

external_urls: ExternalUrls
type: String
}

@@ -14,0 +15,0 @@ `;

@@ -9,6 +9,14 @@ import Playlist from './Playlist'

import Paging from './Paging'
import TimeRange from './TimeRange'
import TopType from './TopType'
import AudioFeatures from './AudioFeatures'
import PlayHistory from './PlayHistory'
import ExternalUrls from './ExternalUrls'
import Category from './Category'
import RecommendationParameters from './RecommendationParameters'
import RecommendationsResponse from './RecommendationsResponse'
import RecommendationsSeedObject from './RecommendationsSeedObject'
import RootQuery from './RootQuery'
const SchemaDefinition = `

@@ -21,37 +29,6 @@ schema {

const RootQuery = `
type RootQuery {
featuredPlaylists(limit: Int, offset: Int): Paging
"""
Returns the most recent 50 tracks played by a user
"""
recentlyPlayed: [PlayHistory]
"""
Get a playlist owned by a Spotify user
"""
playlist(userId: String!, playlistId: String!): Playlist
"""
Get an artist
"""
artist(artistId: String!): Artist
"""
Get audio features of a track
"""
audioFeatures(id: String!): AudioFeatures
"""
Get a track
"""
track(id: String!): Track
}
type Mutation {
"""
"""
saveTrack(trackId: String!): Track
}
`;
const typeDefs = [SchemaDefinition, RootQuery, Playlist, Image, User, PlaylistTrack, Track, Album, Artist, Paging,
AudioFeatures, PlayHistory, ExternalUrls];
AudioFeatures, PlayHistory, Category, RecommendationParameters, RecommendationsResponse, RecommendationsSeedObject,
ExternalUrls, TimeRange, TopType];
export default typeDefs
const Paging = `
union Item = Playlist | PlaylistTrack
union Item = Playlist | PlaylistTrack | Category | Artist | Track
type Paging {

@@ -4,0 +4,0 @@ href: String

@@ -48,2 +48,11 @@ const Playlist = `

uri: String
"""
Check to see if one or more Spotify users are following the playlist.
"""
followersContains(userIds: [String]!): [Boolean]
"""
Check to see the user is following the playlist.
**Required Scope**: playlist-read-private
"""
following: Boolean
}

@@ -50,0 +59,0 @@ `

@@ -20,4 +20,6 @@ const Track = `

saved in the user's library
Required Scope: **user-library-read**
"""
saved: Boolean
type: String
}

@@ -24,0 +26,0 @@ `

@@ -12,8 +12,12 @@ import 'isomorphic-fetch'

function cacheKeyFnForQueryKeys(key) {
return serializeToURLParameters(key)
}
function serializeToURLParameters(obj) {
return Object.entries(obj).map(([key, val]) => `${key}=${val}`).join('&')
return Object.entries(obj).map(([key, val]) => val && `${key}=${val}`).join('&')
}
export async function saveTrackToLib(token, trackIds) {
export async function saveTracksToLib(token, trackIds) {
const url = `https://api.spotify.com/v1/me/tracks?ids=${trackIds.toString()}`

@@ -26,2 +30,27 @@ return await fetch(url, {

export async function removeTracksFromLib(token, trackIds) {
const url = `https://api.spotify.com/v1/me/tracks?ids=${trackIds.toString()}`
return await fetch(url, {
method: 'DELETE',
headers: makeHeaders(token)
})
}
export async function followPlaylist(token, { ownerId, playlistId, isPublic = true }) {
const url = `https://api.spotify.com/v1/users/${ownerId}/playlists/${playlistId}/followers`
return await fetch(url, {
method: 'PUT',
headers: makeHeaders(token),
body: JSON.stringify({ public: isPublic })
})
}
export async function unfollowPlaylist(token, { ownerId, playlistId }) {
const url = `https://api.spotify.com/v1/users/${ownerId}/playlists/${playlistId}/followers`
return await fetch(url, {
method: 'DELETE',
headers: makeHeaders(token)
})
}
export async function getSavedContains(token, trackIds) {

@@ -47,2 +76,42 @@ const url = `https://api.spotify.com/v1/me/tracks/contains?ids=${trackIds.toString()}`

export async function getCategoryPlaylists(token, id, queryParams = {})
{
let res = await fetch(`https://api.spotify.com/v1/browse/categories/${id}/playlists?${serializeToURLParameters(queryParams)}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getRecommendations(token, queryParams)
{
let res = await fetch(`https://api.spotify.com/v1/recommendations?${serializeToURLParameters(queryParams)}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getCategories(token, queryParams = {})
{
let res = await fetch(`https://api.spotify.com/v1/browse/categories?${serializeToURLParameters(queryParams)}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getCategory(token, id)
{
let res = await fetch(`https://api.spotify.com/v1/browse/categories/${id}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getRecentlyPlayed(token) {

@@ -58,2 +127,12 @@ const url = "https://api.spotify.com/v1/me/player/recently-played?limit=50"

export async function getTopType(token, params) {
const { type, limit, offset, time_range } = params
let res = await fetch(`https://api.spotify.com/v1/me/top/${type}?${serializeToURLParameters({ limit, offset, time_range })}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getPlaylist(token, userId, playlistId)

@@ -79,2 +158,12 @@ {

export async function getMe(token)
{
let res = await fetch(`https://api.spotify.com/v1/me`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getPlaylistTracks(token, { userId, playlistId, limit = 100, offset = 0 })

@@ -90,2 +179,12 @@ {

export async function getPlaylistFollowersContains(token, { playlistUserId, playlistId, userIds })
{
let res = await fetch(`https://api.spotify.com/v1/users/${playlistUserId}/playlists/${playlistId}/followers/contains?ids=${userIds.toString()}`, {
method: 'GET',
headers: makeHeaders(token)
});
res = await res.json();
return res;
}
export async function getAlbums(token, ids)

@@ -131,15 +230,2 @@ {

export function makeLoaders(token) {
return {
UserLoader : makeUserLoader(token),
PlaylistLoader : makePlaylistLoader(token),
PlaylistTracksLoader: makePlaylistTracksLoader(token),
AlbumsLoader: makeAlbumsLoader(token),
ArtistsLoader: makeArtistsLoader(token),
TracksLoader: makeTracksLoader(token),
SavedContainsLoader: makeSavedContainsLoader(token),
AudioFeaturesLoader: makeAudioFeaturesLoader(token)
}
}
export function makeUserLoader(token) {

@@ -197,4 +283,3 @@ const batchLoadFn = async ([key]) => {

const batchLoadFn = async (keys) => {
const saved = await getSavedContains(token, keys)
return saved
return await getSavedContains(token, keys)
}

@@ -210,2 +295,79 @@ return new Dataloader(batchLoadFn, { maxBatchSize: 50 })

return new Dataloader(batchLoadFn, { maxBatchSize: 50 })
}
export function makeCategoriesLoader(token) {
const batchLoadFn = async ([key]) => {
return [await getCategories(token, key)]
}
return new Dataloader(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys })
}
export function makeCategoryLoader(token) {
const batchLoadFn = async ([key]) => {
const category = await getCategory(token, key)
return [category]
}
return new Dataloader(batchLoadFn, { batch: false })
}
export function makeCategoriesPlaylistsLoader(token) {
const batchLoadFn = async ([{ id, queryParams }]) => {
return [await getCategoryPlaylists(token, id, queryParams)]
}
return new Dataloader(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys })
}
export function makeRecommendationsLoader(token) {
const batchLoadFn = async ([key]) => {
return [await getRecommendations(token, key)]
}
return new Dataloader(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys })
}
export function makeGetTopTypeLoader(token) {
const batchLoadFn = async ([key]) => {
return [await getTopType(token, key)]
}
return new Dataloader(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys })
}
export function makePlaylistFollowersContainsLoader(token) {
const batchLoadFn = async ([key]) => {
return [await getPlaylistFollowersContains(token, key)]
}
return new Dataloader(batchLoadFn, { batch: false, cacheKeyFn: cacheKeyFnForQueryKeys })
}
// Skipping the dataloader just here since the loader is meant to called with only .load()
// Use it the same way as you would with a dataloader, i.e only on per request basis
export function makeMeLoader(token) {
let cacheMe = null;
return {
load : async () => {
if (!cacheMe) {
cacheMe = await getMe(token)
}
return cacheMe
}
}
}
export function makeLoaders(token) {
return {
UserLoader : makeUserLoader(token),
PlaylistLoader : makePlaylistLoader(token),
PlaylistTracksLoader: makePlaylistTracksLoader(token),
AlbumsLoader: makeAlbumsLoader(token),
ArtistsLoader: makeArtistsLoader(token),
TracksLoader: makeTracksLoader(token),
SavedContainsLoader: makeSavedContainsLoader(token),
AudioFeaturesLoader: makeAudioFeaturesLoader(token),
CategoriesLoader : makeCategoriesLoader(token),
RecommendationsLoader: makeRecommendationsLoader(token),
CategoryPlaylistLoader: makeCategoriesPlaylistsLoader(token),
CategoryLoader: makeCategoryLoader(token),
TopTypeLoader: makeGetTopTypeLoader(token),
PlaylistFollowersContainsLoader: makePlaylistFollowersContainsLoader(token),
MeLoader: makeMeLoader(token)
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc