forked from
rocksky.app/rocksky
A decentralized music tracking and discovery platform built on AT Protocol 馃幍
1package main
2
3import (
4 "context"
5 "fmt"
6 "log"
7 "net/http"
8 "os"
9 "os/signal"
10 "strings"
11 "time"
12
13 "github.com/labstack/echo/v4"
14 "github.com/teal-fm/piper/db"
15 "github.com/teal-fm/piper/models"
16 "github.com/teal-fm/piper/service/musicbrainz"
17)
18
19type Server struct {
20 mb *musicbrainz.MusicBrainzService
21}
22
23func main() {
24 dbPath := os.Getenv("DB_PATH")
25 if dbPath == "" {
26 dbPath = "./piper.db"
27 }
28
29 database, err := db.New(dbPath)
30 if err != nil {
31 log.Fatalf("Error connecting to database: %v", err)
32 }
33
34 if err := database.Initialize(); err != nil {
35 log.Fatalf("Error initializing database: %v", err)
36 }
37
38 srv := &Server{
39 mb: musicbrainz.NewMusicBrainzService(database),
40 }
41
42 e := echo.New()
43
44 e.POST("/search", srv.searchHandler)
45 e.POST("/hydrate", srv.hydrateHandler)
46
47 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
48 defer stop()
49
50 go func() {
51 port := os.Getenv("PORT")
52
53 if port == "" {
54 port = "8088"
55 }
56
57 if err := e.Start(fmt.Sprintf(":%s", port)); err != nil && err != http.ErrServerClosed {
58 e.Logger.Fatal(err)
59 }
60 }()
61
62 <-ctx.Done() // wait for Ctrl+C
63 shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
64 defer cancel()
65 _ = e.Shutdown(shutdownCtx)
66}
67
68func (s *Server) searchHandler(c echo.Context) error {
69 var req musicbrainz.SearchParams
70
71 if err := c.Bind(&req); err != nil {
72 return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
73 }
74
75 req.Track = cleanTitle(req.Track)
76 resp, _ := s.mb.SearchMusicBrainz(c.Request().Context(), req)
77
78 return c.JSON(http.StatusOK, resp)
79}
80
81func (s *Server) hydrateHandler(c echo.Context) error {
82 var req models.Track
83
84 if err := c.Bind(&req); err != nil {
85 return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
86 }
87
88 req.Name = cleanTitle(req.Name)
89 resp, _ := musicbrainz.HydrateTrack(s.mb, req)
90
91 return c.JSON(http.StatusOK, resp)
92}
93
94func cleanTitle(title string) string {
95 removePatterns := []string{
96 " - Album Version (Edited)",
97 " - Album Version (Explicit)",
98 " - Album Version",
99 " (Album Version (Edited))",
100 " (Album Version (Explicit))",
101 " (Album Version)",
102 " - Edited",
103 " - Explicit",
104 " - Radio Edit",
105 " (Edited)",
106 " (Explicit)",
107 " (Radio Edit)",
108 }
109
110 for _, pattern := range removePatterns {
111 title = strings.ReplaceAll(title, pattern, "")
112 }
113
114 return strings.TrimSpace(title)
115}