// vim:ts=4:sts=4:sw=4:noet:tw=72 package sc import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "net/url" "regexp" "strconv" "strings" "time" "flokatirc/util" "github.com/sorcix/irc" ) const ( API_URL = "https://robertsspaceindustries.com/api" API_METHOD = "/stats/getCrowdfundStats" QUERY_CIT_URL = "https://robertsspaceindustries.com/citizens/" QUERY_ORG_URL = "https://robertsspaceindustries.com/orgs/" RE_CIT_NAME = `
\s*

\s*(.*)\s*

\s*

` RE_CIT_RECORD = `

\s*UEE Citizen Record\s*#(.*)` RE_CIT_HANDLE = `

\s*Handle name\s*(.*)\s*

` RE_CIT_ORG = `(.*)` RE_CIT_SID = `Spectrum Identification \(SID\)\s*([A-Z0-9]*)` RE_CIT_RANK = `Organization rank\s*(.*)` RE_ORG_NAME = `

(.*) ?/ ?` RE_ORG_COUNT = `(.*) member` RE_ORG_MODEL = `
  • (.*)
  • ` RE_ORG_FOCUS = `
      \s*
    • \s*.*\s*
      \s*
      (.*)
      \s*\s*
      \s*
    • \s*
    • \s*.*\s*
      \s*
      (.*)
      \s*\s*
      \s*
    • \s*
    ` RE_ORG_COMM = `
  • (.*)
  • ` FANS_INT = 1000 FLEET_INT = 1000 FUNDS_INT = 10000 ) var ( sayCh chan string fans = 0 fleet = 0 funds = 0 ) func Init(ch chan string) { log.Println("Initializing sc module") sayCh = ch go scrapeLoop() } func HandleMessage(m *irc.Message) { tok := strings.Split(m.Trailing, " ") if len(tok) < 1 { return } switch tok[0] { case "!scstats": showScStats() case "!cit": if len(tok) > 1 { showCitizen(tok[1]) } case "!org": if len(tok) > 1 { showOrganization(tok[1]) } default: } } func toInt(v interface{}) int { switch v.(type) { case int: return v.(int) case float64: return int(v.(float64)) case string: ret, _ := strconv.Atoi(v.(string)) return ret default: return 0 } } func scrapeLoop() { for { scraper() time.Sleep(1 * time.Minute) } } func scraper() { var data interface{} log.Println("Scraping SC stats") resp, err := http.PostForm(API_URL+API_METHOD, url.Values{"fans": {"true"}, "fleet": {"true"}, "funds": {"true"}}) if err != nil { log.Printf("Error: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Error: %v", err) return } err = json.Unmarshal(body, &data) if err != nil { log.Printf("Error: %v", err) return } stats := data.(map[string]interface{})["data"].(map[string]interface{}) //fmt.Println(stats["fans"].(type)) curFans := toInt(stats["fans"]) curFleet := toInt(stats["fleet"]) curFunds := toInt(stats["funds"]) / 100 nextFans := ((fans / FANS_INT) * FANS_INT) + FANS_INT nextFleet := ((fleet / FLEET_INT) * FLEET_INT) + FLEET_INT nextFunds := ((funds / FUNDS_INT) * FUNDS_INT) + FUNDS_INT if curFans >= nextFans { sayCh <- "*\n*** [SC] Star Citizens: " + util.NumberToString(curFans, '.') } if curFleet >= nextFleet { sayCh <- "*\n*** [SC] The UEE Fleet: " + util.NumberToString(curFleet, '.') } if curFunds >= nextFunds { sayCh <- "*\n*** [SC] Funds raised: " + util.NumberToString(curFunds, '.') } fans = curFans fleet = curFleet funds = curFunds } func showScStats() { sayCh <- "*\n*** SC User and Funding Stats ###" sayCh <- fmt.Sprintf("*\nFans: %s", util.NumberToString(fans, '.')) sayCh <- fmt.Sprintf("*\nFleet: %s", util.NumberToString(fleet, '.')) sayCh <- fmt.Sprintf("*\nFunds: $ %s", util.NumberToString(funds, '.')) } func showCitizen(handle string) { resp, err := http.Get(QUERY_CIT_URL + handle) if err != nil { log.Printf("Error: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Error: %v", err) return } reName := regexp.MustCompile(RE_CIT_NAME) reRecord := regexp.MustCompile(RE_CIT_RECORD) reHandle := regexp.MustCompile(RE_CIT_HANDLE) reOrg := regexp.MustCompile(RE_CIT_ORG) reSid := regexp.MustCompile(RE_CIT_SID) reRank := regexp.MustCompile(RE_CIT_RANK) name := reName.FindStringSubmatch(string(body)) record := reRecord.FindStringSubmatch(string(body)) handle_ := reHandle.FindStringSubmatch(string(body)) org := reOrg.FindStringSubmatch(string(body)) sid := reSid.FindStringSubmatch(string(body)) rank := reRank.FindStringSubmatch(string(body)) if len(name) > 1 { sayCh <- "*\n*** Citizen Info ***" sayCh <- "*\n" + "Name: " + string(name[1]) + " [" + string(handle_[1]) + "]" sayCh <- "*\n" + "URL: " + QUERY_CIT_URL + string(handle_[1]) sayCh <- "*\n" + "UEE #: " + string(record[1]) if len(org) > 1 { sayCh <- "*\n" + "Organization: " + string(org[1]) + " [" + string(sid[1]) + "]" sayCh <- "*\n" + "Rank: " + string(rank[1]) } else { sayCh <- "*\n" + "Organization: " } } else { sayCh <- "*\n" + "*** No Such Citizen ***" } } func showOrganization(handle string) { resp, err := http.Get(QUERY_ORG_URL + handle) if err != nil { log.Printf("Error: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Printf("Error: %v", err) return } reName := regexp.MustCompile(RE_ORG_NAME) reCount := regexp.MustCompile(RE_ORG_COUNT) reModel := regexp.MustCompile(RE_ORG_MODEL) reFocus := regexp.MustCompile(RE_ORG_FOCUS) reComm := regexp.MustCompile(RE_ORG_COMM) name := reName.FindStringSubmatch(string(body)) count := reCount.FindStringSubmatch(string(body)) model := reModel.FindStringSubmatch(string(body)) focus := reFocus.FindStringSubmatch(string(body)) comm := reComm.FindStringSubmatch(string(body)) if len(name) > 1 { sayCh <- "*\n*** Organization Info ***" sayCh <- "*\nName: " + string(name[1]) + " [" + strings.ToUpper(handle) + "]" sayCh <- "*\nURL: " + QUERY_ORG_URL + strings.ToUpper(handle) sayCh <- "*\nMembers: " + string(count[1]) sayCh <- "*\nModel: " + string(model[1]) sayCh <- "*\nCommitment: " + string(comm[1]) sayCh <- "*\nFocus: " + string(focus[1]) + ", " + string(focus[2]) } else { sayCh <- "*\n*** No Such Organization ***" } }