+3
-2
cmd/handlers.go
+3
-2
cmd/handlers.go
···
9
9
10
10
"github.com/teal-fm/piper/db"
11
11
"github.com/teal-fm/piper/models"
12
+
pages "github.com/teal-fm/piper/pages"
12
13
"github.com/teal-fm/piper/service/musicbrainz"
13
14
"github.com/teal-fm/piper/service/spotify"
14
15
"github.com/teal-fm/piper/session"
15
16
)
16
17
17
-
func home(database *db.DB, pages *Pages) http.HandlerFunc {
18
+
func home(database *db.DB, pages *pages.Pages) http.HandlerFunc {
18
19
return func(w http.ResponseWriter, r *http.Request) {
19
20
20
21
w.Header().Set("Content-Type", "text/html")
···
138
139
</body>
139
140
</html>
140
141
`
141
-
pages.execute("home", w, nil)
142
+
pages.Execute("home", w, nil)
142
143
143
144
//w.Write([]byte(html))
144
145
}
+3
-2
cmd/main.go
+3
-2
cmd/main.go
···
16
16
"github.com/teal-fm/piper/db"
17
17
"github.com/teal-fm/piper/oauth"
18
18
"github.com/teal-fm/piper/oauth/atproto"
19
+
pages "github.com/teal-fm/piper/pages"
19
20
apikeyService "github.com/teal-fm/piper/service/apikey"
20
21
"github.com/teal-fm/piper/service/musicbrainz"
21
22
"github.com/teal-fm/piper/service/spotify"
···
31
32
mbService *musicbrainz.MusicBrainzService
32
33
atprotoService *atproto.ATprotoAuthService
33
34
playingNowService *playingnow.PlayingNowService
34
-
pages *Pages
35
+
pages *pages.Pages
35
36
}
36
37
37
38
// JSON API handlers
···
106
107
spotifyService: spotifyService,
107
108
atprotoService: atprotoService,
108
109
playingNowService: playingNowService,
109
-
pages: NewPages(true),
110
+
pages: pages.NewPages(false),
110
111
}
111
112
112
113
trackerInterval := time.Duration(viper.GetInt("tracker.interval")) * time.Second
+10
-41
cmd/pages.go
pages/pages.go
+10
-41
cmd/pages.go
pages/pages.go
···
1
-
package main
1
+
package pages
2
2
3
3
import (
4
4
"embed"
···
7
7
"io/fs"
8
8
"os"
9
9
"strings"
10
-
"sync"
11
10
"time"
12
11
)
13
12
···
33
32
if pages.dev {
34
33
pages.embedFS = os.DirFS(pages.templateDir)
35
34
} else {
36
-
//pages.embedFS = Files
35
+
pages.embedFS = Files
37
36
}
38
37
39
38
return pages
···
41
40
42
41
func (p *Pages) fragmentPaths() ([]string, error) {
43
42
var fragmentPaths []string
43
+
// When using os.DirFS("templates"), the FS root is already the templates directory.
44
+
// Walk from "." and use relative paths (no "templates/" prefix).
44
45
err := fs.WalkDir(p.embedFS, "templates", func(path string, d fs.DirEntry, err error) error {
45
46
if err != nil {
46
47
return err
···
51
52
if !strings.HasSuffix(path, ".gohtml") {
52
53
return nil
53
54
}
54
-
if !strings.Contains(path, "fragments/") {
55
-
return nil
56
-
}
55
+
//if !strings.Contains(path, "fragments/") {
56
+
// return nil
57
+
//}
57
58
fragmentPaths = append(fragmentPaths, path)
58
59
return nil
59
60
})
···
65
66
}
66
67
67
68
func (p *Pages) pathToName(s string) string {
68
-
return strings.TrimSuffix(strings.TrimPrefix(s, "templates/"), ".html")
69
+
return strings.TrimSuffix(strings.TrimPrefix(s, "templates/"), ".gohtml")
69
70
}
70
71
71
72
// reverse of pathToName
72
73
func (p *Pages) nameToPath(s string) string {
73
-
return "templates/" + s + ".html"
74
+
return "templates/" + s + ".gohtml"
74
75
}
75
76
76
77
// parse without memoization
···
140
141
return tpl.Execute(w, params)
141
142
}
142
143
143
-
func (p *Pages) execute(name string, w io.Writer, params any) error {
144
+
func (p *Pages) Execute(name string, w io.Writer, params any) error {
144
145
tpl, err := p.parseBase(name)
145
146
if err != nil {
146
147
return err
···
148
149
149
150
return tpl.ExecuteTemplate(w, "layouts/base", params)
150
151
}
151
-
152
-
/// Cache for pages
153
-
154
-
type TmplCache[K comparable, V any] struct {
155
-
data map[K]V
156
-
mutex sync.RWMutex
157
-
}
158
-
159
-
func NewTmplCache[K comparable, V any]() *TmplCache[K, V] {
160
-
return &TmplCache[K, V]{
161
-
data: make(map[K]V),
162
-
}
163
-
}
164
-
165
-
func (c *TmplCache[K, V]) Get(key K) (V, bool) {
166
-
c.mutex.RLock()
167
-
defer c.mutex.RUnlock()
168
-
val, exists := c.data[key]
169
-
return val, exists
170
-
}
171
-
172
-
func (c *TmplCache[K, V]) Set(key K, value V) {
173
-
c.mutex.Lock()
174
-
defer c.mutex.Unlock()
175
-
c.data[key] = value
176
-
}
177
-
178
-
func (c *TmplCache[K, V]) Size() int {
179
-
c.mutex.RLock()
180
-
defer c.mutex.RUnlock()
181
-
return len(c.data)
182
-
}
+35
pages/cache.go
+35
pages/cache.go
···
1
+
package pages
2
+
3
+
import "sync"
4
+
5
+
/// Cache for pages
6
+
7
+
type TmplCache[K comparable, V any] struct {
8
+
data map[K]V
9
+
mutex sync.RWMutex
10
+
}
11
+
12
+
func NewTmplCache[K comparable, V any]() *TmplCache[K, V] {
13
+
return &TmplCache[K, V]{
14
+
data: make(map[K]V),
15
+
}
16
+
}
17
+
18
+
func (c *TmplCache[K, V]) Get(key K) (V, bool) {
19
+
c.mutex.RLock()
20
+
defer c.mutex.RUnlock()
21
+
val, exists := c.data[key]
22
+
return val, exists
23
+
}
24
+
25
+
func (c *TmplCache[K, V]) Set(key K, value V) {
26
+
c.mutex.Lock()
27
+
defer c.mutex.Unlock()
28
+
c.data[key] = value
29
+
}
30
+
31
+
func (c *TmplCache[K, V]) Size() int {
32
+
c.mutex.RLock()
33
+
defer c.mutex.RUnlock()
34
+
return len(c.data)
35
+
}
templates/home.gohtml
pages/templates/home.gohtml
templates/home.gohtml
pages/templates/home.gohtml
templates/layouts/base.gohtml
pages/templates/layouts/base.gohtml
templates/layouts/base.gohtml
pages/templates/layouts/base.gohtml