Track artist popularity
[brackets.git] / routes / artist / artist.go
1 package artist
2
3 import (
4 "database/sql"
5 "encoding/json"
6 "git.jacobcasper.com/brackets/env"
7 "git.jacobcasper.com/brackets/routes"
8 "git.jacobcasper.com/brackets/types"
9 "github.com/zmb3/spotify"
10 "log"
11 "net/http"
12 )
13
14 func Index(env *env.Env) routes.Handler {
15 return func(w http.ResponseWriter, r *http.Request) {
16 if r.Method != "GET" {
17 http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
18 return
19 }
20
21 w.Header().Set("Content-Type", "application/json")
22
23 artistId := r.FormValue("id")
24 if artistId != "" {
25 artist := types.Artist{}
26 row := env.Db.Db.QueryRow(`
27 SELECT ID, NAME, POPULARITY
28 FROM ARTIST
29 WHERE ID = ?`,
30 artistId,
31 )
32 if err := row.Scan(&artist.ID, &artist.Name, &artist.Popularity); err != nil {
33 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
34 return
35 }
36 b, err := json.Marshal(artist)
37 if err != nil {
38 log.Print(err)
39 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
40 return
41 }
42 w.Write(b)
43 return
44 }
45
46 rows, err := env.Db.Db.Query(`
47 SELECT ID, NAME, POPULARITY
48 FROM ARTIST
49 LIMIT 20`,
50 )
51 if err != nil {
52 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
53 return
54 }
55 defer rows.Close()
56
57 artists := make([]types.Artist, 0)
58 for rows.Next() {
59 artist := types.Artist{}
60 if err := rows.Scan(&artist.ID, &artist.Name, &artist.Popularity); err != nil {
61 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
62 return
63 }
64 artists = append(artists, artist)
65 }
66 if err = rows.Err(); err != nil {
67 log.Print(err)
68 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
69 return
70 }
71 b, err := json.Marshal(artists)
72 if err != nil {
73 log.Print(err)
74 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
75 return
76 }
77 w.Write(b)
78 }
79 }
80
81 func Add(env *env.Env) routes.Handler {
82 return func(w http.ResponseWriter, r *http.Request) {
83 if r.Method != "POST" {
84 http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
85 return
86 }
87
88 r.ParseForm()
89 artistId := r.PostForm.Get("id")
90
91 if artistId == "" {
92 http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
93 return
94 }
95
96 artist, err := env.C.GetArtist(spotify.ID(artistId))
97 if err != nil {
98 log.Printf("Failed to retrieve artist %s: %s", artistId, err.Error())
99 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
100 return
101 }
102
103 env.Db.Mu.Lock()
104 defer env.Db.Mu.Unlock()
105 env.Db.Db.Exec(`
106 INSERT INTO ARTIST
107 (ID, NAME, POPULARITY)
108 VALUES (?, ?, ?)`,
109 artist.ID,
110 artist.Name,
111 artist.Popularity,
112 )
113
114 for _, genre := range artist.Genres {
115 var genreId int64
116 row := env.Db.Db.QueryRow(`
117 SELECT ID
118 FROM GENRE
119 WHERE NAME = lower(?)
120 `,
121 genre,
122 )
123
124 err := row.Scan(&genreId)
125 if err == sql.ErrNoRows {
126 result, err := env.Db.Db.Exec(`
127 INSERT INTO GENRE
128 (NAME)
129 VALUES (?)`,
130 genre,
131 )
132 if err != nil {
133 log.Printf("Failed to insert genre %s: %s", genre, err.Error())
134 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
135 return
136 }
137
138 genreId, err = result.LastInsertId()
139 if err != nil {
140 log.Print("Failed to retrieve last insert id: ", err.Error())
141 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
142 return
143 }
144 }
145
146 env.Db.Db.Exec(`
147 INSERT INTO ARTIST_GENRE_XREF
148 (ARTIST_ID, GENRE_ID)
149 VALUES (?, ?)`,
150 artist.ID,
151 genreId,
152 )
153 }
154 w.WriteHeader(http.StatusCreated)
155 }
156 }
157
158 func ByGenre(env *env.Env) routes.Handler {
159 return func(w http.ResponseWriter, r *http.Request) {
160 if r.Method != "GET" {
161 http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
162 return
163 }
164
165 w.Header().Set("Content-Type", "application/json")
166 genreName := r.FormValue("genre_name")
167 if genreName != "" {
168 rows, err := env.Db.Db.Query(`
169 SELECT a.ID, a.NAME
170 FROM ARTIST a
171 JOIN ARTIST_GENRE_XREF x ON a.ID = x.ARTIST_ID
172 JOIN GENRE g ON g.ID = x.GENRE_ID
173 WHERE g.NAME = lower(?)
174 `,
175 genreName,
176 )
177 if err != nil {
178 log.Print(err)
179 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
180 return
181 }
182 defer rows.Close()
183
184 artists := make([]types.Artist, 0)
185 for rows.Next() {
186 artist := types.Artist{}
187 if err := rows.Scan(&artist.ID, &artist.Name, &artist.Popularity); err != nil {
188 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
189 return
190 }
191 artists = append(artists, artist)
192 }
193 if err = rows.Err(); err != nil {
194 log.Print(err)
195 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
196 return
197 }
198 b, err := json.Marshal(artists)
199 if err != nil {
200 log.Print(err)
201 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
202 return
203 }
204 w.Write(b)
205 }
206 }
207 }