[WIP] music platform user data scraper
teal-fm atproto

kind of working static

Changed files
+80 -8
cmd
pages
static
templates
service
playingnow
+7
cmd/routes.go
··· 10 11 func (app *application) routes() http.Handler { 12 mux := http.NewServeMux() 13 14 mux.HandleFunc("/", session.WithPossibleAuth(home(app.database, app.pages), app.sessionManager)) 15
··· 10 11 func (app *application) routes() http.Handler { 12 mux := http.NewServeMux() 13 + // Redirect /static to /static/ so it doesn't fall through to "/" handler 14 + mux.Handle("/static/{file_name}", app.pages.Static()) 15 + //mux.HandleFunc("/static/{file_name}", func(w http.ResponseWriter, r *http.Request) { 16 + // w.Header().Set("Content-Type", "text/html") 17 + // 18 + // w.Write([]byte("Static files are served from /static/")) 19 + //}) 20 21 mux.HandleFunc("/", session.WithPossibleAuth(home(app.database, app.pages), app.sessionManager)) 22
+29 -5
pages/pages.go
··· 1 package pages 2 3 // forked and inspired from tangled's implementation 4 //https://tangled.org/@tangled.org/core/blob/master/appview/pages/pages.go 5 ··· 8 "html/template" 9 "io" 10 "io/fs" 11 "strings" 12 "time" 13 ) 14 15 - //go:embed templates/* 16 var Files embed.FS 17 18 type Pages struct { ··· 116 return p.parse(stack...) 117 } 118 119 - func (p *Pages) executePlain(name string, w io.Writer, params any) error { 120 - tpl, err := p.parse(name) 121 if err != nil { 122 - return err 123 } 124 125 - return tpl.Execute(w, params) 126 } 127 128 func (p *Pages) Execute(name string, w io.Writer, params any) error { 129 tpl, err := p.parseBase(name) 130 if err != nil {
··· 1 package pages 2 3 + // Helpers to load gohtml templates and render them 4 // forked and inspired from tangled's implementation 5 //https://tangled.org/@tangled.org/core/blob/master/appview/pages/pages.go 6 ··· 9 "html/template" 10 "io" 11 "io/fs" 12 + "net/http" 13 "strings" 14 "time" 15 ) 16 17 + //go:embed templates/* static/* 18 var Files embed.FS 19 20 type Pages struct { ··· 118 return p.parse(stack...) 119 } 120 121 + func (p *Pages) Static() http.Handler { 122 + //if p.dev { 123 + // return http.StripPrefix("/static/", http.FileServer(http.Dir("appview/pages/static"))) 124 + //} 125 + 126 + sub, err := fs.Sub(Files, "static") 127 if err != nil { 128 + //p.logger.Error("no static dir found? that's crazy", "err", err) 129 + panic(err) 130 } 131 + return http.StripPrefix("/static/", http.FileServer(http.FS(sub))) 132 + // Custom handler to apply Cache-Control headers for font files 133 + //return http.FileServer(http.FS(sub)) 134 + //return http.FileServer(http.FS(sub)) 135 + } 136 137 + func Cache(h http.Handler) http.Handler { 138 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 139 + path := strings.Split(r.URL.Path, "?")[0] 140 + 141 + if strings.HasSuffix(path, ".css") { 142 + // on day for css files 143 + w.Header().Set("Cache-Control", "public, max-age=86400") 144 + } else { 145 + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") 146 + } 147 + h.ServeHTTP(w, r) 148 + }) 149 } 150 151 + // Execute What loads and renders the HTML page/ 152 func (p *Pages) Execute(name string, w io.Writer, params any) error { 153 tpl, err := p.parseBase(name) 154 if err != nil {
+32
pages/static/style.css
···
··· 1 + body { 2 + font-family: Arial, sans-serif; 3 + max-width: 800px; 4 + margin: 0 auto; 5 + padding: 20px; 6 + line-height: 1.6; 7 + } 8 + h1 { 9 + color: #1DB954; /* Spotify green */ 10 + } 11 + .nav { 12 + display: flex; 13 + flex-wrap: wrap; /* Allow wrapping on smaller screens */ 14 + margin-bottom: 20px; 15 + } 16 + .nav a { 17 + margin-right: 15px; 18 + margin-bottom: 5px; /* Add spacing below links */ 19 + text-decoration: none; 20 + color: #1DB954; 21 + font-weight: bold; 22 + } 23 + .card { 24 + border: 1px solid #ddd; 25 + border-radius: 8px; 26 + padding: 20px; 27 + margin-bottom: 20px; 28 + } 29 + .service-status { 30 + font-style: italic; 31 + color: #555; 32 + }
+10
pages/templates/lastFMForm.gohtml
···
··· 1 + {{ define "content" }} 2 + <h2>Link Your Last.fm Account</h2> 3 + <p>Enter your Last.fm username to start tracking your scrobbles.</p> 4 + <form method="post" action="/link-lastfm"> 5 + <label for="lastfm_username">Last.fm Username:</label> 6 + <input type="text" id="lastfm_username" name="lastfm_username" value="%s" required> 7 + <input type="submit" value="Save Username"> 8 + </form> 9 + 10 + {{ end }}
+1
pages/templates/layouts/base.gohtml
··· 3 <html lang="en"> 4 <head> 5 <title>Piper - Spotify & Last.fm Tracker</title> 6 <style> 7 body { 8 font-family: Arial, sans-serif;
··· 3 <html lang="en"> 4 <head> 5 <title>Piper - Spotify & Last.fm Tracker</title> 6 + <link rel="stylesheet" href="~/static/style.css"> 7 <style> 8 body { 9 font-family: Arial, sans-serif;
+1 -3
service/playingnow/playingnow.go
··· 86 Item: playView, 87 } 88 89 - var swapRecord *string 90 authArgs := db.AtpSessionToAuthArgs(sess) 91 - 92 swapRecord, err = p.getStatusSwapRecord(ctx, xrpcClient, sess, authArgs) 93 if err != nil { 94 return err ··· 166 } 167 168 authArgs := db.AtpSessionToAuthArgs(sess) 169 - 170 var swapRecord *string 171 swapRecord, err = p.getStatusSwapRecord(ctx, xrpcClient, sess, authArgs) 172 if err != nil {
··· 86 Item: playView, 87 } 88 89 authArgs := db.AtpSessionToAuthArgs(sess) 90 + var swapRecord *string 91 swapRecord, err = p.getStatusSwapRecord(ctx, xrpcClient, sess, authArgs) 92 if err != nil { 93 return err ··· 165 } 166 167 authArgs := db.AtpSessionToAuthArgs(sess) 168 var swapRecord *string 169 swapRecord, err = p.getStatusSwapRecord(ctx, xrpcClient, sess, authArgs) 170 if err != nil {