232 lines
4.4 KiB
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")
|
|
}
|