tangled
alpha
login
or
join now
tom.sherman.is
/
piper
0
fork
atom
A fork of https://github.com/teal-fm/piper
0
fork
atom
overview
issues
pulls
pipelines
home template
baileytownsend.dev
5 months ago
b65aa00a
9702c710
+79
-129
5 changed files
expand all
collapse all
unified
split
.air.toml
cmd
handlers.go
main.go
pages
pages.go
templates
home.gohtml
+1
-1
.air.toml
···
14
14
follow_symlink = false
15
15
full_bin = ""
16
16
include_dir = []
17
17
-
include_ext = ["go", "tpl", "tmpl", "html"]
17
17
+
include_ext = ["go", "tpl", "tmpl", "html", "gohtml"]
18
18
include_file = []
19
19
kill_delay = "0s"
20
20
log = "build-errors.log"
+11
-107
cmd/handlers.go
···
15
15
"github.com/teal-fm/piper/session"
16
16
)
17
17
18
18
+
type HomeParams struct {
19
19
+
IsLoggedIn bool
20
20
+
LastFMUsername *string
21
21
+
}
22
22
+
18
23
func home(database *db.DB, pages *pages.Pages) http.HandlerFunc {
19
24
return func(w http.ResponseWriter, r *http.Request) {
20
25
···
33
38
log.Printf("Error fetching user %d details for home page: %v", userID, err)
34
39
}
35
40
}
36
36
-
37
37
-
html := `
38
38
-
<html>
39
39
-
<head>
40
40
-
<title>Piper - Spotify & Last.fm Tracker</title>
41
41
-
<style>
42
42
-
body {
43
43
-
font-family: Arial, sans-serif;
44
44
-
max-width: 800px;
45
45
-
margin: 0 auto;
46
46
-
padding: 20px;
47
47
-
line-height: 1.6;
48
48
-
}
49
49
-
h1 {
50
50
-
color: #1DB954; /* Spotify green */
51
51
-
}
52
52
-
.nav {
53
53
-
display: flex;
54
54
-
flex-wrap: wrap; /* Allow wrapping on smaller screens */
55
55
-
margin-bottom: 20px;
56
56
-
}
57
57
-
.nav a {
58
58
-
margin-right: 15px;
59
59
-
margin-bottom: 5px; /* Add spacing below links */
60
60
-
text-decoration: none;
61
61
-
color: #1DB954;
62
62
-
font-weight: bold;
63
63
-
}
64
64
-
.card {
65
65
-
border: 1px solid #ddd;
66
66
-
border-radius: 8px;
67
67
-
padding: 20px;
68
68
-
margin-bottom: 20px;
69
69
-
}
70
70
-
.service-status {
71
71
-
font-style: italic;
72
72
-
color: #555;
73
73
-
}
74
74
-
</style>
75
75
-
</head>
76
76
-
<body>
77
77
-
<h1>Piper - Multi-User Spotify & Last.fm Tracker via ATProto</h1>
78
78
-
<div class="nav">
79
79
-
<a href="/">Home</a>`
80
80
-
81
81
-
if isLoggedIn {
82
82
-
html += `
83
83
-
<a href="/current-track">Spotify Current</a>
84
84
-
<a href="/history">Spotify History</a>
85
85
-
<a href="/link-lastfm">Link Last.fm</a>` // Link to Last.fm page
86
86
-
if lastfmUsername != "" {
87
87
-
html += ` <a href="/lastfm/recent">Last.fm Recent</a>` // Show only if linked
88
88
-
}
89
89
-
html += `
90
90
-
<a href="/api-keys">API Keys</a>
91
91
-
<a href="/login/spotify">Connect Spotify Account</a>
92
92
-
<a href="/logout">Logout</a>`
93
93
-
} else {
94
94
-
html += `
95
95
-
<a href="/login/atproto">Login with ATProto</a>`
41
41
+
params := HomeParams{
42
42
+
IsLoggedIn: isLoggedIn,
43
43
+
LastFMUsername: &lastfmUsername,
96
44
}
97
97
-
98
98
-
html += `
99
99
-
</div>
100
100
-
101
101
-
<div class="card">
102
102
-
<h2>Welcome to Piper</h2>
103
103
-
<p>Piper is a multi-user application that records what you're listening to on Spotify and Last.fm, saving your listening history.</p>`
104
104
-
105
105
-
if !isLoggedIn {
106
106
-
html += `
107
107
-
<p>Login with ATProto to get started!</p>
108
108
-
<form action="/login/atproto">
109
109
-
<label for="handle">handle:</label>
110
110
-
<input type="text" id="handle" name="handle" >
111
111
-
<input type="submit" value="submit">
112
112
-
</form>`
113
113
-
} else {
114
114
-
html += `
115
115
-
<p>You're logged in!</p>
116
116
-
<ul>
117
117
-
<li><a href="/login/spotify">Connect your Spotify account</a> to start tracking.</li>
118
118
-
<li><a href="/link-lastfm">Link your Last.fm account</a> to track scrobbles.</li>
119
119
-
</ul>
120
120
-
<p>Once connected, you can check out your:</p>
121
121
-
<ul>
122
122
-
<li><a href="/current-track">Spotify current track</a> or <a href="/history">listening history</a>.</li>`
123
123
-
if lastfmUsername != "" {
124
124
-
html += `<li><a href="/lastfm/recent">Last.fm recent tracks</a>.</li>`
125
125
-
}
126
126
-
html += `
127
127
-
</ul>
128
128
-
<p>You can also manage your <a href="/api-keys">API keys</a> for programmatic access.</p>`
129
129
-
if lastfmUsername != "" {
130
130
-
html += fmt.Sprintf("<p class='service-status'>Last.fm Username: %s</p>", lastfmUsername)
131
131
-
} else {
132
132
-
html += "<p class='service-status'>Last.fm account not linked.</p>"
133
133
-
}
134
134
-
45
45
+
err := pages.Execute("home", w, params)
46
46
+
if err != nil {
47
47
+
log.Printf("Error executing template: %v", err)
135
48
}
136
136
-
137
137
-
html += `
138
138
-
</div> <!-- Close card div -->
139
139
-
</body>
140
140
-
</html>
141
141
-
`
142
142
-
pages.Execute("home", w, nil)
143
143
-
144
144
-
//w.Write([]byte(html))
145
49
}
146
50
}
147
51
+1
-1
cmd/main.go
···
107
107
spotifyService: spotifyService,
108
108
atprotoService: atprotoService,
109
109
playingNowService: playingNowService,
110
110
-
pages: pages.NewPages(false),
110
110
+
pages: pages.NewPages(),
111
111
}
112
112
113
113
trackerInterval := time.Duration(viper.GetInt("tracker.interval")) * time.Second
+8
-19
pages/pages.go
···
1
1
package pages
2
2
3
3
+
// inspired from tangled's implementation
4
4
+
//https://tangled.org/@tangled.org/core/blob/master/appview/pages/pages.go
5
5
+
3
6
import (
4
7
"embed"
5
8
"html/template"
6
9
"io"
7
10
"io/fs"
8
8
-
"os"
9
11
"strings"
10
12
"time"
11
13
)
···
13
15
//go:embed templates/*
14
16
var Files embed.FS
15
17
16
16
-
// inspired from tangled's implementation
17
17
-
//https://tangled.org/@tangled.org/core/blob/master/appview/pages/pages.go
18
18
-
19
18
type Pages struct {
20
19
cache *TmplCache[string, *template.Template]
21
21
-
dev bool
22
20
templateDir string // Path to templates on disk for dev mode
23
21
embedFS fs.FS
24
22
}
25
23
26
26
-
func NewPages(dev bool) *Pages {
27
27
-
pages := &Pages{
28
28
-
cache: NewTmplCache[string, *template.Template](),
29
29
-
dev: dev,
30
30
-
templateDir: "templates",
31
31
-
}
32
32
-
if pages.dev {
33
33
-
pages.embedFS = os.DirFS(pages.templateDir)
34
34
-
} else {
35
35
-
pages.embedFS = Files
24
24
+
func NewPages() *Pages {
25
25
+
return &Pages{
26
26
+
cache: NewTmplCache[string, *template.Template](),
27
27
+
embedFS: Files,
36
28
}
37
37
-
38
38
-
return pages
39
29
}
40
30
41
31
func (p *Pages) fragmentPaths() ([]string, error) {
···
99
89
func (p *Pages) parse(stack ...string) (*template.Template, error) {
100
90
key := strings.Join(stack, "|")
101
91
102
102
-
// never cache in dev mode
103
103
-
if cached, exists := p.cache.Get(key); !p.dev && exists {
92
92
+
if cached, exists := p.cache.Get(key); exists {
104
93
return cached, nil
105
94
}
106
95
+58
-1
pages/templates/home.gohtml
···
1
1
2
2
{{ define "content" }}
3
3
4
4
-
<h1>Test</h1>
4
4
+
<h1>Piper - Multi-User Spotify & Last.fm Tracker via ATProto</h1>
5
5
+
<div class="nav">
6
6
+
<a href="/">Home</a>
7
7
+
8
8
+
{{if .IsLoggedIn}}
9
9
+
<a href="/current-track">Spotify Current</a>
10
10
+
<a href="/history">Spotify History</a>
11
11
+
<a href="/link-lastfm">Link Last.fm</a>
12
12
+
{{ if .LastFMUsername }}
13
13
+
<a href="/lastfm/recent">Last.fm Recent</a>
14
14
+
{{ end }}
15
15
+
<a href="/api-keys">API Keys</a>
16
16
+
<a href="/login/spotify">Connect Spotify Account</a>
17
17
+
<a href="/logout">Logout</a>
18
18
+
{{ else }}
19
19
+
<a href="/login/atproto">Login with ATProto</a>
20
20
+
{{ end }}
21
21
+
</div>
22
22
+
23
23
+
<div class="card">
24
24
+
<h2>Welcome to Piper</h2>
25
25
+
<p>Piper is a multi-user application that records what you're listening to on Spotify and Last.fm, saving your listening history.</p>
26
26
+
27
27
+
{{if .IsLoggedIn}}
28
28
+
<p>You're logged in!</p>
29
29
+
<ul>
30
30
+
<li><a href="/login/spotify">Connect your Spotify account</a> to start tracking.</li>
31
31
+
<li><a href="/link-lastfm">Link your Last.fm account</a> to track scrobbles.</li>
32
32
+
</ul>
33
33
+
<p>Once connected, you can check out your:</p>
34
34
+
<ul>
35
35
+
<li><a href="/current-track">Spotify current track</a> or <a href="/history">listening history</a>.</li>
36
36
+
{{ if .LastFMUsername }}
37
37
+
<li><a href="/lastfm/recent">Last.fm recent tracks</a>.</li>
38
38
+
{{ end }}
39
39
+
40
40
+
</ul>
41
41
+
<p>You can also manage your <a href="/api-keys">API keys</a> for programmatic access.</p>
42
42
+
43
43
+
{{ if .LastFMUsername }}
44
44
+
<p class='service-status'>Last.fm Username: {{ .LastFMUsername }}</p>
45
45
+
{{else }}
46
46
+
<p class='service-status'>Last.fm account not linked.</p>
47
47
+
{{end}}
48
48
+
49
49
+
50
50
+
{{ else }}
51
51
+
52
52
+
<p>Login with ATProto to get started!</p>
53
53
+
<form action="/login/atproto">
54
54
+
<label for="handle">handle:</label>
55
55
+
<input type="text" id="handle" name="handle" >
56
56
+
<input type="submit" value="submit">
57
57
+
</form>
58
58
+
59
59
+
60
60
+
{{ end }}
61
61
+
</div> <!-- Close card div -->
5
62
6
63
{{ end }}