Skip to content

Commit

Permalink
feat: provide endpoint for a specific playlist
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Gleich <git@mattglei.ch>
  • Loading branch information
gleich committed Jan 2, 2025
1 parent 7bcd8e9 commit a4f8522
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 23 deletions.
1 change: 1 addition & 0 deletions internal/apis/applemusic/applemusic.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func Setup(router *chi.Mux) {

applemusicCache := cache.New("applemusic", data)
router.Get("/applemusic", applemusicCache.ServeHTTP())
router.Get("/applemusic/playlist/{id}", playlistEndpoint(*&applemusicCache))

Check failure on line 63 in internal/apis/applemusic/applemusic.go

View workflow job for this annotation

GitHub Actions / golangci-lint

SA4001: *&x will be simplified to x. It will not copy x. (staticcheck)
router.Handle("/applemusic/ws", applemusicCache.ServeWS())
go applemusicCache.UpdatePeriodically(cacheUpdate, 30*time.Second)
lumber.Done("setup apple music cache")
Expand Down
32 changes: 32 additions & 0 deletions internal/apis/applemusic/playlists.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package applemusic

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"time"

"github.com/gleich/lcp-v2/internal/apis"
"github.com/gleich/lcp-v2/internal/cache"
"github.com/gleich/lumber/v3"
"github.com/go-chi/chi/v5"
)

type playlist struct {
Expand Down Expand Up @@ -73,3 +77,31 @@ func fetchPlaylist(id string) (playlist, error) {
ID: playlistData.Data[0].ID,
}, nil
}

func playlistEndpoint(c *cache.Cache[cacheData]) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")

c.DataMutex.RLock()
var p *playlist
for _, plist := range c.Data.Playlists {
if plist.ID == id {
p = &plist
break
}
}

if p == nil {
c.DataMutex.RUnlock()
w.WriteHeader(http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(w).Encode(p)
c.DataMutex.RUnlock()
if err != nil {
lumber.Error(err, "failed to write json data to request")
w.WriteHeader(http.StatusInternalServerError)
}
})
}
25 changes: 12 additions & 13 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (

type Cache[T any] struct {
name string
dataMutex sync.RWMutex
data T
DataMutex sync.RWMutex
Data T
updated time.Time
filePath string
wsConnPool map[*websocket.Conn]bool
Expand Down Expand Up @@ -52,36 +52,35 @@ type cacheData[T any] struct {
func (c *Cache[T]) ServeHTTP() http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
c.dataMutex.RLock()
err := json.NewEncoder(w).Encode(cacheData[T]{Data: c.data, Updated: c.updated})
c.dataMutex.RUnlock()
c.DataMutex.RLock()
err := json.NewEncoder(w).Encode(cacheData[T]{Data: c.Data, Updated: c.updated})
c.DataMutex.RUnlock()
if err != nil {
lumber.Error(err, "failed to write data")
lumber.Error(err, "failed to write json data to request")
w.WriteHeader(http.StatusInternalServerError)
return
}
})
}

func (c *Cache[T]) Update(data T) {
c.dataMutex.RLock()
old, err := json.Marshal(c.data)
c.DataMutex.RLock()
old, err := json.Marshal(c.Data)
if err != nil {
lumber.Error(err, "failed to json marshal old data")
return
}
c.dataMutex.RUnlock()
c.DataMutex.RUnlock()
new, err := json.Marshal(data)
if err != nil {
lumber.Error(err, "failed to json marshal new data")
return
}

if string(old) != string(new) && string(new) != "null" && strings.Trim(string(new), " ") != "" {
c.dataMutex.Lock()
c.data = data
c.DataMutex.Lock()
c.Data = data
c.updated = time.Now()
c.dataMutex.Unlock()
c.DataMutex.Unlock()

c.persistToFile()
connectionsUpdated := c.broadcastUpdate()
Expand Down
8 changes: 4 additions & 4 deletions internal/cache/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ func (c *Cache[T]) persistToFile() {
}
defer file.Close()

c.dataMutex.RLock()
c.DataMutex.RLock()
b, err := json.Marshal(cacheData[T]{
Data: c.data,
Data: c.Data,
Updated: c.updated,
})
c.dataMutex.RUnlock()
c.DataMutex.RUnlock()
if err != nil {
lumber.Error(err, "encoding data to json failed")
return
Expand All @@ -60,7 +60,7 @@ func (c *Cache[T]) loadFromFile() {
lumber.Fatal(err, "unmarshal json data failed from:", string(b))
}

c.data = data.Data
c.Data = data.Data
c.updated = data.Updated
}
}
12 changes: 6 additions & 6 deletions internal/cache/websockets.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ func (c *Cache[T]) ServeWS() http.HandlerFunc {
c.wsConnPoolMutex.Unlock()

// sending initial data
c.dataMutex.RLock()
err = conn.WriteJSON(c.data)
c.dataMutex.RUnlock()
c.DataMutex.RLock()
err = conn.WriteJSON(c.Data)
c.DataMutex.RUnlock()
if err != nil {
lumber.Error(err, "failed to write initial cache data for", c.name)
c.removeConnection(conn)
Expand All @@ -43,9 +43,9 @@ func (c *Cache[T]) ServeWS() http.HandlerFunc {
}

func (c *Cache[T]) broadcastUpdate() int {
c.dataMutex.RLock()
d := c.data
c.dataMutex.RUnlock()
c.DataMutex.RLock()
d := c.Data
c.DataMutex.RUnlock()

updatedConnections := 0
for conn := range c.wsConnPool {
Expand Down

0 comments on commit a4f8522

Please sign in to comment.