-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from chrisdevwords/develop
Develop
- Loading branch information
Showing
14 changed files
with
742 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
const request = require('request-promise-native'); | ||
const { response } = require('../util/lambda') | ||
|
||
// response types | ||
const TYPE_PRIVATE = 'ephemeral'; | ||
const TYPE_PUBLIC = 'in_channel'; | ||
|
||
// error messages | ||
const INVALID_TOKEN = 'Slack token is invalid.'; | ||
|
||
function slackResp(text, code = 200, type = TYPE_PUBLIC) { | ||
return response({ | ||
// eslint-disable-next-line camelcase | ||
response_type: type, | ||
text | ||
}, code); | ||
} | ||
|
||
module.exports = { | ||
TYPE_PUBLIC, | ||
TYPE_PRIVATE, | ||
INVALID_TOKEN, | ||
slackResp, | ||
notify(uri, text) { | ||
return request | ||
.post({ | ||
uri, | ||
headers: { | ||
'content-type': 'application/json' | ||
}, | ||
body: { | ||
text | ||
}, | ||
json: true | ||
}) | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
const request = require('request-promise-native'); | ||
const { | ||
API_BASE, | ||
extractFromUri | ||
} = require('../spotify'); | ||
|
||
const PLAYLIST_ENDPOINT = (user, id) => | ||
`${API_BASE}/users/${user}/playlists/${id}`; | ||
|
||
const PLAYLIST_TRACKS_ENDPOINT = (user, id) => | ||
`${PLAYLIST_ENDPOINT(user, id)}/tracks`; | ||
|
||
|
||
module.exports = { | ||
|
||
renamePlaylist(playlist, name, accessToken) { | ||
|
||
const userId = extractFromUri(playlist, 'user'); | ||
const playlistId = extractFromUri(playlist, 'playlist'); | ||
|
||
return request | ||
.put({ | ||
json: true, | ||
uri: PLAYLIST_ENDPOINT(userId, playlistId), | ||
headers: { | ||
Authorization: `Bearer ${accessToken}`, | ||
'content-type': 'application/json' | ||
}, | ||
body: { | ||
name | ||
} | ||
}); | ||
}, | ||
|
||
populatePlaylist(playlist, uris, accessToken) { | ||
|
||
const userId = extractFromUri(playlist, 'user'); | ||
const playlistId = extractFromUri(playlist, 'playlist'); | ||
|
||
return request | ||
.put({ | ||
json: true, | ||
uri: PLAYLIST_TRACKS_ENDPOINT(userId, playlistId), | ||
headers: { | ||
Authorization: `Bearer ${accessToken}`, | ||
'content-type': 'application/json' | ||
}, | ||
body: { | ||
uris | ||
} | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
const request = require('request-promise-native'); | ||
const { | ||
API_BASE | ||
} = require('../spotify'); | ||
const playlist = require('../spotify/playlist'); | ||
const track = require('../spotify/track'); | ||
|
||
|
||
// Response templates | ||
const PLAYLIST_NAME = basedOn => | ||
`Radio: based on ${basedOn}`; | ||
const TRACK_NAME = (artist, songName) => | ||
`"${songName}" by ${artist}`; | ||
|
||
const RECCOMENDED_TRACKS_ENDPOINT = `${API_BASE}/recommendations`; | ||
const SLACK_SUCCESS_MESSAGE = playlistName => | ||
`Playlist changed to ${playlistName}`; | ||
|
||
const SLACK_PENDING_MESSAGE = ({ name, artist }) => | ||
`Finding tracks based on: ${TRACK_NAME(artist, name)}...`; | ||
|
||
module.exports = { | ||
|
||
PLAYLIST_NAME, | ||
TRACK_NAME, | ||
SLACK_SUCCESS_MESSAGE, | ||
SLACK_PENDING_MESSAGE, | ||
|
||
getRecommendationsFromTrack(trackId, trackInfo, accessToken) { | ||
|
||
const { energy, valence, popularity } = trackInfo; | ||
|
||
return request | ||
.get({ | ||
uri: RECCOMENDED_TRACKS_ENDPOINT, | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
}, | ||
json: true, | ||
qs: { | ||
limit: 100, | ||
seed_tracks: trackId, | ||
seed_artists: trackInfo.artistIds.join(','), | ||
max_popularity: popularity, | ||
target_energy: energy, | ||
target_valence: valence, | ||
market:'US' | ||
} | ||
}) | ||
.then(({ tracks }) => tracks.map(({ uri }) => uri)); | ||
}, | ||
|
||
createStation(playlistUri, trackInfo, accessToken) { | ||
|
||
const trackId = trackInfo.id; | ||
const playlistName = PLAYLIST_NAME( | ||
TRACK_NAME(trackInfo.artist, trackInfo.name) | ||
); | ||
|
||
return track | ||
.getTrackFeatures(trackId, accessToken) | ||
.then(features => | ||
this.getRecommendationsFromTrack( | ||
trackId, | ||
Object.assign(features, trackInfo), | ||
accessToken | ||
) | ||
) | ||
.then(uris => | ||
playlist.populatePlaylist(playlistUri, uris, accessToken) | ||
) | ||
.then(() => | ||
playlist.renamePlaylist(playlistUri, playlistName, accessToken) | ||
) | ||
.then(() => playlistName) | ||
.catch((err) => { | ||
if (err.error) { | ||
const error = Error(err.error.error.message); | ||
error.statusCode = err.statusCode; | ||
throw error; | ||
} | ||
return Promise.reject(err) | ||
}); | ||
}, | ||
|
||
playBasedOnTrack(playlistUri, trackUri, accessToken, spotifyLocalUrl) { | ||
|
||
return this | ||
.createStation(playlistUri, trackUri, accessToken) | ||
.then(() => | ||
request | ||
.post({ | ||
uri: `${spotifyLocalUrl}/api/spotify/playlist`, | ||
body: { | ||
playlist: playlistUri | ||
}, | ||
json: true | ||
}) | ||
) | ||
.then(resp => | ||
SLACK_SUCCESS_MESSAGE(resp.playlist.title) | ||
); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const request = require('request-promise-native'); | ||
const { | ||
API_BASE, | ||
ERROR_EXPIRED_TOKEN, | ||
ERROR_INVALID_TRACK_URI, | ||
extractFromUri | ||
} = require('../spotify'); | ||
|
||
// Endpoint templates | ||
const TRACK_ENDPOINT = id => | ||
`${API_BASE}/tracks/${id}`; | ||
|
||
const TRACK_FEATURES_ENDPOINT = trackId => | ||
`${API_BASE}/audio-features/${trackId}`; | ||
|
||
module.exports = { | ||
|
||
handleStatusCodeError(err) { | ||
if (err.error) { | ||
let message; | ||
switch (err.statusCode) { | ||
case 404: | ||
case 400: | ||
message = ERROR_INVALID_TRACK_URI; | ||
break; | ||
case 401: | ||
message = ERROR_EXPIRED_TOKEN; | ||
break; | ||
default: | ||
message = err.error.error.message; | ||
} | ||
const error = Error(message); | ||
error.statusCode = err.statusCode; | ||
throw error; | ||
} | ||
return Promise.reject(err) | ||
}, | ||
|
||
getTrackInfo(trackId, accessToken) { | ||
return request | ||
.get({ | ||
uri: TRACK_ENDPOINT(trackId), | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
}, | ||
json: true | ||
}) | ||
.then(({ artists, name, popularity }) => ({ | ||
name, | ||
artist: artists | ||
.map(a => a.name) | ||
.join(', '), | ||
artistIds: artists | ||
.map(a => extractFromUri(a.uri, 'artist')), | ||
popularity, | ||
id: trackId | ||
})) | ||
.catch(this.handleStatusCodeError); | ||
|
||
}, | ||
|
||
getTrackFeatures(trackId, accessToken) { | ||
return request | ||
.get({ | ||
uri: TRACK_FEATURES_ENDPOINT(trackId), | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
}, | ||
json: true | ||
}) | ||
.catch(this.handleStatusCodeError); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
SLACK_TOKEN=foo_bar_baz | ||
EXPIRED_SPOTIFY_ACCESS_TOKEN=BQANyQM3QT080jey_TnbnVSvF1Xr9lKrEc31YkiOlENYwKDuv-3261TtzAWoB0v80IXIPuscAOz7lfTXyfr6WHqCMbAa4DUhRJicDzW1kZ7UV6ofNGWXwoB8raB8ut7q9STN0yIrkvlLvgEAGd6Wsu6Ibfo1olJUDJ0Q2VCAIaNrVtG852AhMp_Wpjzs-K74CYpxO2AtYYNcXo3s0WA7gao84eh1qTnqhprnSbGIjLShqVsmZTo | ||
SPOTIFY_LOCAL_URL=http://localhost:5000 | ||
SPOTIFY_RADIO_PLAYLIST=spotify:user:awpoops:playlist:5PP1I2m0uxEBb3VKLhI7bP | ||
SPOTIFY_USER_ACCESS_TOKEN=BQDeNBJSIWXe3Ezx3IYKf95NJIWeA82cIOFgnDgcc0IwbblLBpi3qEAXz-0R59yAXZ4s4SYz1phS6fWHSWVkDxo08KfSZCUpA-0xEM9FUom7QII2_DL3Ti293Zrhiz1jL4fC-dGLiRxtr7NjImZntCUcss4fBxgrVjuhwCPP4T3AMOljBkE4vY5VNyWq_Pf4aRF1JshyfNg6KLJiL-xClp_AUMglH60IgsjerXWYFq3pt-b8H_U |
Oops, something went wrong.