Initial commit
This commit is contained in:
commit
737a428f52
9 changed files with 383 additions and 0 deletions
3
.envrc
Normal file
3
.envrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
source_url "https://raw.githubusercontent.com/cachix/devenv/95f329d49a8a5289d31e0982652f7058a189bfca/direnvrc" "sha256-d+8cBpDfDBj41inrADaJt+bDWhOktwslgoP5YiGJ1v0="
|
||||
|
||||
use devenv
|
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Devenv
|
||||
.devenv*
|
||||
devenv.local.nix
|
||||
|
||||
# direnv
|
||||
.direnv
|
||||
|
||||
# pre-commit
|
||||
.pre-commit-config.yaml
|
156
devenv.lock
Normal file
156
devenv.lock
Normal file
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"nodes": {
|
||||
"devenv": {
|
||||
"locked": {
|
||||
"dir": "src/modules",
|
||||
"lastModified": 1715593316,
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "725c90407ef53cc2a1b53701c6d2d0745cf2484f",
|
||||
"treeHash": "7ac06cbb236d43b776abbb0a7b8c48c9175d6012",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "src/modules",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"treeHash": "bd263f021e345cb4a39d80c126ab650bebc3c10c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1713361204,
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6",
|
||||
"treeHash": "50354b35a3e0277d4a83a0a88fa0b0866b5f392f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1715542476,
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "44072e24566c5bcc0b7aa9178a0104f4cfffab19",
|
||||
"treeHash": "3f9021e4c33de6fe59b88ac8c3019fc49136dc2a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715609711,
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "c182c876690380f8d3b9557c4609472ebfa1b141",
|
||||
"treeHash": "8ca3c0abe85c95ba7e8eef91a8c6a34f6dde5299",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"treeHash": "cce81f2a0f0743b2eb61bc2eb6c7adbe2f2c6beb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
7
devenv.nix
Normal file
7
devenv.nix
Normal file
|
@ -0,0 +1,7 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
packages = with pkgs; [ git go gopls delve ];
|
||||
|
||||
scripts.start.exec = "go run main.go";
|
||||
}
|
15
devenv.yaml
Normal file
15
devenv.yaml
Normal file
|
@ -0,0 +1,15 @@
|
|||
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
|
||||
inputs:
|
||||
nixpkgs:
|
||||
url: github:cachix/devenv-nixpkgs/rolling
|
||||
|
||||
# If you're using non-OSS software, you can set allowUnfree to true.
|
||||
# allowUnfree: true
|
||||
|
||||
# If you're willing to use a package that's vulnerable
|
||||
# permittedInsecurePackages:
|
||||
# - "openssl-1.1.1w"
|
||||
|
||||
# If you have more than one devenv you can merge them
|
||||
#imports:
|
||||
# - ./backend
|
3
go.mod
Normal file
3
go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module stormlight-tracker
|
||||
|
||||
go 1.22.2
|
51
index.go
Normal file
51
index.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type IndexPage struct {
|
||||
BookTitle string
|
||||
Timestamp string
|
||||
}
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
page := template.Must(template.New("index").Parse(indexPage))
|
||||
|
||||
deadline := time.Date(2024, 12, 1, 0, 0, 0, 0, time.UTC)
|
||||
timeRemaining := deadline.Sub(time.Now().Round(24 * time.Hour))
|
||||
|
||||
book, timestamp := getBookWithTimestamp(timeRemaining)
|
||||
|
||||
data := IndexPage{
|
||||
BookTitle: book,
|
||||
Timestamp: timestamp.String(),
|
||||
}
|
||||
|
||||
page.Execute(w, data)
|
||||
}
|
||||
|
||||
const indexPage string = `<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, height=device-height, user-scalable=no, initial-scale=1.0"/>
|
||||
<title>Stormlight Archive Tracker</title>
|
||||
<meta name="description" content="UwU"/>
|
||||
<link rel="canonical" href="https://stormlight.scalio.me"/>
|
||||
<style>
|
||||
body {margin: 5% auto; background: #f2f2f2; color: #444444; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.8; text-shadow: 0 1px 0 #ffffff; max-width: 73%;}
|
||||
code {background: white;}
|
||||
a {border-bottom: 1px solid #444444; color: #444444; text-decoration: none;}
|
||||
a:hover {border-bottom: 0;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Stormlight Archive Tracker</h1>
|
||||
<p>
|
||||
You should be reading <strong>{{.BookTitle}}</strong> and past the <strong>{{.Timestamp}}</strong> mark by the end of the day.
|
||||
</p>
|
||||
</body>
|
||||
</html>`
|
15
main.go
Normal file
15
main.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := http.NewServeMux()
|
||||
|
||||
router.HandleFunc("GET /", index)
|
||||
|
||||
slog.Info("Listening on port 8080")
|
||||
http.ListenAndServe(":8080", router)
|
||||
}
|
124
stormlight.go
Normal file
124
stormlight.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Book struct {
|
||||
Name string
|
||||
Length time.Duration
|
||||
}
|
||||
|
||||
var stormlight []Book = []Book{
|
||||
{
|
||||
Name: "The Way of Kings Part 1",
|
||||
Length: 26966 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "The Way of Kings Part 2",
|
||||
Length: 25887 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "The Way of Kings Part 3",
|
||||
Length: 27645 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "The Way of Kings Part 4",
|
||||
Length: 26077 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "The Way of Kings Part 5",
|
||||
Length: 27181 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Words of Radiance Part 1",
|
||||
Length: 27556 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Words of Radiance Part 2",
|
||||
Length: 27416 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Words of Radiance Part 3",
|
||||
Length: 26568 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Words of Radiance Part 4",
|
||||
Length: 26130 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Words of Radiance Part 5",
|
||||
Length: 27726 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Oathbringer Part 1",
|
||||
Length: 24407 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Oathbringer Part 2",
|
||||
Length: 24467 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Oathbringer Part 3",
|
||||
Length: 24482 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Oathbringer Part 4",
|
||||
Length: 22930 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Oathbringer Part 5",
|
||||
Length: 24122 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Oathbringer Part 6",
|
||||
Length: 25034 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Rhythm of War Part 1",
|
||||
Length: 25655 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Rhythm of War Part 2",
|
||||
Length: 24470 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Rhythm of War Part 3",
|
||||
Length: 23996 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Rhythm of War Part 4",
|
||||
Length: 27610 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Rhythm of War Part 5",
|
||||
Length: 28758 * time.Second,
|
||||
},
|
||||
{
|
||||
Name: "Rhythm of War Part 6",
|
||||
Length: 29142 * time.Second,
|
||||
},
|
||||
}
|
||||
|
||||
func getBookWithTimestamp(timeRemaining time.Duration) (string, time.Duration) {
|
||||
timeRemaining = time.Duration(timeRemaining.Hours()/24) * time.Hour
|
||||
slices.Reverse(stormlight)
|
||||
|
||||
for _, book := range stormlight {
|
||||
slog.Info("Checking...", "name", book.Name, "length", book.Length, "timeRemaining", timeRemaining)
|
||||
|
||||
if timeRemaining < book.Length {
|
||||
return book.Name, book.Length - timeRemaining
|
||||
}
|
||||
|
||||
timeRemaining = timeRemaining - book.Length
|
||||
}
|
||||
|
||||
if timeRemaining > 0 {
|
||||
return "The Way of Kings Part 1", 0
|
||||
}
|
||||
|
||||
return "YOU SHOULD BE DONE", 0
|
||||
}
|
Loading…
Reference in a new issue