:Sparkles: Add create playlist and get new releases - Spotify (#1520)

*  Create playlist in Spotify node

* Add create operation to Spotify node

* Add description and public properties to playlist resource type

*  Refactor playlist:create

*  Add album:getNewReleases

* 🎨 Replace PNG with SVG icon

*  Small improvements

Co-authored-by: Gerard Louw <gerardlouw@gmail.com>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
This commit is contained in:
Iván Ovejero 2021-03-10 14:50:12 -03:00 committed by GitHub
parent 15ec1f1f4d
commit 1842c7158b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 1204 additions and 60 deletions

View file

@ -1,4 +1,6 @@
import { OptionsWithUri } from 'request';
import {
OptionsWithUri,
} from 'request';
import {
IExecuteFunctions,

File diff suppressed because it is too large Load diff

View file

@ -14,11 +14,15 @@ import {
spotifyApiRequestAllItems,
} from './GenericFunctions';
import {
isoCountryCodes
} from './IsoCountryCodes';
export class Spotify implements INodeType {
description: INodeTypeDescription = {
displayName: 'Spotify',
name: 'spotify',
icon: 'file:spotify.png',
icon: 'file:spotify.svg',
group: ['input'],
version: 1,
description: 'Access public song data via the Spotify API.',
@ -183,6 +187,11 @@ export class Spotify implements INodeType {
value: 'get',
description: 'Get an album by URI or ID.',
},
{
name: 'Get New Releases',
value: 'getNewReleases',
description: 'Get a list of new album releases.',
},
{
name: `Get Tracks`,
value: 'getTracks',
@ -203,6 +212,10 @@ export class Spotify implements INodeType {
resource: [
'album',
],
operation: [
'get',
'getTracks',
],
},
},
placeholder: 'spotify:album:1YZ3k65Mqw3G8FzYlW1mmp',
@ -304,6 +317,11 @@ export class Spotify implements INodeType {
value: 'add',
description: 'Add tracks from a playlist by track and playlist URI or ID.',
},
{
name: 'Create a Playlist',
value: 'create',
description: 'Create a new playlist.',
},
{
name: 'Get',
value: 'get',
@ -350,6 +368,59 @@ export class Spotify implements INodeType {
placeholder: 'spotify:playlist:37i9dQZF1DWUhI3iC1khPH',
description: `The playlist's Spotify URI or its ID.`,
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: [
'playlist',
],
operation: [
'create',
],
},
},
placeholder: 'Favorite Songs',
description: 'Name of the playlist to create.',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'playlist',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
placeholder: 'These are all my favorite songs.',
description: 'Description for the playlist to create.',
},
{
displayName: 'Public',
name: 'public',
type: 'boolean',
default: true,
description: 'Whether the playlist is publicly accessible.',
},
],
},
{
displayName: 'Track ID',
name: 'trackID',
@ -433,6 +504,7 @@ export class Spotify implements INodeType {
'getTracks',
'getAlbums',
'getUserPlaylists',
'getNewReleases',
],
},
},
@ -455,6 +527,7 @@ export class Spotify implements INodeType {
'getTracks',
'getAlbums',
'getUserPlaylists',
'getNewReleases',
],
returnAll: [
false,
@ -489,6 +562,33 @@ export class Spotify implements INodeType {
},
description: `The number of items to return.`,
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: [
'album',
],
operation: [
'getNewReleases',
],
},
},
options: [
{
displayName: 'Country',
name: 'country',
type: 'options',
default: 'US',
options: isoCountryCodes.map(({ name, alpha2 }) => ({ name, value: alpha2 })),
description: 'Country to filter new releases by.',
},
],
},
],
};
@ -519,12 +619,12 @@ export class Spotify implements INodeType {
qs = {};
returnAll = false;
for(let i = 0; i < items.length; i++) {
for (let i = 0; i < items.length; i++) {
// -----------------------------
// Player Operations
// -----------------------------
if( resource === 'player' ) {
if(operation === 'pause') {
if (resource === 'player') {
if (operation === 'pause') {
requestMethod = 'PUT';
endpoint = `/me/player/pause`;
@ -533,7 +633,7 @@ export class Spotify implements INodeType {
responseData = { success: true };
} else if(operation === 'recentlyPlayed') {
} else if (operation === 'recentlyPlayed') {
requestMethod = 'GET';
endpoint = `/me/player/recently-played`;
@ -548,14 +648,14 @@ export class Spotify implements INodeType {
responseData = responseData.items;
} else if(operation === 'currentlyPlaying') {
} else if (operation === 'currentlyPlaying') {
requestMethod = 'GET';
endpoint = `/me/player/currently-playing`;
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
} else if(operation === 'nextSong') {
} else if (operation === 'nextSong') {
requestMethod = 'POST';
endpoint = `/me/player/next`;
@ -564,7 +664,7 @@ export class Spotify implements INodeType {
responseData = { success: true };
} else if(operation === 'previousSong') {
} else if (operation === 'previousSong') {
requestMethod = 'POST';
endpoint = `/me/player/previous`;
@ -573,7 +673,7 @@ export class Spotify implements INodeType {
responseData = { success: true };
} else if(operation === 'startMusic') {
} else if (operation === 'startMusic') {
requestMethod = 'PUT';
endpoint = `/me/player/play`;
@ -586,7 +686,7 @@ export class Spotify implements INodeType {
responseData = { success: true };
} else if(operation === 'addSongToQueue') {
} else if (operation === 'addSongToQueue') {
requestMethod = 'POST';
endpoint = `/me/player/queue`;
@ -601,22 +701,48 @@ export class Spotify implements INodeType {
responseData = { success: true };
}
// -----------------------------
// Album Operations
// -----------------------------
} else if( resource === 'album') {
const uri = this.getNodeParameter('id', i) as string;
// -----------------------------
// Album Operations
// -----------------------------
} else if (resource === 'album') {
const id = uri.replace('spotify:album:', '');
if (operation === 'get') {
const uri = this.getNodeParameter('id', i) as string;
requestMethod = 'GET';
const id = uri.replace('spotify:album:', '');
requestMethod = 'GET';
if(operation === 'get') {
endpoint = `/albums/${id}`;
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
} else if(operation === 'getTracks') {
} else if (operation === 'getNewReleases') {
endpoint = '/browse/new-releases';
requestMethod = 'GET';
const filters = this.getNodeParameter('filters', i) as IDataObject;
if (Object.keys(filters).length) {
Object.assign(qs, filters);
}
returnAll = this.getNodeParameter('returnAll', i) as boolean;
if (!returnAll) {
qs.limit = this.getNodeParameter('limit', i);
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
responseData = responseData.albums.items;
}
} else if (operation === 'getTracks') {
const uri = this.getNodeParameter('id', i) as string;
const id = uri.replace('spotify:album:', '');
requestMethod = 'GET';
endpoint = `/albums/${id}/tracks`;
propertyName = 'tracks';
@ -625,7 +751,7 @@ export class Spotify implements INodeType {
propertyName = 'items';
if(!returnAll) {
if (!returnAll) {
const limit = this.getNodeParameter('limit', i) as number;
qs = {
@ -637,15 +763,15 @@ export class Spotify implements INodeType {
responseData = responseData.items;
}
}
// -----------------------------
// Artist Operations
// -----------------------------
} else if( resource === 'artist') {
// -----------------------------
// Artist Operations
// -----------------------------
} else if (resource === 'artist') {
const uri = this.getNodeParameter('id', i) as string;
const id = uri.replace('spotify:artist:', '');
if(operation === 'getAlbums') {
if (operation === 'getAlbums') {
endpoint = `/artists/${id}/albums`;
@ -653,7 +779,7 @@ export class Spotify implements INodeType {
propertyName = 'items';
if(!returnAll) {
if (!returnAll) {
const limit = this.getNodeParameter('limit', i) as number;
qs = {
@ -664,7 +790,7 @@ export class Spotify implements INodeType {
responseData = responseData.items;
}
} else if(operation === 'getRelatedArtists') {
} else if (operation === 'getRelatedArtists') {
endpoint = `/artists/${id}/related-artists`;
@ -672,7 +798,7 @@ export class Spotify implements INodeType {
responseData = responseData.artists;
} else if(operation === 'getTopTracks'){
} else if (operation === 'getTopTracks') {
const country = this.getNodeParameter('country', i) as string;
qs = {
@ -693,23 +819,23 @@ export class Spotify implements INodeType {
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
}
// -----------------------------
// Playlist Operations
// -----------------------------
} else if( resource === 'playlist') {
if(['delete', 'get', 'getTracks', 'add'].includes(operation)) {
// -----------------------------
// Playlist Operations
// -----------------------------
} else if (resource === 'playlist') {
if (['delete', 'get', 'getTracks', 'add'].includes(operation)) {
const uri = this.getNodeParameter('id', i) as string;
const id = uri.replace('spotify:playlist:', '');
if(operation === 'delete') {
if (operation === 'delete') {
requestMethod = 'DELETE';
const trackId = this.getNodeParameter('trackID', i) as string;
body.tracks = [
{
uri: `${trackId}`,
positions: [ 0 ],
positions: [0],
},
];
@ -719,14 +845,14 @@ export class Spotify implements INodeType {
responseData = { success: true };
} else if(operation === 'get') {
} else if (operation === 'get') {
requestMethod = 'GET';
endpoint = `/playlists/${id}`;
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
} else if(operation === 'getTracks') {
} else if (operation === 'getTracks') {
requestMethod = 'GET';
endpoint = `/playlists/${id}/tracks`;
@ -735,7 +861,7 @@ export class Spotify implements INodeType {
propertyName = 'items';
if(!returnAll) {
if (!returnAll) {
const limit = this.getNodeParameter('limit', i) as number;
qs = {
@ -746,7 +872,7 @@ export class Spotify implements INodeType {
responseData = responseData.items;
}
} else if(operation === 'add') {
} else if (operation === 'add') {
requestMethod = 'POST';
const trackId = this.getNodeParameter('trackID', i) as string;
@ -760,47 +886,62 @@ export class Spotify implements INodeType {
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
}
} else if(operation === 'getUserPlaylists') {
requestMethod = 'GET';
} else if (operation === 'getUserPlaylists') {
requestMethod = 'GET';
endpoint = '/me/playlists';
endpoint = '/me/playlists';
returnAll = this.getNodeParameter('returnAll', i) as boolean;
returnAll = this.getNodeParameter('returnAll', i) as boolean;
propertyName = 'items';
propertyName = 'items';
if(!returnAll) {
const limit = this.getNodeParameter('limit', i) as number;
if (!returnAll) {
const limit = this.getNodeParameter('limit', i) as number;
qs = {
limit,
};
qs = {
limit,
};
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
responseData = responseData.items;
}
responseData = responseData.items;
}
// -----------------------------
// Track Operations
// -----------------------------
} else if( resource === 'track') {
} else if (operation === 'create') {
// https://developer.spotify.com/console/post-playlists/
body.name = this.getNodeParameter('name', i) as string;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (Object.keys(additionalFields).length) {
Object.assign(body, additionalFields);
}
responseData = await spotifyApiRequest.call(this, 'POST', '/me/playlists', body, qs);
}
// -----------------------------
// Track Operations
// -----------------------------
} else if (resource === 'track') {
const uri = this.getNodeParameter('id', i) as string;
const id = uri.replace('spotify:track:', '');
requestMethod = 'GET';
if(operation === 'getAudioFeatures') {
if (operation === 'getAudioFeatures') {
endpoint = `/audio-features/${id}`;
} else if(operation === 'get') {
} else if (operation === 'get') {
endpoint = `/tracks/${id}`;
}
responseData = await spotifyApiRequest.call(this, requestMethod, endpoint, body, qs);
}
if(returnAll) {
if (returnAll) {
responseData = await spotifyApiRequestAllItems.call(this, propertyName, requestMethod, endpoint, body, qs);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 66 65" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><use xlink:href="#A" x=".5" y=".5"/><symbol id="A" overflow="visible"><path d="M32 0C14.3 0 0 14.337 0 32c0 17.7 14.337 32 32 32 17.7 0 32-14.337 32-32S49.663 0 32 0zm14.68 46.184c-.573.956-1.797 1.223-2.753.65-7.532-4.588-16.975-5.62-28.14-3.097-1.07.23-2.14-.42-2.37-1.5s.42-2.14 1.5-2.37c12.196-2.8 22.67-1.606 31.082 3.556a2 2 0 0 1 .688 2.753zm3.9-8.717c-.726 1.185-2.256 1.53-3.44.84-8.602-5.276-21.716-6.805-31.885-3.747-1.338.382-2.714-.344-3.097-1.644-.382-1.338.344-2.714 1.682-3.097 11.622-3.517 26.074-1.835 35.976 4.244 1.147.688 1.5 2.217.765 3.403zm.344-9.1c-10.323-6.117-27.336-6.7-37.2-3.708-1.568.497-3.25-.42-3.747-1.988s.42-3.25 1.988-3.747c11.317-3.44 30.127-2.753 41.98 4.282 1.415.84 1.873 2.676 1.032 4.1-.765 1.453-2.638 1.912-4.053 1.07z" stroke="none" fill="#1ed760" fill-rule="nonzero"/></symbol></svg>

After

Width:  |  Height:  |  Size: 1 KiB