Create scraping library to get match data
To use it, you need to make a JSON config file which gets stored
at the workspace root or you pass the path into the function(s)
Change-Id: I9d074c7ad84c45b418eb5be8b316a84b022db835
Signed-off-by: Het Satasiya <satasiyahet@gmail.com>
diff --git a/scouting/scraping/BUILD b/scouting/scraping/BUILD
new file mode 100644
index 0000000..58db2b1
--- /dev/null
+++ b/scouting/scraping/BUILD
@@ -0,0 +1,12 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "scraping",
+ srcs = [
+ "scrape.go",
+ "types.go",
+ ],
+ importpath = "github.com/frc971/971-Robot-Code/scouting/scraping",
+ target_compatible_with = ["@platforms//cpu:x86_64"],
+ visibility = ["//visibility:public"],
+)
diff --git a/scouting/scraping/scrape.go b/scouting/scraping/scrape.go
new file mode 100644
index 0000000..fa20f7b
--- /dev/null
+++ b/scouting/scraping/scrape.go
@@ -0,0 +1,86 @@
+package scraping
+
+// A library to grab match data from The Blue Alliance.
+import (
+ "encoding/json"
+ "errors"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+)
+
+// Stores the TBA API key to access the API.
+type params struct {
+ ApiKey string `json:"api_key"`
+}
+
+// Takes in year and FIRST event code and returns all matches in that event according to TBA.
+// Also takes in a file path to the JSON config file that contains your TBA API key.
+// It defaults to <workspace root>/config.json
+// the config is expected to have the following contents:
+//{
+// api_key:"myTBAapiKey"
+//}
+func AllMatches(year, eventCode, filePath string) ([]Match, error) {
+ if filePath == "" {
+ filePath = os.Getenv("BUILD_WORKSPACE_DIRECTORY") + "/scouting_config.json"
+ }
+ // Takes the filepath and grabs the api key from the json.
+ content, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ log.Fatal(err)
+ }
+ // Parses the JSON parameters into a struct.
+ var passed_params params
+ error := json.Unmarshal([]byte(content), &passed_params)
+ if error != nil {
+ log.Fatalf("You forgot to add the api_key parameter in the json file")
+ log.Fatalf("%s", err)
+ }
+
+ // Create the TBA event key for the year and event code.
+ eventKey := year + eventCode
+
+ // Create the client for HTTP requests.
+ client := &http.Client{}
+
+ // Create a get request for the match info.
+ req, err := http.NewRequest("GET", "https://www.thebluealliance.com/api/v3/event/"+eventKey+"/matches", nil)
+
+ if err != nil {
+ return nil, errors.New("failed to build http request")
+ }
+
+ // Add the auth key header to the request.
+ req.Header.Add("X-TBA-Auth-Key", passed_params.ApiKey)
+
+ // Make the API request
+ resp, err := client.Do(req)
+
+ if err != nil {
+ return nil, err
+ }
+
+ if resp.Status != "200 OK" {
+ return nil, errors.New("Recieved a status of " + resp.Status + " expected : 200 OK")
+ }
+
+ // Wait until the response is done.
+ defer resp.Body.Close()
+
+ // Get all bytes from response body.
+ bodyBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, errors.New("failed to read response body with error :" + err.Error())
+ }
+
+ var matches []Match
+ // Unmarshal json into go usable format.
+ jsonError := json.Unmarshal([]byte(bodyBytes), &matches)
+ if jsonError != nil {
+ return nil, errors.New("failed to unmarshal json recieved from TBA")
+ }
+
+ return matches, nil
+}
diff --git a/scouting/scraping/types.go b/scouting/scraping/types.go
new file mode 100644
index 0000000..aa0d4be
--- /dev/null
+++ b/scouting/scraping/types.go
@@ -0,0 +1,82 @@
+package scraping
+
+// Match holds the TBA data for a given match
+type Match struct {
+ Key string
+ CompLevel string `json:"comp_level"`
+ SetNumber int `json:"set_number"`
+ MatchNumber int `json:"match_number"`
+ Alliances Alliances `json:"alliances"`
+ WinningAlliance string `json:"winning_alliance"`
+ EventKey string `json:"event_key"`
+ Time int `json:"time"`
+ PredictedTime int `json:"predicted_time"`
+ ActualTime int `json:"actual_time"`
+ PostResultTime int `json:"post_result_time"`
+ ScoreBreakdowns ScoreBreakdowns `json:"score_breakdowns"`
+}
+
+// Holds score breakdowns for each alliance
+type ScoreBreakdowns struct {
+ Blue ScoreBreakdownAlliance `json:"blue"`
+ Red ScoreBreakdownAlliance `json:"red"`
+}
+
+// Stores the actual data for the breakdown
+type ScoreBreakdownAlliance struct {
+ TaxiRobot1 string `json:"taxiRobot1"`
+ EndgameRobot1 string `json:"endgameRobot1"`
+ TaxiRobot2 string `json:"taxiRobot2"`
+ EndgameRobot2 string `json:"endgameRobot2"`
+ TaxiRobot3 string `json:"taxiRobot3"`
+ EndgameRobot3 string `json:"endgameRobot3"`
+
+ AutoCargoLowerNear int `json:"autoCargoLowerNear"`
+ AutoCargoLowerFar int `json:"autoCargoLowerFar"`
+ AutoCargoLowerBlue int `json:"autoCargoLowerBlue"`
+ AutoCargoLowerRed int `json:"autoCargoLowerRed"`
+ AutoCargoUpperNear int `json:"autoCargoUpperNear"`
+ AutoCargoUpperFar int `json:"autoCargoUpperFar"`
+ AutoCargoUpperBlue int `json:"autoCargoUpperBlue"`
+ AutoCargoUpperRed int `json:"autoCargoUpperRed"`
+ AutoCargoTotal int `json:"autoCargoTotal"`
+ TeleOpCargoLowerNear int `json:"teleopCargoLowerNear"`
+ TeleOpCargoLowerFar int `json:"teleopCargoLowerFar"`
+ TeleOpCargoLowerBlue int `json:"teleopCargoLowerBlue"`
+ TeleOpCargoLowerRed int `json:"teleopCargoLowerRed"`
+ TeleOpCargoUpperNear int `json:"teleopCargoUpperNear"`
+ TeleOpCargoUpperFar int `json:"teleopCargoUpperFar"`
+ TeleOpCargoUpperBlue int `json:"teleopCargoUpperBlue"`
+ TeleOpCargoUpperRed int `json:"teleopCargoUpperRed"`
+ TeleopCargoTotal int `json:"teleopCargoTotal"`
+ MatchCargoTotal int `json:"matchCargoTotal"`
+ AutoTaxiPoints int `json:"autoTaxiPoints"`
+ AutoCargoPoints int `json:"autoCargoPoints"`
+ AutoPoints int `json:"autoPoints"`
+ QuintetAchieved bool `json:"quintetAchieved"`
+ TeleOpCargoPoints int `json:"teleopCargoPoints"`
+ EndgamePoints int `json:"endgamePoints"`
+ TeleOpPoints int `json:"teleopPoints"`
+ CargoBonusRankingPoint bool `json:"cargoBonusRankingPoint"`
+ HangerBonusRankingPoint bool `json:"hangarBonusRankingPoint"`
+ FoulCount bool `json:"foulCount"`
+ TechFoulCount int `json:"techFoulCount"`
+ AdjustPoints int `json:"adjustPoints"`
+ FoulPoints int `json:"foulPoints"`
+ RankingPoints int `json:"rp"`
+ TotalPoints int `json:"totalPoints"`
+}
+
+// Alliances holds the two alliances for a match
+type Alliances struct {
+ Red Alliance `json:"red"`
+ Blue Alliance `json:"blue"`
+}
+
+// Alliance holds the info for the alliance
+type Alliance struct {
+ Score int `json:"score"`
+ TeamKeys []string `json:"team_keys"`
+ SurrogateTeamKeys []string `json:"surrogate_team_keys"`
+ DqTeamKeys []string `json:"dq_team_keys"`
+}