web.go 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. }
  114. songs, err := loadDb()
  115. if err != nil {
  116. http.Error(w, err.Error(), http.StatusInternalServerError)
  117. return
  118. }
  119. matched := false
  120. for _, song := range songs.Songs {
  121. if song.Week == week {
  122. song.Artist = artist
  123. song.Title = title
  124. song.URL = url
  125. if song.Sync && sync != "on" {
  126. song.Sync = false
  127. }
  128. songsChan <- song
  129. matched = true
  130. }
  131. }
  132. if !matched {
  133. song := &SongEntry{
  134. Artist: artist,
  135. Title: title,
  136. URL: url,
  137. Week: week,
  138. }
  139. songs.Songs = append(songs.Songs, song)
  140. songsChan <- song
  141. }
  142. err = saveDb(songs)
  143. if err != nil {
  144. http.Error(w, err.Error(), http.StatusInternalServerError)
  145. return
  146. }
  147. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  148. }
  149. func loginHandler(w http.ResponseWriter, r *http.Request) {
  150. err := r.ParseForm()
  151. if err != nil {
  152. http.Error(w, err.Error(), http.StatusBadRequest)
  153. return
  154. }
  155. username := r.Form.Get("username")
  156. password := r.Form.Get("password")
  157. remember := r.Form.Get("remember")
  158. longer := remember == "remember-me"
  159. cookie, err := tryLogin(username, password, longer)
  160. if err != nil {
  161. http.Error(w, err.Error(), http.StatusForbidden)
  162. return
  163. }
  164. http.SetCookie(w, &cookie)
  165. http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
  166. }
  167. func webStart(modifiedSongChan chan *SongEntry, spot *spotify.SpotifyClient) {
  168. songsChan = modifiedSongChan
  169. spotifyClient = spot
  170. mux := http.NewServeMux()
  171. fs := http.FileServer(http.Dir("web"))
  172. mux.Handle("/css/", fs)
  173. mux.Handle("/fonts/", fs)
  174. mux.Handle("/js/", fs)
  175. mux.Handle("/favicon.ico", fs)
  176. mux.HandleFunc("/", indexHandler)
  177. mux.HandleFunc("/update", updateHandler)
  178. mux.HandleFunc("/login", loginHandler)
  179. http.ListenAndServe("localhost:8080", mux)
  180. }