Skip to content

Instantly share code, notes, and snippets.

@treed

treed/main.go Secret

Created September 25, 2016 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save treed/9c933f860adedadf4916cabfe6932669 to your computer and use it in GitHub Desktop.
Save treed/9c933f860adedadf4916cabfe6932669 to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/PuerkitoBio/goquery"
"io/ioutil"
"net/http"
"net/url"
"os"
"sort"
"strconv"
"strings"
"text/template"
"time"
)
func linkChannel(channels string) string {
if strings.Contains(channels, "ESPN2") {
return "[](http://espn.go.com/watchespn/index/_/sport/soccer-futbol/channel/espn2)"
} else if strings.Contains(channels, "Fox Sports 1") {
return "[](http://msn.foxsports.com/foxsports1)"
} else if strings.Contains(channels, "UniMas") {
return "[](http://tv.univision.com/unimas)"
} else if strings.Contains(channels, "MLS LIVE") {
return "[](http://live.mlssoccer.com/mlsmdl)"
}
return ""
}
func linkTeam(team string) string {
if strings.Contains(team, "Chicago") {
return "[CHI](http://www.chicago-fire.com)"
} else if strings.Contains(team, "Colorado") {
return "[COL](http://www.coloradorapids.com)"
} else if strings.Contains(team, "Columbus") {
return "[CLB](http://www.thecrew.com)"
} else if strings.Contains(team, "Dallas") {
return "[FCD](http://www.fcdallas.com)"
} else if strings.Contains(team, "D.C. United") {
return "[DC](http://www.dcunited.com)"
} else if strings.Contains(team, "Houston") {
return "[HOU](http://www.houstondynamo.com)"
} else if strings.Contains(team, "Montreal") {
return "[MTL](http://www.impactmontreal.com/en)"
} else if strings.Contains(team, "Galaxy") {
return "[LAG](http://www.lagalaxy.com)"
} else if strings.Contains(team, "Portland") {
return "[POR](http://www.portlandtimbers.com)"
} else if strings.Contains(team, "New England") {
return "[NE](http://www.revolutionsoccer.net)"
} else if strings.Contains(team, "Salt Lake") {
return "[RSL](http://www.realsaltlake.com)"
} else if strings.Contains(team, "New York City") {
return "[NYC](http://www.nycfc.com/)"
} else if strings.Contains(team, "San Jose") {
return "[SJ](http://www.sjearthquakes.com)"
} else if strings.Contains(team, "Red Bull") {
//return "Wings"
return "[NYRB](http://www.newyorkredbulls.com)"
} else if strings.Contains(team, "Orlando") {
return "[OCSC](http://www.orlandocitysc.com/)"
} else if strings.Contains(team, "Seattle") {
return "[SEA](http://www.soundersfc.com)"
} else if strings.Contains(team, "Philadelphia") {
return "[PHI](http://www.philadelphiaunion.com)"
} else if strings.Contains(team, "Sporting") {
return "[SKC](http://www.sportingkc.com)"
} else if strings.Contains(team, "Toronto") {
return "[TFC](http://torontofc.ca)"
} else if strings.Contains(team, "Vancouver") {
return "[VAN](http://www.whitecapsfc.com)"
}
return team
}
type WikiPage struct {
Data struct {
Content string `json:"content_md"`
}
}
func main() {
var err error
reddit := &Reddit{
username: "none",
password: "--",
client: &http.Client{},
}
reddit.Login()
sidebar, err := reddit.Get("https://www.reddit.com/r/mls/wiki/sidebar-template.json")
if err != nil {
fmt.Fprintf(os.Stderr, "Error getting template: %s\n", err)
return
}
var wikiTemplate WikiPage
err = json.Unmarshal(sidebar, &wikiTemplate)
if err != nil {
fmt.Fprintf(os.Stderr, "Error unmarshalling template: %s\n", err)
return
}
templateData := make(map[string]interface{})
templateData["Now"] = time.Now()
templateData["Standings"] = getStandings()
templateData["Schedule"], err = getSchedule()
if err != nil {
fmt.Printf("Error fetching schedule: %s\n", err)
return
}
t := template.New("sidebar")
t.Funcs(template.FuncMap{"link_team": linkTeam, "link_channel": linkChannel})
_, err = t.Parse(wikiTemplate.Data.Content)
if err != nil {
fmt.Fprintf(os.Stderr, "got error parsing template: %s\n, template data:\n%s", err, wikiTemplate.Data.Content)
return
}
//newSidebar := new(bytes.Buffer)
err = t.Execute(os.Stdout, templateData)
if err != nil {
fmt.Fprintf(os.Stderr, "got error executing template: %s\n", err)
return
}
//err = reddit.EditWikiPage("MLSDev", "config/sidebar", newSidebar.String())
//if err != nil {
// return
//}
}
type Reddit struct {
username, password string
cookie string
modhash string
client *http.Client
}
type RedditLoginResponse struct {
JSON struct {
Errors []interface{}
Data struct {
NeedHTTPS bool `json:"need_https"`
HTTSRedir string `json:"hsts_redir"`
Modhash string
Cookie string
}
}
}
func (r *Reddit) Login() (err error) {
loginURL := fmt.Sprintf("https://www.reddit.com/api/login/%s", r.username)
postValues := url.Values{
"user": {r.username},
"passwd": {r.password},
"api_type": {"json"},
}
resp, err := r.Post(loginURL, postValues)
if err != nil {
return
}
loginResponse := new(RedditLoginResponse)
err = json.Unmarshal(resp, loginResponse)
if err != nil {
return
}
r.cookie = loginResponse.JSON.Data.Cookie
r.modhash = loginResponse.JSON.Data.Modhash
return
return
}
type WikiEditRequest struct {
Content string `json:"content"`
Page string `json:"string"`
}
func (r *Reddit) EditWikiPage(subreddit, page, content string) (err error) {
body, err := json.Marshal(&WikiEditRequest{Content: content, Page: page})
if err != nil {
return
}
req, err := http.NewRequest("POST", fmt.Sprintf("https://www.reddit.com/r/%s/api/wiki/edit.json", subreddit), bytes.NewBuffer(body))
if err != nil {
return
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "linux:rMLSBot:v0.9.0 (by /u/tedreed)")
if r.cookie != "" {
req.Header.Set("Cookie", "reddit_session="+r.cookie)
}
if r.modhash != "" {
req.Header.Set("X-Modhash", r.modhash)
}
resp, err := r.client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
fmt.Fprintf(os.Stderr, "%s", body)
return
}
func (r *Reddit) Post(url string, values url.Values) (body []byte, err error) {
req, err := http.NewRequest("POST", url, strings.NewReader(values.Encode()))
if err != nil {
return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("User-Agent", "linux:rMLSBot:v0.9.0 (by /u/tedreed)")
resp, err := r.client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
return
}
func (r *Reddit) Get(url string) (body []byte, err error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return
}
req.Header.Set("User-Agent", "linux:rMLSBot:v0.9.0 (by /u/tedreed)")
if r.cookie != "" {
req.Header.Set("Cookie", "reddit_session="+r.cookie)
}
if r.modhash != "" {
req.Header.Set("X-Modhash", r.modhash)
}
resp, err := r.client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
return
}
type Standing struct {
Conference, Team string
Position, Points, GamesPlayed, GoalsFor, GoalDifference, Wins int64
}
func (s *Standing) String() string {
return fmt.Sprintf("%s%d %s %d %d %d %d", s.Conference, s.Position, s.Team, s.Points, s.GamesPlayed, s.GoalDifference, s.GoalsFor)
}
type Standings []*Standing
func (s Standings) Len() int { return len(s) }
func (s Standings) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s Standings) Less(i, j int) bool {
if s[i].Points > s[j].Points {
return true
}
if s[i].Points < s[j].Points {
return false
}
if s[i].Wins > s[j].Wins {
return true
}
if s[i].Wins < s[j].Wins {
return false
}
if s[i].GoalDifference > s[j].GoalDifference {
return true
}
if s[i].GoalDifference < s[j].GoalDifference {
return false
}
if s[i].GoalsFor > s[j].GoalsFor {
return true
}
if s[i].GoalsFor < s[j].GoalsFor {
return false
}
return false
}
func getStandings() []*Standing {
scorePage, err := goquery.NewDocument("http://www.mlssoccer.com/standings")
if err != nil {
panic(err)
}
standings := make([]*Standing, 0, 20)
scorePage.Find(".eastern + .stats-table .standings-table tbody tr").Each(func(i int, s *goquery.Selection) {
standing := extractStanding(s.Children())
standing.Conference = "E"
standings = append(standings, &standing)
})
scorePage.Find(".western + .stats-table .standings-table tbody tr").Each(func(i int, s *goquery.Selection) {
standing := extractStanding(s.Children())
standing.Conference = "W"
standings = append(standings, &standing)
})
sort.Sort(Standings(standings))
return standings
}
func extractStanding(record *goquery.Selection) (standing Standing) {
standing.Position, _ = strconv.ParseInt(strings.TrimSpace(record.Eq(0).Contents().Text()), 10, 64)
standing.Team = strings.TrimSpace(record.Eq(1).Contents().Text())
standing.Points, _ = strconv.ParseInt(strings.TrimSpace(record.Eq(2).Contents().Text()), 10, 64)
standing.GamesPlayed, _ = strconv.ParseInt(strings.TrimSpace(record.Eq(3).Contents().Text()), 10, 64)
standing.GoalsFor, _ = strconv.ParseInt(strings.TrimSpace(record.Eq(8).Contents().Text()), 10, 64)
standing.GoalDifference, _ = strconv.ParseInt(strings.TrimSpace(record.Eq(10).Contents().Text()), 10, 64)
standing.Wins, _ = strconv.ParseInt(strings.TrimSpace(record.Eq(5).Contents().Text()), 10, 64)
return
}
type ScheduleEntry struct {
Time string
Home, Away string
Score, AggScore string
Channels string
}
func getSchedule() (schedule map[string][]ScheduleEntry, err error) {
var easternTime *time.Location
easternTime, err = time.LoadLocation("America/New_York")
if err != nil {
return
}
monday := getMostRecentMonday()
rawSchedule, err := goquery.NewDocument(fmt.Sprintf("http://matchcenter.mlssoccer.com/matches/%s", monday.Format("2006-01-02")))
if err != nil {
return
}
schedule = make(map[string][]ScheduleEntry)
rawSchedule.Find(".sb-wrapper").Each(func(i int, s *goquery.Selection) {
comp := s.Find(".sb-match-comp").Contents().Text()
if comp != "MLS" {
return
}
var entry ScheduleEntry
entry.Home = s.Find(".sb-home .sb-club-name .sb-club-name-full").Contents().Text()
entry.Away = s.Find(".sb-away .sb-club-name .sb-club-name-full").Contents().Text()
d := s.Find(".sb-match-date").Contents().Text()
t := s.Find(".sb-match-time").Contents().Text()
dateTime, err := time.ParseInLocation("Mon, Jan 2 3:04 PM", d+" "+strings.Replace(t, " ET", "", 1), easternTime)
if err != nil {
fmt.Fprintf(os.Stderr, "Error parsing time: %s\n", err)
}
date := dateTime.Format("1/2")
entry.Time = dateTime.Format("3:04")
entry.Score = s.Find(".sb-score").Eq(0).Contents().Text()
entry.AggScore = s.Find(".sb-score").Eq(1).Contents().Text()
entry.Channels = s.Find(".sb-tv-listing span").Contents().Text()
if _, ok := schedule[date]; ok {
schedule[date] = append(schedule[date], entry)
} else {
schedule[date] = make([]ScheduleEntry, 0, 5)
schedule[date] = append(schedule[date], entry)
}
})
return
}
func getMostRecentMonday() time.Time {
day := time.Now()
for day.Weekday() != time.Monday {
day = day.Add(-24 * time.Hour)
}
return day
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment