From 28dd6b6ae32e0cccdaf6486fb76c6b7f98647f27 Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sat, 9 Oct 2021 17:20:22 -0700 Subject: scrobbler: watch for events and print song details We create a module "mpd" to interact with our MPD instance. For now we only have a single function to create a new client, which creates an actual client for mpd (and we ping the instance every 30 seconds), and a watcher to receive new events. The tool "scrobbler" then wait for new events and display songs information. --- cmd/mpd-scrobbler/main.go | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 cmd/mpd-scrobbler/main.go (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go new file mode 100644 index 0000000..9929225 --- /dev/null +++ b/cmd/mpd-scrobbler/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "log" + + "golang.fcuny.net/mpd-stats/internal/mpd" +) + +func main() { + net := "tcp" + addr := "localhost:6600" + + c, err := mpd.NewMPD(net, addr) + if err != nil { + log.Fatalf("failed to create a client: %v", err) + } + + defer c.Watcher.Close() + defer c.Client.Close() + + for { + e := <-c.Watcher.Event + if e != "" { + attrs, err := c.Client.CurrentSong() + if err != nil { + log.Fatalf("could not get current song: %v", err) + } + currentAlbum := attrs["Album"] + artist := attrs["Artist"] + song := attrs["Title"] + duration := attrs["duration"] + log.Printf("we're playing %s/%s/%s [%s]\n", artist, currentAlbum, song, duration) + } + } +} -- cgit v1.2.3 From 6fde72a495edef3ed108fec5a3324638a8518361 Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sat, 9 Oct 2021 18:19:17 -0700 Subject: scrobbler: create a record on new song When we receive an event from the player, we look if the song is different from the previous one, and we create a new record if that's the case. If the song is similar, there's nothing to do. --- cmd/mpd-scrobbler/main.go | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go index 9929225..40b1348 100644 --- a/cmd/mpd-scrobbler/main.go +++ b/cmd/mpd-scrobbler/main.go @@ -4,6 +4,7 @@ import ( "log" "golang.fcuny.net/mpd-stats/internal/mpd" + "golang.fcuny.net/mpd-stats/internal/scrobbler" ) func main() { @@ -18,6 +19,10 @@ func main() { defer c.Watcher.Close() defer c.Client.Close() + var ( + currentRecord *scrobbler.Record + previousRecord *scrobbler.Record + ) for { e := <-c.Watcher.Event if e != "" { @@ -25,11 +30,28 @@ func main() { if err != nil { log.Fatalf("could not get current song: %v", err) } - currentAlbum := attrs["Album"] - artist := attrs["Artist"] - song := attrs["Title"] - duration := attrs["duration"] - log.Printf("we're playing %s/%s/%s [%s]\n", artist, currentAlbum, song, duration) + + if currentRecord == nil { + currentRecord, err = scrobbler.NewRecord(attrs) + if err != nil { + log.Fatalf("could not create a log: %v", err) + } + log.Printf("we're playing %s/%s/%s [%s]\n", currentRecord.Artist, currentRecord.Album, currentRecord.Title, currentRecord.Duration) + previousRecord = currentRecord + continue + } + + if currentRecord.Title != attrs["Title"] || currentRecord.Artist != attrs["Artist"] || currentRecord.Album != attrs["Album"] { + currentRecord, err = scrobbler.NewRecord(attrs) + if err != nil { + log.Fatalf("could not create a log: %v", err) + } + } + + if currentRecord.Id != previousRecord.Id { + log.Printf("we're playing %s/%s/%s [%s]\n", currentRecord.Artist, currentRecord.Album, currentRecord.Title, currentRecord.Duration) + previousRecord = currentRecord + } } } } -- cgit v1.2.3 From 14e16c0b3818a68cf3a1f26f9cd7461481d00e4d Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sun, 10 Oct 2021 11:32:10 -0700 Subject: mpd: rename function to create the player --- cmd/mpd-scrobbler/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go index 40b1348..3953123 100644 --- a/cmd/mpd-scrobbler/main.go +++ b/cmd/mpd-scrobbler/main.go @@ -11,7 +11,7 @@ func main() { net := "tcp" addr := "localhost:6600" - c, err := mpd.NewMPD(net, addr) + c, err := mpd.NewPlayer(net, addr) if err != nil { log.Fatalf("failed to create a client: %v", err) } -- cgit v1.2.3 From 5caeabc351feffb1769b842e8d79481f330c46d9 Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sun, 10 Oct 2021 11:34:07 -0700 Subject: mpd: add function `Close` to the player Let's close both the watcher and the client, instead of leaking this interface to the user. --- cmd/mpd-scrobbler/main.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go index 3953123..ba7bb05 100644 --- a/cmd/mpd-scrobbler/main.go +++ b/cmd/mpd-scrobbler/main.go @@ -16,8 +16,11 @@ func main() { log.Fatalf("failed to create a client: %v", err) } - defer c.Watcher.Close() - defer c.Client.Close() + defer func() { + if err := c.Close(); err != nil { + log.Fatalf("failed to close the player: %v", err) + } + }() var ( currentRecord *scrobbler.Record -- cgit v1.2.3 From b5c00edf16716e4398c5ce0827164648f203e8d6 Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sun, 10 Oct 2021 11:47:52 -0700 Subject: mpd-stats: create and run the scrobbler --- cmd/mpd-scrobbler/main.go | 43 ++++--------------------------------------- 1 file changed, 4 insertions(+), 39 deletions(-) (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go index ba7bb05..3540807 100644 --- a/cmd/mpd-scrobbler/main.go +++ b/cmd/mpd-scrobbler/main.go @@ -3,7 +3,6 @@ package main import ( "log" - "golang.fcuny.net/mpd-stats/internal/mpd" "golang.fcuny.net/mpd-stats/internal/scrobbler" ) @@ -11,50 +10,16 @@ func main() { net := "tcp" addr := "localhost:6600" - c, err := mpd.NewPlayer(net, addr) + s, err := scrobbler.NewScrobbler(net, addr) if err != nil { log.Fatalf("failed to create a client: %v", err) } defer func() { - if err := c.Close(); err != nil { - log.Fatalf("failed to close the player: %v", err) + if err := s.Close(); err != nil { + log.Fatalf("failed to close the scrobbler: %v", err) } }() - var ( - currentRecord *scrobbler.Record - previousRecord *scrobbler.Record - ) - for { - e := <-c.Watcher.Event - if e != "" { - attrs, err := c.Client.CurrentSong() - if err != nil { - log.Fatalf("could not get current song: %v", err) - } - - if currentRecord == nil { - currentRecord, err = scrobbler.NewRecord(attrs) - if err != nil { - log.Fatalf("could not create a log: %v", err) - } - log.Printf("we're playing %s/%s/%s [%s]\n", currentRecord.Artist, currentRecord.Album, currentRecord.Title, currentRecord.Duration) - previousRecord = currentRecord - continue - } - - if currentRecord.Title != attrs["Title"] || currentRecord.Artist != attrs["Artist"] || currentRecord.Album != attrs["Album"] { - currentRecord, err = scrobbler.NewRecord(attrs) - if err != nil { - log.Fatalf("could not create a log: %v", err) - } - } - - if currentRecord.Id != previousRecord.Id { - log.Printf("we're playing %s/%s/%s [%s]\n", currentRecord.Artist, currentRecord.Album, currentRecord.Title, currentRecord.Duration) - previousRecord = currentRecord - } - } - } + s.Run() } -- cgit v1.2.3 From c95f72a953e6a9068c1e7b89f530fa05f10c4bde Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sun, 10 Oct 2021 13:01:21 -0700 Subject: mpd-stats: pass database path to the scrobbler When creating a scrobbler, we provide the path to the database. The scrobbler then get a handler to the database. When a new record is created, we persist it to the database using the `save` function. --- cmd/mpd-scrobbler/main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go index 3540807..fdd9e4d 100644 --- a/cmd/mpd-scrobbler/main.go +++ b/cmd/mpd-scrobbler/main.go @@ -1,7 +1,9 @@ package main import ( + "fmt" "log" + "os" "golang.fcuny.net/mpd-stats/internal/scrobbler" ) @@ -9,8 +11,9 @@ import ( func main() { net := "tcp" addr := "localhost:6600" + dbpath := fmt.Sprintf("%s/.config/scrobbler.sql", os.Getenv("HOME")) - s, err := scrobbler.NewScrobbler(net, addr) + s, err := scrobbler.NewScrobbler(net, addr, dbpath) if err != nil { log.Fatalf("failed to create a client: %v", err) } -- cgit v1.2.3 From 8ce42165d8baa3b5e8e1feac072ca8275bfcb826 Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sun, 10 Oct 2021 16:10:32 -0700 Subject: mpd-scrobbler: proper default arguments The program needs two arguments: the mpd host and port, which can be passed as flags (default is to use the local instance of mpd). We store the database in `XDG_CONFIG_HOME/mpd-scrobbler`, and we create the path if needed. --- cmd/mpd-scrobbler/main.go | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'cmd/mpd-scrobbler/main.go') diff --git a/cmd/mpd-scrobbler/main.go b/cmd/mpd-scrobbler/main.go index fdd9e4d..c2693a4 100644 --- a/cmd/mpd-scrobbler/main.go +++ b/cmd/mpd-scrobbler/main.go @@ -1,17 +1,29 @@ package main import ( + "flag" "fmt" "log" "os" + "path/filepath" "golang.fcuny.net/mpd-stats/internal/scrobbler" ) func main() { + var ( + mpdHost = flag.String("host", "localhost", "The MPD server to connect to (default: localhost)") + mpdPort = flag.Int("port", 6600, "The TCP port of the MPD server to connect to (default: 6600)") + ) + flag.Parse() + net := "tcp" - addr := "localhost:6600" - dbpath := fmt.Sprintf("%s/.config/scrobbler.sql", os.Getenv("HOME")) + addr := fmt.Sprintf("%s:%d", *mpdHost, *mpdPort) + + dbpath, err := getDbPath() + if err != nil { + log.Fatalf("failed to get the path to the database: %v", err) + } s, err := scrobbler.NewScrobbler(net, addr, dbpath) if err != nil { @@ -26,3 +38,20 @@ func main() { s.Run() } + +func getDbPath() (string, error) { + xch := os.Getenv("XDG_CONFIG_HOME") + if xch == "" { + home := os.Getenv("HOME") + xch = filepath.Join(home, ".config") + } + + scrobblerHome := filepath.Join(xch, "mpd-scrobbler") + if _, err := os.Stat(scrobblerHome); os.IsNotExist(err) { + if err := os.Mkdir(scrobblerHome, 0755); err != nil { + return "", err + } + } + + return filepath.Join(scrobblerHome, "scrobbler.sql"), nil +} -- cgit v1.2.3