// vi:ts=4:sts=4:sw=4:noet:tw=72 package modules import ( "encoding/json" "flag" "fmt" "html" "io/ioutil" "net/http" "net/url" "regexp" "strings" "time" "git.dnix.de/an/flokatilib/util" "git.dnix.de/an/xlog" ) 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 = 50000 ) var ( fans = 0 fleet = 0 funds = 0 targetChannel = flag.String("sc_target_channel", "", "Default channel for stats output") ) func init() { MsgFuncs["sc"] = scHandleMessage RunFuncs["sc"] = scScrapeLoop } func scHandleMessage(m *Message) { tok := strings.Split(m.Text, " ") if len(tok) < 1 { return } switch tok[0] { case "!scstats": showScStats(m.Channel) case "!sccit": if len(tok) > 1 { showCitizen(tok[1], m.Channel) } case "!scorg": if len(tok) > 1 { showOrganization(tok[1], m.Channel) } default: } } func scScrapeLoop() { for { scScraper() time.Sleep(1 * time.Minute) } } func scScraper() { var data interface{} xlog.Info("Scraping SC stats") resp, err := http.PostForm(API_URL+API_METHOD, url.Values{"fans": {"true"}, "fleet": {"true"}, "funds": {"true"}}) if err != nil { xlog.Info("Error: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { xlog.Info("Error: %v", err) return } err = json.Unmarshal(body, &data) if err != nil { xlog.Info("Error: %v", err) return } stats := data.(map[string]interface{})["data"].(map[string]interface{}) //fmt.Println(stats["fans"].(type)) curFans := util.ToInt(stats["fans"]) curFleet := util.ToInt(stats["fleet"]) curFunds := util.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 <- *targetChannel + "\n[SC] Star Citizens: " + util.NumberToString(curFans, '.') } if curFleet >= nextFleet { SayCh <- *targetChannel + "\n[SC] The UEE Fleet: " + util.NumberToString(curFleet, '.') } if curFunds >= nextFunds { SayCh <- *targetChannel + "\n[SC] Funds raised: " + util.NumberToString(curFunds, '.') } fans = curFans fleet = curFleet funds = curFunds } func showScStats(channel string) { SayCh <- channel + "\n**SC User and Funding Stats**" SayCh <- fmt.Sprintf("%s\nFans: %s", channel, util.NumberToString(fans, '.')) SayCh <- fmt.Sprintf("%s\nFleet: %s", channel, util.NumberToString(fleet, '.')) SayCh <- fmt.Sprintf("%s*\nFunds: $ %s", channel, util.NumberToString(funds, '.')) } func showCitizen(handle, channel string) { resp, err := http.Get(QUERY_CIT_URL + handle) if err != nil { xlog.Info("Error: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { xlog.Info("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 <- channel + "\n**Citizen Info**" SayCh <- channel + "\nName: " + html.UnescapeString(string(name[1])) + " [" + string(handle_[1]) + "]" SayCh <- channel + "\nURL: " + QUERY_CIT_URL + string(handle_[1]) SayCh <- channel + "\nUEE #: " + string(record[1]) if len(org) > 1 { SayCh <- channel + "\nOrganization: " + html.UnescapeString(string(org[1])) + " [" + string(sid[1]) + "]" SayCh <- channel + "\nRank: " + html.UnescapeString(string(rank[1])) } else { SayCh <- channel + "\nOrganization: " } } else { SayCh <- channel + "\n***No Such Citizen***" } } func showOrganization(handle, channel string) { resp, err := http.Get(QUERY_ORG_URL + handle) if err != nil { xlog.Info("Error: %v", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { xlog.Info("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 <- channel + "\n**Organization Info**" SayCh <- channel + "\nName: " + string(name[1]) + " [" + strings.ToUpper(handle) + "]" SayCh <- channel + "\nURL: " + QUERY_ORG_URL + strings.ToUpper(handle) SayCh <- channel + "\nMembers: " + string(count[1]) SayCh <- channel + "\nModel: " + string(model[1]) SayCh <- channel + "\nCommitment: " + string(comm[1]) SayCh <- channel + "\nFocus: " + string(focus[1]) + ", " + string(focus[2]) } else { SayCh <- channel + "\n***No Such Organization***" } }