2025-05-02 13:13:33 -05:00

200 lines
5.1 KiB
Go

package main
import (
"context"
"fmt"
"log"
"os"
"strconv"
"strings"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/joho/godotenv"
"github.com/kr/pretty"
"github.com/xuri/excelize/v2"
"googlemaps.github.io/maps"
)
type Row struct {
PlaceID string `xlsx:"column(PlaceID)"`
Name string `xlsx:"column(Name)"`
Types []string `xlsx:"column(Types)"`
Address string `xlsx:"column(Address)"`
Website string `xlsx:"column(Website)"`
PhoneNumber string `xlsx:"column(PhoneNumber)"`
GoogleMapsUrl string `xlsx:"column(GoogleMapsUrl)"`
}
func main() {
fmt.Println("Reading ENV...")
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
}
fmt.Println("Creating maps api client...")
c, err := maps.NewClient(maps.WithAPIKey(os.Getenv("API_KEY")))
if err != nil {
log.Fatalf("error creating maps client: %s", err)
}
t := table.NewWriter()
t.AppendHeader(table.Row{"Name", "Address", "PhoneNumber"})
var rows []Row
fmt.Println("Searching places...")
foundPlaces := searchNearby(c)
for _, place := range foundPlaces {
details := searchDetails(c, place)
r := makeRow(place, details)
t.AppendRow(table.Row{r.Name, r.Address, r.PhoneNumber})
rows = append(rows, r)
}
fmt.Println(t.Render())
pretty.Println(len(rows))
createExcelSheet(rows)
}
func searchNearby(mapsClient *maps.Client) []maps.PlacesSearchResult {
mileInMeters, _ := strconv.ParseUint(os.Getenv("RADIUS_IN_METERS"), 10, strconv.IntSize)
Lat, _ := strconv.ParseFloat(os.Getenv("LAT"), 64)
Lng, _ := strconv.ParseFloat(os.Getenv("LNG"), 64)
latLon := maps.LatLng{
Lat: Lat,
Lng: Lng,
}
var foundPlaces []maps.PlacesSearchResult
var nextPageToken string = ""
MAX_RESULTS, _ := strconv.Atoi(os.Getenv("MAX_RESULTS"))
for next := true; next; next = (len(foundPlaces) <= MAX_RESULTS) && nextPageToken != "" {
mapRequest := maps.NearbySearchRequest{
Location: &latLon,
Radius: uint(mileInMeters),
PageToken: nextPageToken,
}
searchResponse, err := mapsClient.NearbySearch(context.Background(), &mapRequest)
if err != nil {
log.Fatalf("error searching places: %s", err)
}
nextPageToken = searchResponse.NextPageToken
for _, place := range searchResponse.Results {
if !shouldOmitPlace(place) {
foundPlaces = append(foundPlaces, place)
}
}
}
return foundPlaces
}
func findString(slice []string, condition func(string) bool) *string {
for _, element := range slice {
if condition(element) {
return &element
}
}
return nil
}
func shouldOmitPlace(place maps.PlacesSearchResult) bool {
omitTypes := []string{"bar", "food", "restaurant", "store"}
requiredTypes := []string{"establishment"}
var hasOmitType bool = false
var hasRequredType bool = false
for _, placeType := range place.Types {
foundInOmit := findString(omitTypes, func(omitType string) bool {
return omitType == placeType
})
if foundInOmit != nil {
hasOmitType = true
break
}
foundInRequired := findString(requiredTypes, func(requiredType string) bool {
return requiredType == placeType
})
if foundInRequired != nil {
hasRequredType = true
}
}
return hasOmitType || !hasRequredType
}
func makeRow(place maps.PlacesSearchResult, details maps.PlaceDetailsResult) Row {
return Row{
PlaceID: place.PlaceID,
Name: place.Name,
Types: place.Types,
Address: details.FormattedAddress,
PhoneNumber: details.FormattedPhoneNumber,
Website: details.Website,
GoogleMapsUrl: details.URL,
}
}
func searchDetails(mapsClient *maps.Client, place maps.PlacesSearchResult) maps.PlaceDetailsResult {
desiredDetails := []maps.PlaceDetailsFieldMask{
"formatted_address",
"formatted_phone_number",
"website",
"url",
}
detailsRequest := maps.PlaceDetailsRequest{
PlaceID: place.PlaceID,
Fields: desiredDetails,
}
detailsResponse, err := mapsClient.PlaceDetails(context.Background(), &detailsRequest)
if err != nil {
log.Fatalf("error getting details for %s: %s", place.Name, err)
}
return detailsResponse
}
func createExcelSheet(rows []Row) {
fmt.Println("Writing XLSX...")
f := excelize.NewFile()
sheetName := os.Getenv("SHEET_NAME")
index, _ := f.NewSheet(sheetName)
f.SetActiveSheet(index)
excelHeaders := []string{"PlaceID", "Name", "Types", "Address", "Website", "PhoneNumber", "GoogleMapsUrl"}
for col, header := range excelHeaders {
cell := string(rune('A'+col)) + "1"
f.SetCellValue(sheetName, cell, header)
}
for i, row := range rows {
baseRow := i + 2
f.SetCellValue(sheetName, "A"+strconv.Itoa(baseRow), row.PlaceID)
f.SetCellValue(sheetName, "B"+strconv.Itoa(baseRow), row.Name)
f.SetCellValue(sheetName, "C"+strconv.Itoa(baseRow), strings.Join(row.Types, ","))
f.SetCellValue(sheetName, "D"+strconv.Itoa(baseRow), row.Address)
f.SetCellValue(sheetName, "E"+strconv.Itoa(baseRow), row.Website)
f.SetCellValue(sheetName, "F"+strconv.Itoa(baseRow), row.PhoneNumber)
f.SetCellValue(sheetName, "G"+strconv.Itoa(baseRow), row.GoogleMapsUrl)
}
if err := f.SaveAs(sheetName + ".xlsx"); err != nil {
fmt.Println(err)
} else {
fmt.Println("Finished")
}
}