diff --git a/cmdHandlers.go b/cmdHandlers.go new file mode 100644 index 0000000..08e393f --- /dev/null +++ b/cmdHandlers.go @@ -0,0 +1,190 @@ +package main + +import ( + "context" + "crypto/tls" + "fmt" + "log" + "log/slog" + "net/http" + "song-recognition/shazam" + "song-recognition/spotify" + "song-recognition/utils" + "song-recognition/wav" + "strings" + + "github.com/fatih/color" + socketio "github.com/googollee/go-socket.io" + "github.com/googollee/go-socket.io/engineio" + "github.com/googollee/go-socket.io/engineio/transport" + "github.com/googollee/go-socket.io/engineio/transport/polling" + "github.com/googollee/go-socket.io/engineio/transport/websocket" + "github.com/mdobak/go-xerrors" +) + +const ( + SONGS_DIR = "songs" +) + +var yellow = color.New(color.FgYellow) + +func find(filePath string) { + wavInfo, err := wav.ReadWavInfo(filePath) + if err != nil { + yellow.Println("Error reading wave info:", err) + return + } + + samples, err := wav.WavBytesToSamples(wavInfo.Data) + if err != nil { + yellow.Println("Error converting to samples:", err) + return + } + + matches, searchDuration, err := shazam.FindMatches(samples, wavInfo.Duration, wavInfo.SampleRate) + if err != nil { + yellow.Println("Error finding matches:", err) + return + } + + msg := "Matches:" + topMatches := matches + if len(matches) >= 20 { + msg = "Top 20 matches:" + topMatches = matches[:20] + } + + fmt.Println(msg) + for _, match := range topMatches { + fmt.Printf("\t- %s by %s, score: %.2f\n", + match.SongTitle, match.SongArtist, match.Score) + } + + fmt.Printf("\nSearch took: %s\n", searchDuration) + topMatch := topMatches[0] + fmt.Printf("\nFinal prediction: %s by %s , score: %.2f\n", + topMatch.SongTitle, topMatch.SongArtist, topMatch.Score) +} + +func download(spotifyURL string) { + err := spotify.CreateFolder(SONGS_DIR) + if err != nil { + err := xerrors.New(err) + logger := utils.GetLogger() + ctx := context.Background() + logMsg := fmt.Sprintf("failed to create directory %v", SONGS_DIR) + logger.ErrorContext(ctx, logMsg, slog.Any("error", err)) + } + + if strings.Contains(spotifyURL, "album") { + _, err := spotify.DlAlbum(spotifyURL, SONGS_DIR) + if err != nil { + yellow.Println("Error: ", err) + } + } + + if strings.Contains(spotifyURL, "playlist") { + _, err := spotify.DlPlaylist(spotifyURL, SONGS_DIR) + if err != nil { + yellow.Println("Error: ", err) + } + } + + if strings.Contains(spotifyURL, "track") { + _, err := spotify.DlSingleTrack(spotifyURL, SONGS_DIR) + if err != nil { + yellow.Println("Error: ", err) + } + } +} + +func serve(protocol, port string) { + protocol = strings.ToLower(protocol) + var allowOriginFunc = func(r *http.Request) bool { + return true + } + + err := spotify.CreateFolder(SONGS_DIR) + if err != nil { + err := xerrors.New(err) + logger := utils.GetLogger() + ctx := context.Background() + logMsg := fmt.Sprintf("failed to create directory %v", SONGS_DIR) + logger.ErrorContext(ctx, logMsg, slog.Any("error", err)) + } + + server := socketio.NewServer(&engineio.Options{ + Transports: []transport.Transport{ + &polling.Transport{ + CheckOrigin: allowOriginFunc, + }, + &websocket.Transport{ + CheckOrigin: allowOriginFunc, + }, + }, + }) + + server.OnConnect("/", func(socket socketio.Conn) error { + socket.SetContext("") + log.Println("CONNECTED: ", socket.ID()) + + return nil + }) + + server.OnEvent("/", "totalSongs", handleTotalSongs) + server.OnEvent("/", "newDownload", handleSongDownload) + server.OnEvent("/", "newRecording", handleNewRecording) + + server.OnError("/", func(s socketio.Conn, e error) { + log.Println("meet error:", e) + }) + + server.OnDisconnect("/", func(s socketio.Conn, reason string) { + log.Println("closed", reason) + }) + + go func() { + if err := server.Serve(); err != nil { + log.Fatalf("socketio listen error: %s\n", err) + } + }() + defer server.Close() + + serveHTTPS := protocol == "https" + + serveHTTP(server, serveHTTPS, port) +} + +func serveHTTP(socketServer *socketio.Server, serveHTTPS bool, port string) { + http.Handle("/socket.io/", socketServer) + + if serveHTTPS { + httpsAddr := ":" + port + httpsServer := &http.Server{ + Addr: httpsAddr, + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + }, + Handler: socketServer, + } + + cert_key_default := "/etc/letsencrypt/live/localport.online/privkey.pem" + cert_file_default := "/etc/letsencrypt/live/localport.online/fullchain.pem" + + cert_key := utils.GetEnv("CERT_KEY", cert_key_default) + cert_file := utils.GetEnv("CERT_FILE", cert_file_default) + if cert_key == "" || cert_file == "" { + log.Fatal("Missing cert") + } + + log.Printf("Starting HTTPS server on %s\n", httpsAddr) + if err := httpsServer.ListenAndServeTLS(cert_file, cert_key); err != nil { + log.Fatalf("HTTPS server ListenAndServeTLS: %v", err) + } + } + + log.Printf("Starting HTTP server on port %v", port) + if err := http.ListenAndServe(":"+port, nil); err != nil { + log.Fatalf("HTTP server ListenAndServe: %v", err) + } +} diff --git a/main.go b/main.go index 63117d6..a2eea4e 100644 --- a/main.go +++ b/main.go @@ -1,121 +1,40 @@ package main import ( - "context" - "crypto/tls" + "flag" "fmt" - "log" - "log/slog" - "net/http" - "song-recognition/spotify" - "song-recognition/utils" - "strconv" - "strings" - - "github.com/mdobak/go-xerrors" - - socketio "github.com/googollee/go-socket.io" - "github.com/googollee/go-socket.io/engineio" - "github.com/googollee/go-socket.io/engineio/transport" - "github.com/googollee/go-socket.io/engineio/transport/polling" - "github.com/googollee/go-socket.io/engineio/transport/websocket" + "os" ) -const ( - SONGS_DIR = "songs" -) - -var allowOriginFunc = func(r *http.Request) bool { - return true -} - func main() { - - err := spotify.CreateFolder(SONGS_DIR) - if err != nil { - err := xerrors.New(err) - logger := utils.GetLogger() - ctx := context.Background() - logMsg := fmt.Sprintf("failed to create directory %v", SONGS_DIR) - logger.ErrorContext(ctx, logMsg, slog.Any("error", err)) + if len(os.Args) < 2 { + fmt.Println("Expected 'find', 'download', or 'serve' subcommands") + os.Exit(1) } - server := socketio.NewServer(&engineio.Options{ - Transports: []transport.Transport{ - &polling.Transport{ - CheckOrigin: allowOriginFunc, - }, - &websocket.Transport{ - CheckOrigin: allowOriginFunc, - }, - }, - }) - - server.OnConnect("/", func(socket socketio.Conn) error { - socket.SetContext("") - log.Println("CONNECTED: ", socket.ID()) - - return nil - }) - - server.OnEvent("/", "totalSongs", handleTotalSongs) - server.OnEvent("/", "newDownload", handleSongDownload) - server.OnEvent("/", "newRecording", handleNewRecording) - - server.OnError("/", func(s socketio.Conn, e error) { - log.Println("meet error:", e) - }) - - server.OnDisconnect("/", func(s socketio.Conn, reason string) { - log.Println("closed", reason) - }) - - go func() { - if err := server.Serve(); err != nil { - log.Fatalf("socketio listen error: %s\n", err) + switch os.Args[1] { + case "find": + if len(os.Args) < 3 { + fmt.Println("Usage: main.go find ") + os.Exit(1) } - }() - defer server.Close() - - SERVE_HTTPS := strings.ToLower(utils.GetEnv("SERVE_HTTPS", "true")) - serveHTTPS, err := strconv.ParseBool(SERVE_HTTPS) - if err != nil { - log.Fatalf("Error converting string to bool: %v", err) - } - - serveHTTP(server, serveHTTPS) -} - -func serveHTTP(socketServer *socketio.Server, serveHTTPS bool) { - http.Handle("/socket.io/", socketServer) - - if serveHTTPS { - httpsAddr := ":4443" - httpsServer := &http.Server{ - Addr: httpsAddr, - TLSConfig: &tls.Config{ - MinVersion: tls.VersionTLS12, - }, - Handler: socketServer, + filePath := os.Args[2] + find(filePath) + case "download": + if len(os.Args) < 3 { + fmt.Println("Usage: main.go download ") + os.Exit(1) } - - cert_key_default := "/etc/letsencrypt/live/localport.online/privkey.pem" - cert_file_default := "/etc/letsencrypt/live/localport.online/fullchain.pem" - - cert_key := utils.GetEnv("CERT_KEY", cert_key_default) - cert_file := utils.GetEnv("CERT_FILE", cert_file_default) - if cert_key == "" || cert_file == "" { - log.Fatal("Missing cert") - } - - log.Printf("Starting HTTPS server on %s\n", httpsAddr) - if err := httpsServer.ListenAndServeTLS(cert_file, cert_key); err != nil { - log.Fatalf("HTTPS server ListenAndServeTLS: %v", err) - } - } - - log.Printf("Starting HTTP server on port 5000") - if err := http.ListenAndServe(":5000", nil); err != nil { - log.Fatalf("HTTP server ListenAndServe: %v", err) + url := os.Args[2] + download(url) + case "serve": + serveCmd := flag.NewFlagSet("serve", flag.ExitOnError) + protocol := serveCmd.String("proto", "http", "Protocol to use (http or https)") + port := serveCmd.String("p", "5000", "Port to use") + serveCmd.Parse(os.Args[2:]) + serve(*protocol, *port) + default: + fmt.Println("Expected 'find', 'download', or 'serve' subcommands") + os.Exit(1) } }