yellowcab/scrape/lastfm.go
2023-10-24 17:38:03 -04:00

153 lines
3.4 KiB
Go

package scrape
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"net/url"
"os"
"strconv"
"github.com/joho/godotenv"
)
type lastfm struct {
Name string
}
var LASTFM_KEY string
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
LASTFM_KEY = url.PathEscape(os.Getenv("LASTFM_KEY"))
}
type LastFmObject struct {
Name string `json:"#text"`
Id string `json:"mbid"`
}
type LastFmTime struct {
Unix string `json:"uts"`
Human string `json:"#text"`
}
type LastFmResponse struct {
RecentTracks struct {
Track []struct {
Artist LastFmObject `json:"artist"`
Album LastFmObject `json:"album"`
Name string `json:"name"`
URL string `json:"url"`
Cover []struct {
Size string `json:"size"`
URL string `json:"#text"`
} `json:"image"`
Time *LastFmTime `json:"date"`
Attributes *struct {
NowPlaying string `json:"nowplaying"`
} `json:"@attr,omitempty"`
} `json:"track"`
} `json:"recenttracks"`
}
func (s *lastfm) GetNowPlaying(username string) (response *ScrobblerResponse, err error) {
encodedUsername := url.PathEscape(username)
req, err := http.NewRequest("GET", fmt.Sprintf("https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=%s&api_key=%s&format=json&limit=1", encodedUsername, LASTFM_KEY), nil)
if err != nil {
return
}
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
err = errors.New("Request was unsuccessful, status code: " + strconv.Itoa(resp.StatusCode))
return
}
var lastfmResponseBody LastFmResponse
err = json.NewDecoder(resp.Body).Decode(&lastfmResponseBody)
if len(lastfmResponseBody.RecentTracks.Track) <= 0 {
err = errors.New("no listen history")
return
}
var lastPlayedTimeString string
lastPlayed := lastfmResponseBody.RecentTracks.Track[0]
var lastPlayedTimeMs int64 = 0
if lastPlayed.Attributes != nil && lastPlayed.Attributes.NowPlaying == "true" {
lastPlayedTimeString = "live"
} else if lastPlayed.Time != nil {
lastPlayedTimeString = lastPlayed.Time.Human
lastPlayedTimeMs, err = strconv.ParseInt(lastPlayed.Time.Unix, 10, 64)
if err != nil {
return
}
lastPlayedTimeMs *= 1000
} else {
fmt.Println(lastPlayed, *lastPlayed.Attributes)
err = errors.New("LastFM API response is missing timestamp")
return
}
trackURL := lastPlayed.URL
track := Track{
Name: lastPlayed.Name,
URL: &trackURL,
}
// TODO: implement stream URLs if possible?
var album *Album
if lastPlayed.Album.Name != "" {
album = &Album{
Name: lastPlayed.Album.Name,
URL: nil,
}
}
var artist *Artist
if lastPlayed.Artist.Name != "" {
artist = &Artist{
Name: lastPlayed.Artist.Name,
URL: nil,
}
}
response = &ScrobblerResponse{
FromScrobbler: FromScrobbler{
Name: s.Name,
UserURL: fmt.Sprintf("https://www.last.fm/user/%s/", encodedUsername),
},
Track: track,
Artist: artist,
Album: album,
EstTimestamp: lastPlayedTimeString,
TimestampMs: lastPlayedTimeMs,
}
for _, cover := range lastPlayed.Cover {
if cover.Size == "extralarge" && cover.URL != "" {
response.Cover = &(cover.URL)
break
}
}
return
}
var Lastfm = lastfm{
Name: "Last.fm",
}