diff options
| author | Thibaut Horel <thibaut.horel@gmail.com> | 2016-11-19 17:35:07 -0500 |
|---|---|---|
| committer | Thibaut Horel <thibaut.horel@gmail.com> | 2016-11-19 17:35:07 -0500 |
| commit | c2c39cc2756230c1de29d8065b8b320f2f084045 (patch) | |
| tree | baf3569f25b0fabeb93144d636bf61a2deae6b4a /main.go | |
| download | lastfm-api-c2c39cc2756230c1de29d8065b8b320f2f084045.tar.gz | |
Initial commit
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 161 |
1 files changed, 161 insertions, 0 deletions
@@ -0,0 +1,161 @@ +package main + +import ( + "errors" + "fmt" + "net/http" + "net/http/httputil" + "net/url" + "sort" + "strconv" + "time" +) + +func mainHandler(ds DataStore, w http.ResponseWriter, r *http.Request) { + r.ParseForm() + if _, ok := r.Form["hs"]; ok { + + protocol := r.FormValue("p") + if protocol != "1.2.1" && protocol != "1.2" { + fmt.Fprintf(w, "FAILED Protocol mismatch\n") + return + } + + timestamp := r.FormValue("t") + ts, err := strconv.ParseInt(timestamp, 10, 0) + if err != nil { + fmt.Fprintf(w, "FAILED Invalid timestamp\n") + return + } + + delta := time.Now().Unix() - ts + if delta > 30 || delta < -30 { + fmt.Fprintf(w, "BADTIME\n") + return + } + + user := r.FormValue("u") + auth := r.FormValue("a") + password, ok := ds.GetPassword(user) + + if (md5hex(password+timestamp) != auth) || !ok { + fmt.Fprintf(w, "BADAUTH\n") + return + } + + client := r.FormValue("c") + s := NewSession(user, client, protocol) + ds.PutSession(s) + fmt.Fprint(w, "OK\n") + fmt.Fprintf(w, "%s\n", s.Key) + fmt.Fprint(w, "http://post.audioscrobbler.com:80/np\n") + fmt.Fprint(w, "http://post.audioscrobbler.com:80/scrobble\n") + } else { + fmt.Fprintf(w, "<html>This is an endpoint, see <a href=\"http://www.last.fm/api/submissions\">here</a></html>") + } +} + +func parseValues(values url.Values) map[int]url.Values { + parts := make(map[int]url.Values) + var letter string + var idx int + for key, value := range values { + _, err := fmt.Sscanf(key, "%1s[%d]", &letter, &idx) + if err != nil { + continue + } + if _, ok := parts[idx]; !ok { + parts[idx] = make(url.Values) + } + parts[idx][letter] = value + } + return parts +} + +func parsePart(values url.Values) (Scrobble, error) { + var scrobble Scrobble + scrobble.TrackName = values.Get("t") + scrobble.Artist = values.Get("a") + time, err := strconv.Atoi(values.Get("i")) + if err != nil { + return scrobble, errors.New("Could not parse timestamp") + } + scrobble.Time = time + scrobble.Album = values.Get("b") + scrobble.Mbid = values.Get("m") + tn, err := strconv.Atoi(values.Get("n")) + if err != nil { + return scrobble, errors.New("Could not parse track number") + } + scrobble.TrackNumber = tn + duration, err := strconv.Atoi(values.Get("l")) + if err != nil { + return scrobble, errors.New("Could not parse duration") + } + scrobble.Duration = duration + chosen := values.Get("o") + if chosen == "P" || chosen == "" { + scrobble.Chosen = true + } + return scrobble, nil +} + +func parseScrobbles(values url.Values, session *Session) []Scrobble { + scrobbles := make([]Scrobble, 0, 1) + parts := parseValues(values) + keys := make([]int, len(parts)) + i := 0 + for key := range parts { + keys[i] = key + i++ + } + sort.Ints(keys) + for _, key := range keys { + scrobble, err := parsePart(parts[key]) + if err != nil { + continue + } + scrobble.Session = session.Key + scrobbles = append(scrobbles, scrobble) + } + + return scrobbles +} + +func scrobbleHandler(ds DataStore, w http.ResponseWriter, r *http.Request) { + if session, ok := ds.GetSession(r.FormValue("s")); ok { + scrobbles := parseScrobbles(r.Form, session) + ds.PutScrobbles(scrobbles) + fmt.Fprintf(w, "OK\n") + } else { + fmt.Fprintf(w, "BADSESSION\n") + } +} + +func nowPlayingHandler(ds DataStore, w http.ResponseWriter, r *http.Request) { + if _, ok := ds.GetSession(r.FormValue("s")); ok { + fmt.Fprintf(w, "OK\n") + } else { + fmt.Fprintf(w, "BADSESSION\n") + } +} + +type handler func(DataStore, http.ResponseWriter, *http.Request) + +func wrap(ds DataStore, fn handler) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + d, _ := httputil.DumpRequest(r, true) + fmt.Printf("--------------------------\n%s\n", d) + r.ParseForm() + fn(ds, w, r) + } +} + +func main() { + store := NewSqlStore() + http.HandleFunc("/", wrap(store, handler(mainHandler))) + http.HandleFunc("/np", wrap(store, nowPlayingHandler)) + http.HandleFunc("/scrobble", wrap(store, scrobbleHandler)) + http.HandleFunc("/2.0/", wrap(store, ApiHandler)) + http.ListenAndServe(":3001", nil) +} |
