Skip to content

Instantly share code, notes, and snippets.

@kbl
Created Jan 27, 2018
Embed
What would you like to do?
Mathandel script
package main
import (
"fmt"
"net/http"
"log"
"io/ioutil"
"strings"
"encoding/xml"
"strconv"
"regexp"
)
const geekList = "https://www.boardgamegeek.com/xmlapi/geeklist/235895"
const geekListFile = "/home/mapi/Desktop/235895.xml"
const gameTemplate = "https://www.boardgamegeek.com/xmlapi/boardgame/%d?pricehistory=1&stats=1"
const gameTemplateFile = "/home/mapi/Desktop/126000.xml"
type Geeklist struct {
XMLName xml.Name `xml:"geeklist"`
Items []Item `xml:"item"`
}
type Item struct {
Ordinal int `xml:"id,attr"`
GameId int `xml:"objectid,attr"`
Name string `xml:"objectname,attr"`
Description string `xml:"body"`
}
type Boardgames struct {
XMLName xml.Name `xml:"boardgames"`
Boardgame Boardgame `xml:"boardgame"`
}
type Boardgame struct {
Year int `xml:"yearpublished"`
Awards []string `xml:"boardgamehonor"`
Categories []string `xml:"boardgamecategory"`
Mechanics []string `xml:"boardgamemechanic"`
Rating float64 `xml:"statistics>ratings>average"`
Geekrating float64 `xml:"statistics>ratings>bayesaverage"`
Listings []Listing `xml:"marketplacehistory>listing"`
}
type Listing struct {
Body string `xml:",innerxml"`
}
// ---
type GameMetadata struct {
Name string
Id int
Year int
Awards int
Mechanics []string
Categories []string
Rating float64
PriceUSD float64
PriceEUR float64
}
func main() {
fmt.Println(1)
r := fetchUrl(geekList)
var geeklist Geeklist
xml.Unmarshal(r, &geeklist)
ch := make(chan GameMetadata)
gameNames := make(map[int]string)
gameOccurences := make(map[int][]int)
gameMetas := make(map[int]GameMetadata)
for i, g := range geeklist.Items {
gameNames[g.GameId] = g.Name
gameOccurences[g.GameId] = append(gameOccurences[g.GameId], i + 1)
}
fmt.Println(len(gameNames))
for id, name := range gameNames {
if id > 500 {
break
}
go fetchGameMetadata(ch, id, name)
}
for i, _ := range gameNames {
meta := <-ch
fmt.Sprintln("dong %d! ", (i + 1))
gameMetas[meta.Id] = meta
}
fmt.Println(gameMetas)
}
func fetchGameMetadata(ch chan<- GameMetadata, id int, name string) GameMetadata {
r := fetchUrl(fmt.Sprintf(gameTemplate, id))
var boardgames Boardgames
xml.Unmarshal(r, &boardgames)
game := boardgames.Boardgame
prices := countAveragePrice(game.Listings)
var priceUSD float64
if val, ok := prices["USD,new"]; ok {
priceUSD = val
} else if val, ok := prices["USD,likenew"]; ok {
priceUSD = val
}
var priceEUR float64
if val, ok := prices["EUR,new"]; ok {
priceEUR = val
} else if val, ok := prices["EUR,likenew"]; ok {
priceEUR = val
}
return GameMetadata{
name,
id,
game.Year,
len(game.Awards),
game.Mechanics,
game.Categories,
game.Rating,
priceUSD,
priceEUR}
}
func fetchUrl(url string) []byte {
if strings.HasPrefix(url, "http") {
r, err := http.Get(url)
handleErr(err)
defer r.Body.Close()
b, err := ioutil.ReadAll(r.Body)
handleErr(err)
return b
}
b, err := ioutil.ReadFile(url)
handleErr(err)
return b
}
func handleErr(err error) {
if err != nil {
log.Fatal(err)
}
}
func countAveragePrice(listings []Listing) map[string]float64 {
rPrice, err := regexp.Compile("<price currency='(.+)'>([0-9.]+)</price>")
handleErr(err)
rCondition, err := regexp.Compile("<condition>(.+)</condition>")
handleErr(err)
m := make(map[string]map[string][]float64)
for _, l := range listings {
match := rPrice.FindStringSubmatch(l.Body)
currency := match[1]
if currency == "USD" || currency == "EUR" {
price, err := strconv.ParseFloat(match[2], 64)
handleErr(err)
match = rCondition.FindStringSubmatch(l.Body)
condition := match[1]
if condition == "new" || condition == "likenew" {
if m[currency] == nil {
m[currency] = make(map[string][]float64)
}
m[currency][condition] = append(m[currency][condition], price)
}
}
}
ret := make(map[string]float64)
for cur, mm := range m {
for con, prices := range mm {
var sum float64
for _, p := range prices {
sum += p
}
ret[fmt.Sprintf("%s,%s", cur, con)] = sum / float64(len(prices))
}
}
return ret
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment