153 lines
3.4 KiB
Go
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",
|
|
}
|