web.go 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package main
  2. import (
  3. "github.com/lamperi/e4bot/spotify"
  4. "html/template"
  5. "log"
  6. "net/http"
  7. "strconv"
  8. "strings"
  9. )
  10. var (
  11. cachedTemplates = template.Must(template.ParseFiles("web/index.html"))
  12. songsChan chan *SongEntry
  13. spotifyClient *spotify.SpotifyClient
  14. )
  15. func indexHandler(w http.ResponseWriter, r *http.Request) {
  16. if r.URL.Path != "/" {
  17. http.Error(w, "Not Found", http.StatusNotFound)
  18. return
  19. }
  20. alsoEmptySongs := SongsFile{
  21. Songs: make([]*SongEntry, 52),
  22. }
  23. for week := 1; week <= 52; week++ {
  24. alsoEmptySongs.Songs[week-1] = &SongEntry{Week: week}
  25. }
  26. username := ""
  27. session, err := getSession(r)
  28. if session != nil {
  29. songs, err := loadDb()
  30. if err != nil {
  31. http.Error(w, err.Error(), http.StatusInternalServerError)
  32. return
  33. }
  34. for _, song := range songs.Songs {
  35. alsoEmptySongs.Songs[song.Week-1] = song
  36. }
  37. username = session.username
  38. }
  39. var templates = cachedTemplates
  40. if true {
  41. templates = template.Must(template.ParseFiles("web/index.html"))
  42. }
  43. data := struct {
  44. Username string
  45. Songs []*SongEntry
  46. }{
  47. username,
  48. alsoEmptySongs.Songs,
  49. }
  50. err = templates.ExecuteTemplate(w, "index.html", data)
  51. if err != nil {
  52. http.Error(w, err.Error(), http.StatusInternalServerError)
  53. }
  54. }
  55. func getTrackID(url string) string {
  56. const externalURLPrefix = "https://open.spotify.com/track/"
  57. const trackURIPrefix = "spotify:track:"
  58. if strings.HasPrefix(url, externalURLPrefix) {
  59. return strings.Split(url, externalURLPrefix)[1]
  60. } else if strings.HasPrefix(url, trackURIPrefix) {
  61. return strings.Split(url, trackURIPrefix)[1]
  62. }
  63. return url
  64. }
  65. func updateHandler(w http.ResponseWriter, r *http.Request) {
  66. if r.URL.Path != "/update" {
  67. http.Error(w, "Forbidden", http.StatusForbidden)
  68. return
  69. }
  70. session, err := getSession(r)
  71. if session == nil {
  72. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  73. return
  74. }
  75. err = r.ParseForm()
  76. if err != nil {
  77. http.Error(w, err.Error(), http.StatusBadRequest)
  78. return
  79. }
  80. week, err := strconv.Atoi(r.Form.Get("week"))
  81. if err != nil {
  82. http.Error(w, "week parameter not provided", http.StatusBadRequest)
  83. return
  84. }
  85. artist := r.Form.Get("artist")
  86. title := r.Form.Get("title")
  87. url := r.Form.Get("url")
  88. sync := r.Form.Get("sync")
  89. if artist == "" && title == "" && url != "" {
  90. log.Println("Resolving Spotify URL")
  91. trackID := getTrackID(url)
  92. err := spotifyClient.Authenticate()
  93. if err != nil {
  94. http.Error(w, err.Error(), http.StatusInternalServerError)
  95. return
  96. }
  97. track, err := spotifyClient.GetTrack(trackID)
  98. if err != nil {
  99. http.Error(w, err.Error(), http.StatusInternalServerError)
  100. return
  101. }
  102. log.Printf("Found Track with name %v and artists %v\n", track.Name, track.Artists)
  103. for index, trackArtist := range track.Artists {
  104. if index == 0 {
  105. artist = trackArtist.Name
  106. } else if index == 1 {
  107. artist = artist + " feat. " + trackArtist.Name
  108. } else {
  109. artist = artist + ", " + trackArtist.Name
  110. }
  111. }
  112. title = track.Name
  113. url = track.ExternalUrls.Spotify
  114. }
  115. songs, err := loadDb()
  116. if err != nil {
  117. http.Error(w, err.Error(), http.StatusInternalServerError)
  118. return
  119. }
  120. matched := false
  121. for _, song := range songs.Songs {
  122. if song.Week == week {
  123. song.Artist = artist
  124. song.Title = title
  125. song.URL = url
  126. if song.Sync && sync != "on" {
  127. song.Sync = false
  128. }
  129. songsChan <- song
  130. matched = true
  131. }
  132. }
  133. if !matched {
  134. song := &SongEntry{
  135. Artist: artist,
  136. Title: title,
  137. URL: url,
  138. Week: week,
  139. }
  140. songs.Songs = append(songs.Songs, song)
  141. songsChan <- song
  142. }
  143. err = saveDb(songs)
  144. if err != nil {
  145. http.Error(w, err.Error(), http.StatusInternalServerError)
  146. return
  147. }
  148. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  149. }
  150. func loginHandler(w http.ResponseWriter, r *http.Request) {
  151. err := r.ParseForm()
  152. if err != nil {
  153. http.Error(w, err.Error(), http.StatusBadRequest)
  154. return
  155. }
  156. username := r.Form.Get("username")
  157. password := r.Form.Get("password")
  158. remember := r.Form.Get("remember")
  159. longer := remember == "remember-me"
  160. cookie, err := tryLogin(username, password, longer)
  161. if err != nil {
  162. log.Println("Error while trying to login", err.Error())
  163. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  164. return
  165. }
  166. http.SetCookie(w, &cookie)
  167. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  168. }
  169. func webStart(listenAddr string, modifiedSongChan chan *SongEntry, spot *spotify.SpotifyClient) {
  170. songsChan = modifiedSongChan
  171. spotifyClient = spot
  172. mux := http.NewServeMux()
  173. fs := http.FileServer(http.Dir("web"))
  174. mux.Handle("/css/", fs)
  175. mux.Handle("/fonts/", fs)
  176. mux.Handle("/js/", fs)
  177. mux.Handle("/favicon.ico", fs)
  178. mux.HandleFunc("/", indexHandler)
  179. mux.HandleFunc("/update", updateHandler)
  180. mux.HandleFunc("/login", loginHandler)
  181. http.ListenAndServe(listenAddr, mux)
  182. }