web.go 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package main
  2. import (
  3. "github.com/lamperi/e4bot/spotify"
  4. "html/template"
  5. "log"
  6. "net/http"
  7. "strings"
  8. )
  9. var (
  10. cachedTemplates = template.Must(template.ParseFiles("web/index.html"))
  11. )
  12. func (s *WebService) IndexHandler(w http.ResponseWriter, r *http.Request) {
  13. if r.URL.Path != "/" {
  14. http.Error(w, "Not Found", http.StatusNotFound)
  15. return
  16. }
  17. data := struct {
  18. Username string
  19. Songs []*Song
  20. }{
  21. "",
  22. make([]*Song, 0),
  23. }
  24. session, err := getSession(r)
  25. if session != nil {
  26. songs, err := s.db.FindAllEntries(session.username)
  27. if err != nil {
  28. log.Println("Error while reading entries from database", err)
  29. http.Error(w, err.Error(), http.StatusInternalServerError)
  30. return
  31. }
  32. data.Songs = songs
  33. data.Username = session.username
  34. }
  35. var templates = cachedTemplates
  36. if s.noCache {
  37. templates = template.Must(template.ParseFiles("web/index.html"))
  38. }
  39. err = templates.ExecuteTemplate(w, "index.html", data)
  40. if err != nil {
  41. log.Println("Error while rendering template", err)
  42. http.Error(w, err.Error(), http.StatusInternalServerError)
  43. }
  44. }
  45. func getTrackID(url string) string {
  46. const externalURLPrefix = "https://open.spotify.com/track/"
  47. const trackURIPrefix = "spotify:track:"
  48. if strings.HasPrefix(url, externalURLPrefix) {
  49. return strings.Split(url, externalURLPrefix)[1]
  50. } else if strings.HasPrefix(url, trackURIPrefix) {
  51. return strings.Split(url, trackURIPrefix)[1]
  52. }
  53. return url
  54. }
  55. func (s *WebService) UpdateHandler(w http.ResponseWriter, r *http.Request) {
  56. if r.URL.Path != "/update" {
  57. http.Error(w, "Forbidden", http.StatusForbidden)
  58. return
  59. }
  60. session, err := getSession(r)
  61. if session == nil {
  62. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  63. return
  64. }
  65. err = r.ParseForm()
  66. if err != nil {
  67. http.Error(w, err.Error(), http.StatusBadRequest)
  68. return
  69. }
  70. round := r.Form.Get("round")
  71. artist := r.Form.Get("artist")
  72. title := r.Form.Get("title")
  73. url := r.Form.Get("url")
  74. if artist == "" && title == "" && url != "" {
  75. log.Println("Resolving Spotify URL")
  76. trackID := getTrackID(url)
  77. err := s.spotifyClient.Authenticate()
  78. if err != nil {
  79. http.Error(w, err.Error(), http.StatusInternalServerError)
  80. return
  81. }
  82. track, err := s.spotifyClient.GetTrack(trackID)
  83. if err != nil {
  84. http.Error(w, err.Error(), http.StatusInternalServerError)
  85. return
  86. }
  87. log.Printf("Found Track with name %v and artists %v\n", track.Name, track.Artists)
  88. for index, trackArtist := range track.Artists {
  89. if index == 0 {
  90. artist = trackArtist.Name
  91. } else if index == 1 {
  92. artist = artist + " feat. " + trackArtist.Name
  93. } else {
  94. artist = artist + ", " + trackArtist.Name
  95. }
  96. }
  97. title = track.Name
  98. url = track.ExternalUrls.Spotify
  99. }
  100. updated, err := s.db.UpdateEntry(session.username, round, artist, title, url)
  101. if err != nil {
  102. http.Error(w, err.Error(), http.StatusInternalServerError)
  103. return
  104. }
  105. if !updated {
  106. http.Error(w, "No round in DB", http.StatusNotFound)
  107. return
  108. }
  109. log.Printf("Updated song for round %s, artist: %s, title: %s, URL: %s",
  110. round, artist, title, url)
  111. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  112. }
  113. func (s *WebService) LoginHandler(w http.ResponseWriter, r *http.Request) {
  114. err := r.ParseForm()
  115. if err != nil {
  116. http.Error(w, err.Error(), http.StatusBadRequest)
  117. return
  118. }
  119. username := r.Form.Get("username")
  120. password := r.Form.Get("password")
  121. remember := r.Form.Get("remember")
  122. longer := remember == "remember-me"
  123. cookie, err := tryLogin(s.db, username, password, longer)
  124. if err != nil {
  125. log.Println("Error while trying to login", err.Error())
  126. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  127. return
  128. }
  129. http.SetCookie(w, &cookie)
  130. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  131. }
  132. func (s *WebService) SpotifyHandler(w http.ResponseWriter, r *http.Request) {
  133. url := s.spotifyClient.GetAuthUrl("foobar")
  134. http.Redirect(w, r, url, http.StatusTemporaryRedirect)
  135. }
  136. func (s *WebService) CallbackHandler(w http.ResponseWriter, r *http.Request) {
  137. state := "foobar"
  138. err := s.spotifyClient.HandleToken(state, r)
  139. if err != nil {
  140. http.Error(w, "Couldn't get token", http.StatusForbidden)
  141. return
  142. }
  143. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  144. }
  145. type WebService struct {
  146. db *DB
  147. spotifyClient *spotify.SpotifyClient
  148. noCache bool
  149. }
  150. func webStart(listenAddr string, db *DB, spotifyClient *spotify.SpotifyClient) {
  151. service := &WebService{db, spotifyClient, true}
  152. mux := http.NewServeMux()
  153. fs := http.FileServer(http.Dir("web"))
  154. mux.Handle("/css/", fs)
  155. mux.Handle("/fonts/", fs)
  156. mux.Handle("/js/", fs)
  157. mux.Handle("/favicon.ico", fs)
  158. mux.HandleFunc("/", service.IndexHandler)
  159. mux.HandleFunc("/update", service.UpdateHandler)
  160. mux.HandleFunc("/login", service.LoginHandler)
  161. mux.HandleFunc("/spotify", service.SpotifyHandler)
  162. mux.HandleFunc("/callback", service.CallbackHandler)
  163. http.ListenAndServe(listenAddr, mux)
  164. }