newtab/main.go

232 lines
4.4 KiB
Go

package main
import (
"encoding/json"
"fmt"
"html/template"
"io"
"log"
"net/http"
"os"
"strconv"
"time"
"git.gay/h/newtab/dunstctl"
"git.gay/h/newtab/playerctl"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/etag"
"github.com/gofiber/template/html"
"github.com/joho/godotenv"
)
type Timezone struct {
Name string `json:"name"`
Location string `json:"location"`
}
type HeatmapValue int
type Heatmap struct {
Start time.Time `json:"start"`
End time.Time `json:"end"`
Days [371]HeatmapValue `json:"days"`
}
func (heatmap *Heatmap) UpdateIfStale() (err error) {
now := time.Now()
yy, mm, dd := now.Date()
correctEnd := time.Date(yy, mm, dd, 0, 0, 0, 0, now.Location())
if !correctEnd.Equal(heatmap.End) {
err = heatmap.Update()
return
}
return
}
func (heatmap *Heatmap) Update() (err error) {
fmt.Println("updating heatmap")
resp, err := http.Get(fmt.Sprintf("https://%s/api/v1/users/%s/heatmap", GITEA_HOST, GITEA_USER))
if err != nil {
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
type Contribution struct {
Timestamp int64 `json:"timestamp"`
Contributions int64 `json:"contributions"`
}
var contributions []Contribution
json.Unmarshal(body, &contributions)
heatmap.Days = [371]HeatmapValue{}
now := time.Now()
yy, mm, dd := now.Date()
heatmap.End = time.Date(yy, mm, dd, 0, 0, 0, 0, now.Location())
heatmap.Start = heatmap.End.AddDate(0, 0, -371)
for _, v := range contributions {
contribTime := time.Unix(v.Timestamp, 0)
duration := contribTime.Sub(heatmap.Start)
day := int(duration.Hours()/24) - 1
if day < 0 {
continue
}
if day >= len(heatmap.Days) {
// this shouldn't really happen, it hasn't in testing,
// but why not check for it I guess?
continue
}
heatmap.Days[day] += HeatmapValue(v.Contributions)
}
return
}
var GITEA_HOST string
var GITEA_USER string
var TIMEZONES []Timezone
var heatmap *Heatmap
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
GITEA_HOST = os.Getenv("GITEA_HOST")
GITEA_USER = os.Getenv("GITEA_USER")
json.Unmarshal([]byte(os.Getenv("TIMEZONES")), &TIMEZONES)
}
func main() {
heatmap = &Heatmap{}
err := heatmap.UpdateIfStale()
if err != nil {
fmt.Println("Couldn't get heatmap.")
fmt.Println(err)
}
engine := html.New("./views", ".tmpl")
engine.AddFunc("htmlSafe", func(html string) template.HTML {
return template.HTML(html)
},
)
app := fiber.New(fiber.Config{
Views: engine,
})
app.Use(etag.New())
app.Get("/", func(c *fiber.Ctx) (err error) {
type Time struct {
Name string
Time string
}
err = heatmap.UpdateIfStale()
if err != nil {
fmt.Println(err)
return
}
var times []Time
for _, v := range TIMEZONES {
tz, err := time.LoadLocation(v.Location)
if err != nil {
return err
}
now := time.Now().In(tz)
times = append(times, Time{
Name: v.Name,
Time: now.Format(time.TimeOnly),
})
}
state, err := playerctl.GetPlayState()
if err != nil {
state = nil
}
notifications, err := dunstctl.GetHistory()
if err != nil {
return
}
return c.Render("home", fiber.Map{
"Heatmap": heatmap,
"Times": times,
"Playing": state,
"Notifications": notifications,
})
})
app.Get("/heatmap", func(c *fiber.Ctx) (err error) {
err = heatmap.UpdateIfStale()
if err != nil {
fmt.Println(err)
return
}
return c.JSON(heatmap)
})
app.Get("/playstate", func(c *fiber.Ctx) (err error) {
state, err := playerctl.GetPlayState()
if err != nil {
return
}
return c.JSON(state)
})
app.Get("/players", func(c *fiber.Ctx) (err error) {
players, err := playerctl.ListPlayers()
if err != nil {
return
}
return c.JSON(players)
})
app.Get("/notifications", func(c *fiber.Ctx) (err error) {
notifications, err := dunstctl.GetHistory()
if err != nil {
return
}
return c.JSON(notifications)
})
app.Delete("/notifications/:id", func(c *fiber.Ctx) (err error) {
id, err := strconv.Atoi(c.Params("id"))
if err != nil {
return
}
err = dunstctl.CloseNotification(int64(id))
if err != nil {
return
}
return c.SendStatus(200)
})
app.Use("/", func(c *fiber.Ctx) error {
c.Request().Header.Add("Cache-Control", "public, max-age=2592000")
return c.Next()
})
app.Static("/", "./static")
app.Listen("127.0.0.1:7564")
}