mirror of
https://github.com/jackmerrill/hampbot.git
synced 2025-04-19 10:01:38 -04:00
280 lines
6.4 KiB
Go
280 lines
6.4 KiB
Go
package studentlife
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image/color"
|
|
"image/png"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/bwmarrin/discordgo"
|
|
sm "github.com/flopp/go-staticmaps"
|
|
"github.com/golang/geo/s2"
|
|
"github.com/jackmerrill/hampbot/internal/utils/config"
|
|
"github.com/jackmerrill/hampbot/internal/utils/embed"
|
|
pvtago "github.com/jackmerrill/pvta-go"
|
|
"github.com/zekroTJA/shireikan"
|
|
)
|
|
|
|
type PVTA struct {
|
|
}
|
|
|
|
func (c *PVTA) GetInvokes() []string {
|
|
return []string{"pvta", "bus"}
|
|
}
|
|
|
|
func (c *PVTA) GetDescription() string {
|
|
return "Get the details and location of a PVTA bus"
|
|
}
|
|
|
|
func (c *PVTA) GetHelp() string {
|
|
return "`pvta [route] <vehicle>` - Get the details and location of a PVTA bus"
|
|
}
|
|
|
|
func (c *PVTA) GetGroup() string {
|
|
return config.GroupStudentLife
|
|
}
|
|
|
|
func (c *PVTA) GetDomainName() string {
|
|
return "hamp.studentlife.pvta"
|
|
}
|
|
|
|
func (c *PVTA) GetSubPermissionRules() []shireikan.SubPermission {
|
|
return nil
|
|
}
|
|
|
|
func (c *PVTA) IsExecutableInDMChannels() bool {
|
|
return true
|
|
}
|
|
|
|
func getRouteByShortName(shortName string) (*pvtago.RouteDetail, error) {
|
|
client := pvtago.NewClient()
|
|
|
|
routes, err := client.GetRoutes()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, route := range routes {
|
|
if route.ShortName == shortName {
|
|
return &route, nil
|
|
}
|
|
|
|
if route.RouteAbbreviation == shortName {
|
|
return &route, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
func (c *PVTA) Exec(ctx shireikan.Context) error {
|
|
client := pvtago.NewClient()
|
|
|
|
route := ctx.GetArgs().Get(0).AsString()
|
|
|
|
if route == "" {
|
|
routes, err := client.GetVisibleRoutes()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var routeIds []string
|
|
|
|
for _, route := range routes {
|
|
if route.ShortName != "" {
|
|
routeIds = append(routeIds, route.ShortName)
|
|
}
|
|
}
|
|
|
|
ctx.ReplyEmbed(embed.NewSuccessEmbed(ctx).SetTitle("Available PVTA routes").SetDescription(strings.Join(routeIds, ", ")).MessageEmbed)
|
|
|
|
return nil
|
|
}
|
|
|
|
vehicle := ctx.GetArgs().Get(1).AsString()
|
|
|
|
if vehicle == "" {
|
|
route, err := getRouteByShortName(route)
|
|
|
|
if err != nil {
|
|
ctx.ReplyEmbed(embed.NewErrorEmbed(ctx).SetTitle("Error").SetDescription("An error occured while fetching the route.").AddField("Error", err.Error(), false).MessageEmbed)
|
|
return err
|
|
}
|
|
|
|
if route == nil {
|
|
ctx.ReplyEmbed(embed.NewErrorEmbed(ctx).SetTitle("Error").SetDescription("The route you specified does not exist.").MessageEmbed)
|
|
return nil
|
|
}
|
|
|
|
vehicles, err := client.GetVehiclesForRoute(route.RouteID)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(vehicles) == 0 {
|
|
ctx.ReplyEmbed(embed.NewErrorEmbed(ctx).SetTitle("Error").SetDescription("There are no vehicles on this route.").MessageEmbed)
|
|
return nil
|
|
}
|
|
|
|
e := embed.NewSuccessEmbed(ctx).SetTitle(":bus: PVTA Route Details").SetDescription(fmt.Sprintf("**Route:** %s\n**Name:** %s", route.ShortName, route.LongName))
|
|
|
|
tileProvider := &sm.TileProvider{
|
|
Name: "thunderforest-transit",
|
|
Attribution: "Maps (c) Thundeforest; Data (c) OSM and contributors, ODbL",
|
|
TileSize: 256,
|
|
URLPattern: "https://%[1]s.tile.thunderforest.com/transport/%[2]d/%[3]d/%[4]d.png?apikey=" + os.Getenv("TF_API_KEY"),
|
|
Shards: []string{"a", "b", "c"},
|
|
}
|
|
|
|
mapCtx := sm.NewContext()
|
|
mapCtx.SetSize(600, 400)
|
|
mapCtx.SetTileProvider(tileProvider)
|
|
|
|
for _, vehicle := range vehicles {
|
|
e.AddField(fmt.Sprintf("Vehicle #`%d`", vehicle.VehicleID), fmt.Sprintf(":round_pushpin: **Destination:** %s (%s)\n:globe_with_meridians: **Lat/Long:** `%f` `%f`", vehicle.Destination, vehicle.Direction, vehicle.Latitude, vehicle.Longitude), false)
|
|
|
|
rgb, err := config.Hex2RGB(config.Hex(route.Color))
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
marker := sm.NewMarker(
|
|
s2.LatLngFromDegrees(vehicle.Latitude, vehicle.Longitude),
|
|
color.RGBA{R: rgb.Red, G: rgb.Green, B: rgb.Blue, A: 255},
|
|
16.0,
|
|
)
|
|
|
|
marker.Label = fmt.Sprintf("%s (%s)", vehicle.Destination, vehicle.Direction)
|
|
marker.LabelColor = color.RGBA{R: 0, G: 0, B: 0, A: 255}
|
|
marker.LabelYOffset = 3
|
|
|
|
mapCtx.AddObject(marker)
|
|
}
|
|
|
|
img, err := mapCtx.Render()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// convert to base64
|
|
buf := new(bytes.Buffer)
|
|
|
|
err = png.Encode(buf, img)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
e.SetImage("attachment://map.png")
|
|
|
|
_, err = ctx.GetSession().ChannelMessageSendComplex(ctx.GetChannel().ID, &discordgo.MessageSend{
|
|
Embed: e.MessageEmbed,
|
|
Reference: ctx.GetMessage().Reference(),
|
|
Files: []*discordgo.File{
|
|
{
|
|
Name: "map.png",
|
|
ContentType: "image/png",
|
|
Reader: buf,
|
|
},
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
} else {
|
|
id, err := strconv.ParseInt(vehicle, 10, 64)
|
|
|
|
if err != nil {
|
|
ctx.ReplyEmbed(embed.NewErrorEmbed(ctx).SetTitle("Error").SetDescription("An error occured while parsing the vehicle ID.").AddField("Error", err.Error(), false).MessageEmbed)
|
|
return err
|
|
}
|
|
|
|
v, err := client.GetVehicle(id)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
route, err := client.GetRoute(v.RouteID)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
e := embed.NewSuccessEmbed(ctx).SetTitle(":bus: Vehicle Details").SetDescription(fmt.Sprintf(":round_pushpin: **Destination:** %s (%s)\n:globe_with_meridians: **Lat/Long:** `%f` `%f`", v.Destination, v.Direction, v.Latitude, v.Longitude))
|
|
|
|
tileProvider := &sm.TileProvider{
|
|
Name: "thunderforest-transit",
|
|
Attribution: "Maps (c) Thundeforest; Data (c) OSM and contributors, ODbL",
|
|
TileSize: 256,
|
|
URLPattern: "https://%[1]s.tile.thunderforest.com/transport/%[2]d/%[3]d/%[4]d.png?apikey=" + os.Getenv("TF_API_KEY"),
|
|
Shards: []string{"a", "b", "c"},
|
|
}
|
|
|
|
mapCtx := sm.NewContext()
|
|
mapCtx.SetSize(600, 400)
|
|
mapCtx.SetTileProvider(tileProvider)
|
|
|
|
rgb, err := config.Hex2RGB(config.Hex(route.Color))
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mapCtx.AddObject(
|
|
sm.NewMarker(
|
|
s2.LatLngFromDegrees(v.Latitude, v.Longitude),
|
|
color.RGBA{R: rgb.Red, G: rgb.Green, B: rgb.Blue, A: 255},
|
|
16.0,
|
|
),
|
|
)
|
|
|
|
img, err := mapCtx.Render()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// convert to base64
|
|
buf := new(bytes.Buffer)
|
|
|
|
err = png.Encode(buf, img)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
e.SetImage("attachment://map.png")
|
|
|
|
_, err = ctx.GetSession().ChannelMessageSendComplex(ctx.GetChannel().ID, &discordgo.MessageSend{
|
|
Embed: e.MessageEmbed,
|
|
Reference: ctx.GetMessage().Reference(),
|
|
Files: []*discordgo.File{
|
|
{
|
|
Name: "map.png",
|
|
ContentType: "image/png",
|
|
Reader: buf,
|
|
},
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
}
|