Created
January 1, 2014 22:42
-
-
Save antzucaro/8212369 to your computer and use it in GitHub Desktop.
Pulls listened tracks from a given user's Last.fm account between the provided time bounds, dumping the results to a file "tracks.csv". Usage: go run summarizr.go -user <username> -key <Last.fm API key> -from <Unix timestamp> -to <Unix timestamp>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Generate the data (timestamps represent the entirety of 2013): | |
go run summarizr.go -user antzucaro -key MY_API_KEY -from 1357016400 -to 1388552340 | |
This produces a file "tracks.csv" with the selected range of data (8173 songs in total for me). One can load these tracks to a database easily with the below steps. | |
Create the database: | |
postgres=# create database tracks2013 encoding='utf-8'; | |
CREATE DATABASE | |
postgres=# \c tracks2013 | |
You are now connected to database "tracks2013". | |
Create the table for the tracks: | |
tracks2013=# create table tracks ( | |
tracks2013(# artist character varying(100), | |
tracks2013(# album character varying(100), | |
tracks2013(# song character varying(100), | |
tracks2013(# date int | |
tracks2013(# ); | |
CREATE TABLE | |
Load the generated CSV file into the table we just created: | |
tracks2013=# copy tracks from '/home/ant/tracks.csv' with (format csv); | |
COPY 8173 | |
From there you can query until your heart is content! Here are some example queries: | |
Which artists did you listen to the most? | |
select artist, count(*) from tracks group by artist order by count(*) desc; | |
How many different artists did you listen to? | |
select count(distinct artist) from tracks; | |
How many tracks did you listen to per month? | |
select extract(month from to_timestamp(date)), count(*) | |
from tracks | |
group by extract(month from to_timestamp(date)) | |
order by extract(month from to_timestamp(date)); | |
Which artists did you listen to the most by month? | |
select artist, mon, plays | |
from ( | |
select artist, extract(month from to_timestamp(date)) mon, count(*) plays, rank(). | |
over (partition by extract(month from to_timestamp(date)) order by count(*) desc) rank | |
from tracks group by artist, extract(month from to_timestamp(date)) | |
order by extract(month from to_timestamp(date)), count(*) desc | |
) trackplays | |
where rank = 1; | |
What song did you listen to the most? | |
select artist, song, count(*) from tracks group by artist, song order by count(*) desc; | |
How many different artists did we listen to, per month? | |
select extract(month from to_timestamp(date)), count(distinct artist) | |
from tracks | |
group by extract(month from to_timestamp(date)) | |
order by extract(month from to_timestamp(date));) | |
Enjoy! | |
-Ant "Antibody" Zucaro |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/csv" | |
"encoding/xml" | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"net/http" | |
"os" | |
"strconv" | |
"time" | |
) | |
type Date struct { | |
XMLName xml.Name `xml:"date"` | |
Uts int `xml:"uts,attr"` | |
} | |
type Track struct { | |
XMLName xml.Name `xml:"track"` | |
Artist string `xml:"artist"` | |
Album string `xml:"album"` | |
Song string `xml:"name"` | |
Date Date `xml:"date"` | |
} | |
type RecentTracks struct { | |
XMLName xml.Name `xml:"recenttracks"` | |
User string `xml:"user,attr"` | |
CurrentPage int `xml:"page,attr"` | |
TotalPages int `xml:"totalPages,attr"` | |
Tracks []Track `xml:"track"` | |
} | |
type Result struct { | |
XMLName xml.Name `xml:"lfm"` | |
Status string `xml:"status,attr"` | |
RecentTracks RecentTracks | |
} | |
func getPage(user string, key string, from int, page int) *Result { | |
url := fmt.Sprintf("http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=%s&api_key=%s&limit=200&from=%d&page=%d", user, key, from, page) | |
fmt.Println(url) | |
r, err := http.Get(url) | |
defer r.Body.Close() | |
if err != nil { | |
panic("Error making the GET request to user.getrecenttracks.") | |
} | |
body, err := ioutil.ReadAll(r.Body) | |
if err != nil { | |
panic(err) | |
} | |
var rt *Result | |
rt = &Result{} | |
if err := xml.Unmarshal(body, rt); err != nil { | |
panic(err) | |
} | |
return rt | |
} | |
func main() { | |
var user = flag.String("user", "nobody", "user to summarize") | |
var key = flag.String("key", "", "API key to use when fetching") | |
var from = flag.Int("from", 0, "summarize from this time (format: unix timestamp)") | |
var to = flag.Int("to", 0, "summarize to this time (format: unix timestamp)") | |
flag.Parse() | |
f, err := os.Create("tracks.csv") | |
if err != nil { | |
panic(err) | |
} | |
defer f.Close() | |
c := csv.NewWriter(f) | |
page := 1 | |
for rt := getPage(*user, *key, *from, page); page <= rt.RecentTracks.TotalPages; rt = getPage(*user, *key, *from, page) { | |
for _, v := range rt.RecentTracks.Tracks { | |
if v.Date.Uts >= *from && v.Date.Uts <= *to { | |
c.Write([]string{v.Artist, v.Album, v.Song, strconv.Itoa(v.Date.Uts)}) | |
} | |
} | |
time.Sleep(500 * time.Millisecond) | |
page++ | |
} | |
c.Flush() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment