forked from ballofmatts/hubot-spotify-playlist
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspotify-playlist.coffee
162 lines (141 loc) · 6.59 KB
/
spotify-playlist.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Description
# Allows the ability to add/remove/findTracks to a Spotify Playlist.
#
# Configuration:
# SPOTIFY_APP_CLIENT_ID
# SPOTIFY_APP_CLIENT_SECRET
# SPOTIFY_USER_ID
# SPOTIFY_PLAYLIST_ID
# SPOTIFY_OAUTH_CODE
# SPOTIFY_REDIRECT_URI
#
# Commands:
# hubot playlist add <query> - Adds first track in search to the playlist
# hubot playlist addid <track_id> - Adds a track to the playlist via ID
# hubot playlist remove <track_id> - Removes a track on the playlist
# hubot playlist find <query> - go to that link to get a token
# hubot playlist link - displays link to spotify playlist
# hubot playlist listen <on|off|status> - controls whether it should be listening for spotify links to automatically add
#
# Author:
# Kevin Ngao (kev5873) <[email protected]>
module.exports = (robot) ->
# init listen flag to false if none can be found
if (robot.brain.get('playlistListen') == null)
robot.brain.set 'playlistListen', false
# Authorize app, only authorizes non-user specific functions for the app, like Searching.
# See: https://developer.spotify.com/web-api/authorization-guide/#client_credentials_flow
authorizeApp = (res, func) ->
encodedAppId = new Buffer(process.env.SPOTIFY_APP_CLIENT_ID + ":" + process.env.SPOTIFY_APP_CLIENT_SECRET).toString('base64')
data = "grant_type=client_credentials"
res.http("https://accounts.spotify.com/api/token")
.header("Authorization", "Basic " + encodedAppId)
.header('Content-Type', 'application/x-www-form-urlencoded')
.post(data) (err, resp, body) =>
response = JSON.parse(body)
func(res, response.access_token)
# Authorize App User Flow, authorizes user specific functions, like modifying playlists
# See: https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow
requestInitialTokens = (res, func) ->
encodedAppId = new Buffer(process.env.SPOTIFY_APP_CLIENT_ID + ":" + process.env.SPOTIFY_APP_CLIENT_SECRET).toString('base64')
data = "grant_type=authorization_code&code=" + process.env.SPOTIFY_OAUTH_CODE + "&redirect_uri=" + process.env.SPOTIFY_REDIRECT_URI
res.http("https://accounts.spotify.com/api/token")
.header("Authorization", "Basic " + encodedAppId)
.header('Content-Type', 'application/x-www-form-urlencoded')
.post(data) (err, resp, body) =>
response = JSON.parse(body)
if err
res.send "Encountered an error :( #{err}"
robot.brain.set 'access_token', response.access_token
robot.brain.set 'refresh_token', response.refresh_token
robot.brain.set 'expires', (new Date().getTime() + (response.expires_in * 1000))
func(res)
refreshAccessToken = (res, func) ->
console.log 'refreshAccessToken', robot
encodedAppId = new Buffer(process.env.SPOTIFY_APP_CLIENT_ID + ":" + process.env.SPOTIFY_APP_CLIENT_SECRET).toString('base64')
data = "grant_type=refresh_token&refresh_token=" + robot.brain.get('refresh_token')
res.http("https://accounts.spotify.com/api/token")
.header("Authorization", "Basic " + encodedAppId)
.header('Content-Type', 'application/x-www-form-urlencoded')
.post(data) (err, resp, body) =>
if err
res.send "Encountered an error :( #{err}"
return
response = JSON.parse(body)
if response.refresh_token
robot.brain.set 'refresh_token', response.refresh_token
robot.brain.set 'access_token', response.access_token
robot.brain.set 'expires', (new Date().getTime() + (response.expires_in * 1000))
func(res)
authorizeAppUser = (res, func) ->
if (robot.brain.get('access_token') != null) # Access Token Exists
if ((new Date().getTime()) > robot.brain.get('expires')) # Token expired
refreshAccessToken(res, func)
else # Token has not expired, continue using it
func(res)
else # access token doesn't exist
requestInitialTokens(res, func)
# Spotify Web API Functions
addTrack = (res) ->
data = JSON.stringify({
uris: ["spotify:track:"+res.match[1]]
})
res.http("https://api.spotify.com/v1/playlists/" + process.env.SPOTIFY_PLAYLIST_ID + "/tracks")
.header("Authorization", "Bearer " + robot.brain.get('access_token'))
.header('Content-Type', 'application/json')
.header('Accept', 'application/json')
.post(data) (err, resp, body) =>
if err
res.send "Encountered an error :( #{err}"
return
response = JSON.parse(body)
if response.snapshot_id
res.send "Track added"
removeTrack = (res) ->
data = JSON.stringify({
tracks: [
uri : "spotify:track:" + res.match[1]
]
})
res.http("https://api.spotify.com/v1/playlists/" + process.env.SPOTIFY_PLAYLIST_ID + "/tracks")
.header("Authorization", "Bearer " + robot.brain.get('access_token'))
.header('Content-Type', 'application/json')
.delete(data) (err, resp, body) =>
if err
res.send "Encountered an error :( #{err}"
return
response = JSON.parse(body)
if response.snapshot_id
res.send "Track removed"
findTrack = (res, token) ->
res.http("https://api.spotify.com/v1/search?q=" + res.match[1] + "&type=track&market=US&limit=10")
.header("Authorization", "Bearer " + token)
.header('Accept', 'application/json')
.get() (err, resp, body) =>
response = JSON.parse body
string = ""
for item in response.tracks.items
string = string + "#{item.name} - #{item.artists[0].name} - #{item.album.name} - #{item.id} \n"
res.send string
robot.respond /playlist add (.*)/i, (res) ->
authorizeAppUser(res, addTrack)
robot.respond /playlist remove (.*)/i, (res) ->
authorizeAppUser(res, removeTrack)
robot.respond /playlist find (.*)/i, (res) ->
authorizeApp(res, findTrack)
robot.respond /playlist listen (on|off|status)/i, (res) ->
if (res.match[1] == "on")
robot.brain.set 'playlistListen', true
res.send "Now listening for spotify links!"
else if (res.match[1] == "off")
robot.brain.set 'playlistListen', false
res.send "No longer listening for spotify links."
else
listenStatus = robot.brain.get('playlistListen')
value = if listenStatus then "on" else "off"
res.send "Listening status: " + value
robot.hear /https:\/\/open\.spotify\.com\/track\/([a-zA-Z\d]+)\s*?/i, (res) ->
if (robot.brain.get('playlistListen'))
authorizeAppUser(res, addTrack)
robot.respond /playlist link/i, (res) ->
res.send "https://open.spotify.com/user/#{process.env.SPOTIFY_USER_ID}/playlist/#{process.env.SPOTIFY_PLAYLIST_ID}"