A decentralized music tracking and discovery platform built on AT Protocol 馃幍
at main 115 lines 2.4 kB view raw
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}