소스 검색

Use github.com/zmb3/spotify

Toni Fadjukoff 6 년 전
부모
커밋
490689d5ce
5개의 변경된 파일184개의 추가작업 그리고 72개의 파일을 삭제
  1. 2 1
      auth.go
  2. 63 43
      bot.go
  3. 76 15
      spotify/spotify.go
  4. 38 13
      web.go
  5. 5 0
      web/index.html

+ 2 - 1
auth.go 파일 보기

17
 type SessionData struct {
17
 type SessionData struct {
18
 	sid      string
18
 	sid      string
19
 	username string
19
 	username string
20
+	spotify  string
20
 	priority time.Time
21
 	priority time.Time
21
 	index    int
22
 	index    int
22
 }
23
 }
162
 	}
163
 	}
163
 
164
 
164
 	expiration := time.Now().Add(duration)
165
 	expiration := time.Now().Add(duration)
165
-	addSession(&SessionData{sid, username, expiration, 0})
166
+	addSession(&SessionData{sid, username, "", expiration, 0})
166
 
167
 
167
 	return loginCookie, nil
168
 	return loginCookie, nil
168
 }
169
 }

+ 63 - 43
bot.go 파일 보기

6
 	"flag"
6
 	"flag"
7
 	"fmt"
7
 	"fmt"
8
 	"github.com/jasonlvhit/gocron"
8
 	"github.com/jasonlvhit/gocron"
9
-	"github.com/lamperi/e4bot/spotify"
9
+	"github.com/zmb3/spotify"
10
 	"io"
10
 	"io"
11
 	"log"
11
 	"log"
12
 	"os"
12
 	"os"
18
 )
18
 )
19
 
19
 
20
 type App struct {
20
 type App struct {
21
-	db            *DB
22
-	credentials   Credentials
23
-	spotifyClient *spotify.SpotifyClient
21
+	db          *DB
22
+	credentials Credentials
23
+	spotify     *AppSpotify
24
+}
25
+type AppSpotify struct {
26
+	auth   *spotify.Authenticator
27
+	client *spotify.Client
24
 }
28
 }
25
 
29
 
26
 type Credentials struct {
30
 type Credentials struct {
34
 	ListenAddr          string
38
 	ListenAddr          string
35
 }
39
 }
36
 
40
 
37
-func (app *App) CreateSpotifyClient() *spotify.SpotifyClient {
38
-	spotifyClient := spotify.NewClient(app.credentials.SpotifyClientID, app.credentials.SpotifyClientSecret)
39
-	spotifyClient.SetupUserAuthenticate(app.credentials.SpotifyCallback)
40
-	return spotifyClient
41
+func (app *App) CreateSpotifyAuthenticator() *spotify.Authenticator {
42
+	auth := spotify.NewAuthenticator(app.credentials.SpotifyCallback, spotify.ScopePlaylistModifyPublic)
43
+	auth.SetAuthInfo(app.credentials.SpotifyClientID, app.credentials.SpotifyClientSecret)
44
+	return &auth
41
 }
45
 }
42
 
46
 
43
 func (app *App) LaunchWeb() {
47
 func (app *App) LaunchWeb() {
44
-	app.spotifyClient = app.CreateSpotifyClient()
48
+	app.spotify.auth = app.CreateSpotifyAuthenticator()
45
 	go func() {
49
 	go func() {
46
-		webStart(app.credentials.ListenAddr, app.db, app.spotifyClient)
50
+		webStart(app.credentials.ListenAddr, app.db, app.spotify)
47
 	}()
51
 	}()
48
 }
52
 }
49
 
53
 
225
 	return strings.Join(changedLines, "\n")
229
 	return strings.Join(changedLines, "\n")
226
 }
230
 }
227
 
231
 
228
-func findPlaylist(wikiText string) (string, []string) {
232
+func findPlaylist(wikiText string) (spotify.ID, []spotify.ID) {
229
 	const SONG_MARK = "<!-- Kappale -->"
233
 	const SONG_MARK = "<!-- Kappale -->"
230
 	const SPOTIFY_MARK = "https://open.spotify.com/track/"
234
 	const SPOTIFY_MARK = "https://open.spotify.com/track/"
231
 	const SPOTIFY_PLAYLIST_MARK = "/playlist/"
235
 	const SPOTIFY_PLAYLIST_MARK = "/playlist/"
232
 	const PLAYLIST_MARK = " Spotify-soittolista]"
236
 	const PLAYLIST_MARK = " Spotify-soittolista]"
233
 	lines := strings.Split(wikiText, "\n")
237
 	lines := strings.Split(wikiText, "\n")
234
 
238
 
235
-	playlistId := ""
236
-	tracks := make([]string, 0)
239
+	var playlistId spotify.ID
240
+	tracks := make([]spotify.ID, 0)
237
 	for _, line := range lines {
241
 	for _, line := range lines {
238
 		if strings.Index(line, SONG_MARK) != -1 {
242
 		if strings.Index(line, SONG_MARK) != -1 {
239
 			i := strings.Index(line, SPOTIFY_MARK)
243
 			i := strings.Index(line, SPOTIFY_MARK)
243
 					j += i
247
 					j += i
244
 				}
248
 				}
245
 				trackId := line[i+len(SPOTIFY_MARK) : j]
249
 				trackId := line[i+len(SPOTIFY_MARK) : j]
246
-				tracks = append(tracks, trackId)
250
+				tracks = append(tracks, spotify.ID(trackId))
247
 			}
251
 			}
248
 		} else if strings.Index(line, SPOTIFY_PLAYLIST_MARK) != -1 && strings.Index(line, PLAYLIST_MARK) != -1 {
252
 		} else if strings.Index(line, SPOTIFY_PLAYLIST_MARK) != -1 && strings.Index(line, PLAYLIST_MARK) != -1 {
249
 			i := strings.Index(line, SPOTIFY_PLAYLIST_MARK)
253
 			i := strings.Index(line, SPOTIFY_PLAYLIST_MARK)
250
 			j := strings.Index(line[i:], PLAYLIST_MARK)
254
 			j := strings.Index(line[i:], PLAYLIST_MARK)
251
 
255
 
252
-			playlistId = line[i+len(SPOTIFY_PLAYLIST_MARK) : i+j]
253
-			q := strings.Index(playlistId, "?")
256
+			playlist := line[i+len(SPOTIFY_PLAYLIST_MARK) : i+j]
257
+			q := strings.Index(playlist, "?")
254
 			if q != -1 {
258
 			if q != -1 {
255
-				playlistId = playlistId[:q]
259
+				playlist = playlist[:q]
256
 			}
260
 			}
261
+			playlistId = spotify.ID(playlist)
257
 		}
262
 		}
258
 	}
263
 	}
259
 	log.Printf("Found playlist %s and tracks %s\n", playlistId, tracks)
264
 	log.Printf("Found playlist %s and tracks %s\n", playlistId, tracks)
260
 
265
 
261
-	return playlistId, tracks
266
+	return spotify.ID(playlistId), tracks
262
 }
267
 }
263
 
268
 
264
-func appendPlaylist(wikiText string, playlist *spotify.PlaylistInfo) string {
269
+func appendPlaylist(wikiText string, playlist *spotify.FullPlaylist) string {
265
 	changedText := wikiText + `
270
 	changedText := wikiText + `
266
-	[` + playlist.ExternalUrls.Spotify + ` Spotify-soittolista]
271
+	[` + playlist.ExternalURLs["spotify"] + ` Spotify-soittolista]
267
 	`
272
 	`
268
 	return changedText
273
 	return changedText
269
 }
274
 }
273
 
278
 
274
 	sections, err := wiki.GetWikiPageSections(title)
279
 	sections, err := wiki.GetWikiPageSections(title)
275
 	if err != nil {
280
 	if err != nil {
281
+		log.Println("Error while reading page sections")
276
 		return err
282
 		return err
277
 	}
283
 	}
278
 
284
 
292
 
298
 
293
 			wikiText, err := wiki.GetWikiPageSectionText(title, section.index)
299
 			wikiText, err := wiki.GetWikiPageSectionText(title, section.index)
294
 			if err != nil {
300
 			if err != nil {
301
+				log.Println("Error reading text from wiki")
295
 				return err
302
 				return err
296
 			}
303
 			}
297
 			message := ""
304
 			message := ""
300
 				message = message + fmt.Sprintf("Calculate averages for week %d. ", weekNumber)
307
 				message = message + fmt.Sprintf("Calculate averages for week %d. ", weekNumber)
301
 			}
308
 			}
302
 
309
 
303
-			if app.spotifyClient.HasUserLogin() {
304
-				playlistId, tracks := findPlaylist(changedWikiText)
305
-				currentTracks, err := app.db.FindPlaylistBySection(section.title)
306
-				if len(tracks) > 0 && (err != nil || reflect.DeepEqual(currentTracks, tracks)) {
310
+			if app.spotify.client != nil {
311
+				token, err := app.spotify.client.Token()
312
+				if err != nil {
313
+					log.Println("No token available")
314
+				} else if token.Expiry.Before(time.Now()) {
315
+					log.Println("Token has expired")
316
+				} else {
317
+					log.Println("Checking if playlist needs updating")
318
+					playlistId, tracks := findPlaylist(changedWikiText)
319
+					currentTracks, err := app.db.FindPlaylistBySection(section.title)
320
+					if len(tracks) > 0 && (err != nil || reflect.DeepEqual(currentTracks, tracks)) {
321
+
322
+						if playlistId == "" {
323
+
324
+							info, err := app.spotify.client.CreatePlaylistForUser(app.credentials.SpotifyUser, title+" "+section.title, true)
325
+							if err != nil {
326
+								log.Println("Error creating playlist to Spotify")
327
+								return err
328
+							}
329
+							playlistId = info.ID
330
+							changedWikiText = appendPlaylist(changedWikiText, info)
331
+							message = message + fmt.Sprintf("Added link to Spotify playlist for week %d.", weekNumber)
332
+						}
333
+						err := app.spotify.client.ReplacePlaylistTracks(app.credentials.SpotifyUser, playlistId, tracks...)
334
+						if err != nil {
335
+							log.Println("Error updating playlist to Spotify")
336
+							return err
337
+						}
307
 
338
 
308
-					spotify := app.spotifyClient
309
-					if playlistId == "" {
339
+						stringTracks := make([]string, len(tracks))
340
+						for i, t := range tracks {
341
+							stringTracks[i] = string(t)
342
+						}
310
 
343
 
311
-						info, err := spotify.NewPlaylist(title+" "+section.title, app.credentials.SpotifyUser)
344
+						_, err = app.db.UpdatePlaylistBySection(section.title, stringTracks)
312
 						if err != nil {
345
 						if err != nil {
313
-							log.Println("Error creating playlist")
346
+							log.Println("Error updating playlist to DB")
314
 							return err
347
 							return err
315
 						}
348
 						}
316
-						playlistId = info.Id
317
-						changedWikiText = appendPlaylist(changedWikiText, info)
318
-						message = message + fmt.Sprintf("Added link to Spotify playlist for week %d.", weekNumber)
319
-					}
320
-					err := spotify.UpdatePlaylist(app.credentials.SpotifyUser, playlistId, tracks)
321
-					if err != nil {
322
-						log.Println("Error updating playlist")
323
-						return err
324
-					}
325
-					_, err = app.db.UpdatePlaylistBySection(section.title, tracks)
326
-					if err != nil {
327
-						return err
328
 					}
349
 					}
329
 				}
350
 				}
330
-
331
 			}
351
 			}
332
 
352
 
333
 			if message != "" {
353
 			if message != "" {
334
 
354
 
335
 				_, err := wiki.EditWikiPageSection(title, section.index, changedWikiText,
355
 				_, err := wiki.EditWikiPageSection(title, section.index, changedWikiText,
336
 					fmt.Sprintf("Calculate averages for week %d", weekNumber))
356
 					fmt.Sprintf("Calculate averages for week %d", weekNumber))
337
-				err = nil
357
+				//err = errors.New("foo")
338
 				if err != nil {
358
 				if err != nil {
339
 					return err
359
 					return err
340
 				}
360
 				}
397
 		panic(err)
417
 		panic(err)
398
 	}
418
 	}
399
 
419
 
400
-	a := App{InitDatabase(), creds, nil}
420
+	a := App{InitDatabase(), creds, &AppSpotify{}}
401
 	a.LaunchWeb()
421
 	a.LaunchWeb()
402
 
422
 
403
 	gocron.Every(1).Minute().Do(a.AutomateSectionTask)
423
 	gocron.Every(1).Minute().Do(a.AutomateSectionTask)

+ 76 - 15
spotify/spotify.go 파일 보기

1
 package spotify
1
 package spotify
2
 
2
 
3
 import (
3
 import (
4
+	"bytes"
4
 	"context"
5
 	"context"
5
 	"crypto/tls"
6
 	"crypto/tls"
6
 	"encoding/json"
7
 	"encoding/json"
10
 	"golang.org/x/oauth2/clientcredentials"
11
 	"golang.org/x/oauth2/clientcredentials"
11
 	spotifyAuth "golang.org/x/oauth2/spotify"
12
 	spotifyAuth "golang.org/x/oauth2/spotify"
12
 	"io"
13
 	"io"
14
+	"log"
13
 	"net/http"
15
 	"net/http"
14
 	"net/url"
16
 	"net/url"
17
+	"reflect"
15
 	"strings"
18
 	"strings"
16
 )
19
 )
17
 
20
 
138
 	Total int    `json:"total"`
141
 	Total int    `json:"total"`
139
 }
142
 }
140
 
143
 
144
+type SpotifyProfile struct {
145
+	Birthdate    string       `json:"birthdate"`
146
+	Country      string       `json:"country"`
147
+	DisplayName  string       `json:"display_name"`
148
+	Email        string       `json:"email"`
149
+	ExternalUrls ExternalUrls `json:"external_urls"`
150
+	Followers    Followers    `json:"followers"`
151
+	Id           string       `json:"id"`
152
+	Product      string       `json:"product"`
153
+	Type         string       `json:"type"`
154
+	Uri          string       `json:"uri"`
155
+}
156
+
141
 func NewClient(username, secret string) *SpotifyClient {
157
 func NewClient(username, secret string) *SpotifyClient {
142
 	baseURL, _ := url.Parse("https://api.spotify.com")
158
 	baseURL, _ := url.Parse("https://api.spotify.com")
143
 	httpClient := &http.Client{}
159
 	httpClient := &http.Client{}
157
 	}
173
 	}
158
 	token, err := config.Token(context.Background())
174
 	token, err := config.Token(context.Background())
159
 	if err != nil {
175
 	if err != nil {
160
-		fmt.Println(err)
176
+		log.Println(err)
161
 		return err
177
 		return err
162
 	}
178
 	}
163
 	s.bearerAuth = token.AccessToken
179
 	s.bearerAuth = token.AccessToken
182
 func (s *SpotifyClient) GetTrack(trackId string) (*TrackInfo, error) {
198
 func (s *SpotifyClient) GetTrack(trackId string) (*TrackInfo, error) {
183
 	var trackInfo TrackInfo
199
 	var trackInfo TrackInfo
184
 	url := s.urlFromBase(fmt.Sprintf("/v1/tracks/%s", trackId))
200
 	url := s.urlFromBase(fmt.Sprintf("/v1/tracks/%s", trackId))
185
-	err := s.doRequest("GET", url, &trackInfo, nil)
201
+	err := s.doRequest("GET", url, &trackInfo, nil, nil)
186
 	if err != nil {
202
 	if err != nil {
187
 		return nil, err
203
 		return nil, err
188
 	} else {
204
 	} else {
195
 	values := &url.Values{}
211
 	values := &url.Values{}
196
 	values.Add("name", name)
212
 	values.Add("name", name)
197
 	url := s.urlFromBase(fmt.Sprintf("/v1/users/%s/playlists", userId))
213
 	url := s.urlFromBase(fmt.Sprintf("/v1/users/%s/playlists", userId))
198
-	err := s.doRequest("POST", url, &playlistInfo, values)
214
+	err := s.doRequest("POST", url, &playlistInfo, values, nil)
199
 	if err != nil {
215
 	if err != nil {
200
 		return nil, err
216
 		return nil, err
201
 	} else {
217
 	} else {
203
 	}
219
 	}
204
 }
220
 }
205
 
221
 
222
+type Playlist struct {
223
+	Uris []string `json:"uris"`
224
+}
225
+
206
 func (s *SpotifyClient) UpdatePlaylist(userId, playlistId string, tracks []string) error {
226
 func (s *SpotifyClient) UpdatePlaylist(userId, playlistId string, tracks []string) error {
207
-	values := &url.Values{}
208
 	uris := make([]string, 0)
227
 	uris := make([]string, 0)
209
 	for _, track := range tracks {
228
 	for _, track := range tracks {
210
 		uris = append(uris, "spotify:track:"+track)
229
 		uris = append(uris, "spotify:track:"+track)
211
 	}
230
 	}
231
+	//playlist := &Playlist{uris}
232
+	values := &url.Values{}
212
 	values.Add("uris", strings.Join(uris, ","))
233
 	values.Add("uris", strings.Join(uris, ","))
213
 
234
 
235
+	result := struct {
236
+		SnapshotID string `json:"snapshot_id"`
237
+	}{}
238
+
214
 	url := s.urlFromBase(fmt.Sprintf("/v1/users/%s/playlists/%s", userId, playlistId))
239
 	url := s.urlFromBase(fmt.Sprintf("/v1/users/%s/playlists/%s", userId, playlistId))
215
-	err := s.doRequest("PUT", url, nil, values)
240
+	err := s.doRequest("PUT", url, &result, values, nil)
216
 	return err
241
 	return err
217
 }
242
 }
218
 
243
 
244
+func (s *SpotifyClient) GetMe() (*SpotifyProfile, error) {
245
+	var profile SpotifyProfile
246
+	url := s.urlFromBase(fmt.Sprintf("/v1/me"))
247
+	err := s.doRequest("GET", url, &profile, nil, nil)
248
+	if err != nil {
249
+		return nil, err
250
+	} else {
251
+		return &profile, nil
252
+	}
253
+}
254
+
219
 func (s *SpotifyClient) urlFromBase(path string) *url.URL {
255
 func (s *SpotifyClient) urlFromBase(path string) *url.URL {
220
 	endpoint := &url.URL{Path: path}
256
 	endpoint := &url.URL{Path: path}
221
 	return s.baseURL.ResolveReference(endpoint)
257
 	return s.baseURL.ResolveReference(endpoint)
222
 }
258
 }
223
 
259
 
224
-func (s *SpotifyClient) doRequest(method string, url *url.URL, object interface{}, values *url.Values) error {
260
+func (s *SpotifyClient) doRequest(method string, url *url.URL, object interface{}, values *url.Values, inputBody interface{}) error {
225
 	var bodyReader io.Reader
261
 	var bodyReader io.Reader
226
-	if values != nil {
262
+	var contentType string
263
+	if inputBody != nil {
264
+
265
+		//pr, pw := io.Pipe()
266
+		//go func() {
267
+		//	err := json.NewEncoder(pw).Encode(&inputBody)
268
+		//	pw.Close()
269
+		//	if err != nil {
270
+		//		log.Printf("Spotify: Encoding body failed: %s\n", err.Error())
271
+		//	}
272
+		//}()
273
+
274
+		var buf bytes.Buffer
275
+		err := json.NewEncoder(&buf).Encode(&inputBody)
276
+		log.Printf("Spotify: Body is '%s'\n", buf.String())
277
+		if err != nil {
278
+			log.Printf("Spotify: Encoding body failed: %s\n", err.Error())
279
+			return err
280
+		}
281
+
282
+		bodyReader = &buf
283
+		contentType = "application/json"
284
+	} else if values != nil {
227
 		s := values.Encode()
285
 		s := values.Encode()
228
 		bodyReader = strings.NewReader(s)
286
 		bodyReader = strings.NewReader(s)
287
+		contentType = "application/x-www-form-urlencoded"
229
 	}
288
 	}
230
 
289
 
231
 	req, err := http.NewRequest(method, url.String(), bodyReader)
290
 	req, err := http.NewRequest(method, url.String(), bodyReader)
232
 	if err != nil {
291
 	if err != nil {
233
 		return err
292
 		return err
234
 	}
293
 	}
294
+	req.Header.Set("Content-Type", contentType)
235
 
295
 
236
 	if s.bearerAuth != "" {
296
 	if s.bearerAuth != "" {
237
 		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", s.bearerAuth))
297
 		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", s.bearerAuth))
238
 	}
298
 	}
239
 
299
 
240
-	if values != nil {
241
-		req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
242
-	}
243
-
244
 	req.Header.Set("Accept", "application/json")
300
 	req.Header.Set("Accept", "application/json")
245
 	req.Header.Set("User-Agent", "github.com/lamperi/e4bot/spotify")
301
 	req.Header.Set("User-Agent", "github.com/lamperi/e4bot/spotify")
246
 
302
 
303
+	log.Printf("Spotify: %s %s\n", method, url.Path)
304
+
247
 	resp, err := s.httpClient.Do(req)
305
 	resp, err := s.httpClient.Do(req)
248
 	if err != nil {
306
 	if err != nil {
249
 		return err
307
 		return err
256
 		return errors.New(fmt.Sprintf("Spotify API returned: %d: %s", resp.StatusCode, errorResp.Error.Message))
314
 		return errors.New(fmt.Sprintf("Spotify API returned: %d: %s", resp.StatusCode, errorResp.Error.Message))
257
 	}
315
 	}
258
 
316
 
259
-	err = json.NewDecoder(resp.Body).Decode(object)
260
-	if err != nil {
261
-		return err
317
+	if object != nil {
318
+		log.Printf("Spotify: Trying to decode payload %s\n", reflect.TypeOf(object))
319
+		err = json.NewDecoder(resp.Body).Decode(object)
320
+		if err != nil {
321
+			return err
322
+		}
262
 	}
323
 	}
263
 	return nil
324
 	return nil
264
 
325
 
286
 		return err
347
 		return err
287
 	}
348
 	}
288
 
349
 
289
-	fmt.Println("Got token from Spotify", token)
350
+	log.Println("Got token from Spotify", token)
290
 
351
 
291
 	client := s.config.Client(s.context, token)
352
 	client := s.config.Client(s.context, token)
292
 	s.httpClient = client
353
 	s.httpClient = client

+ 38 - 13
web.go 파일 보기

1
 package main
1
 package main
2
 
2
 
3
 import (
3
 import (
4
-	"github.com/lamperi/e4bot/spotify"
4
+	"github.com/zmb3/spotify"
5
 	"html/template"
5
 	"html/template"
6
 	"log"
6
 	"log"
7
 	"net/http"
7
 	"net/http"
8
 	"strings"
8
 	"strings"
9
+	"time"
9
 )
10
 )
10
 
11
 
11
 var (
12
 var (
20
 
21
 
21
 	data := struct {
22
 	data := struct {
22
 		Username string
23
 		Username string
24
+		Spotify  string
23
 		Songs    []*Song
25
 		Songs    []*Song
24
 	}{
26
 	}{
27
+		"",
25
 		"",
28
 		"",
26
 		make([]*Song, 0),
29
 		make([]*Song, 0),
27
 	}
30
 	}
36
 		}
39
 		}
37
 		data.Songs = songs
40
 		data.Songs = songs
38
 		data.Username = session.username
41
 		data.Username = session.username
42
+		data.Spotify = session.spotify
39
 	}
43
 	}
40
 
44
 
41
 	var templates = cachedTemplates
45
 	var templates = cachedTemplates
83
 	url := r.Form.Get("url")
87
 	url := r.Form.Get("url")
84
 
88
 
85
 	if artist == "" && title == "" && url != "" {
89
 	if artist == "" && title == "" && url != "" {
86
-		log.Println("Resolving Spotify URL")
87
-		trackID := getTrackID(url)
88
-		err := s.spotifyClient.Authenticate()
90
+		if s.spotify.client == nil {
91
+			http.Error(w, "No Spotify token available", http.StatusInternalServerError)
92
+			return
93
+		}
94
+		token, err := s.spotify.client.Token()
89
 		if err != nil {
95
 		if err != nil {
90
 			http.Error(w, err.Error(), http.StatusInternalServerError)
96
 			http.Error(w, err.Error(), http.StatusInternalServerError)
91
 			return
97
 			return
98
+		} else if token.Expiry.Before(time.Now()) {
99
+			http.Error(w, "Spotify token expired", http.StatusInternalServerError)
100
+			return
92
 		}
101
 		}
93
-		track, err := s.spotifyClient.GetTrack(trackID)
102
+
103
+		log.Println("Resolving Spotify URL")
104
+		trackID := getTrackID(url)
105
+		track, err := s.spotify.client.GetTrack(spotify.ID(trackID))
94
 
106
 
95
 		if err != nil {
107
 		if err != nil {
96
 			http.Error(w, err.Error(), http.StatusInternalServerError)
108
 			http.Error(w, err.Error(), http.StatusInternalServerError)
107
 			}
119
 			}
108
 		}
120
 		}
109
 		title = track.Name
121
 		title = track.Name
110
-		url = track.ExternalUrls.Spotify
122
+		url = track.ExternalURLs["spotify"]
111
 	}
123
 	}
112
 
124
 
113
 	updated, err := s.db.UpdateEntry(session.username, round, artist, title, url)
125
 	updated, err := s.db.UpdateEntry(session.username, round, artist, title, url)
150
 }
162
 }
151
 
163
 
152
 func (s *WebService) SpotifyHandler(w http.ResponseWriter, r *http.Request) {
164
 func (s *WebService) SpotifyHandler(w http.ResponseWriter, r *http.Request) {
153
-	url := s.spotifyClient.GetAuthUrl("foobar")
165
+	url := s.spotify.auth.AuthURL("foobar")
154
 	http.Redirect(w, r, url, http.StatusTemporaryRedirect)
166
 	http.Redirect(w, r, url, http.StatusTemporaryRedirect)
155
 }
167
 }
156
 
168
 
157
 func (s *WebService) CallbackHandler(w http.ResponseWriter, r *http.Request) {
169
 func (s *WebService) CallbackHandler(w http.ResponseWriter, r *http.Request) {
158
 	state := "foobar"
170
 	state := "foobar"
159
-	err := s.spotifyClient.HandleToken(state, r)
171
+	token, err := s.spotify.auth.Token(state, r)
160
 	if err != nil {
172
 	if err != nil {
161
 		http.Error(w, "Couldn't get token", http.StatusForbidden)
173
 		http.Error(w, "Couldn't get token", http.StatusForbidden)
162
 		return
174
 		return
163
 	}
175
 	}
176
+	session, err := getSession(r)
177
+	if err != nil {
178
+		http.Error(w, "Couldn't get session", http.StatusInternalServerError)
179
+		return
180
+	}
181
+	client := s.spotify.auth.NewClient(token)
182
+	s.spotify.client = &client
183
+	profile, err := s.spotify.client.CurrentUser()
184
+	if err != nil {
185
+		http.Error(w, "Couldn't load profile from Spotify", http.StatusInternalServerError)
186
+		return
187
+	}
188
+	session.spotify = profile.ID
164
 	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
189
 	http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
165
 }
190
 }
166
 
191
 
167
 type WebService struct {
192
 type WebService struct {
168
-	db            *DB
169
-	spotifyClient *spotify.SpotifyClient
170
-	noCache       bool
193
+	db      *DB
194
+	spotify *AppSpotify
195
+	noCache bool
171
 }
196
 }
172
 
197
 
173
-func webStart(listenAddr string, db *DB, spotifyClient *spotify.SpotifyClient) {
174
-	service := &WebService{db, spotifyClient, true}
198
+func webStart(listenAddr string, db *DB, spotify *AppSpotify) {
199
+	service := &WebService{db, spotify, true}
175
 
200
 
176
 	mux := http.NewServeMux()
201
 	mux := http.NewServeMux()
177
 
202
 

+ 5 - 0
web/index.html 파일 보기

33
 
33
 
34
     <div class="container">
34
     <div class="container">
35
         {{if .Username }}
35
         {{if .Username }}
36
+        {{if .Spotify}}
37
+        <p>You are logged to Spotify as <strong>{{ .Spotify }}</strong></p>
38
+        {{else}}
39
+        <a href="/spotify"><button style="margin-bottom: 1em">Login with Spotify</button></a>
40
+        {{end}}
36
         {{range .Songs }}
41
         {{range .Songs }}
37
         <div class="row">
42
         <div class="row">
38
             <small style="width: 70px">{{ .RoundName }}</small>
43
             <small style="width: 70px">{{ .RoundName }}</small>