This is a Go package for accessing Music Player Daemon (MPD).
Old repository: https://code.google.com/p/gompd/
How to install:
$ go get github.com/fhs/gompd/v2/mpd
Documentation can be found here: http://godoc.org/github.com/fhs/gompd/v2/mpd
Client side library for MPD (Music Player Daemon) for Go Programming Language.
License: MIT License
This is a Go package for accessing Music Player Daemon (MPD).
Old repository: https://code.google.com/p/gompd/
How to install:
$ go get github.com/fhs/gompd/v2/mpd
Documentation can be found here: http://godoc.org/github.com/fhs/gompd/v2/mpd
Currently in my go.mod
, this module displays as github.com/fhs/gompd v2.0.0+incompatible
. I search this up and found that this is supposed to happen when:
If a repository has not opted in to modules but has been tagged with valid semver tags, meanwhile, it's a v2+ module
I am using Golang version 1.13.
On a related note, for some reason I am also not getting the most recent version of this library when I use modules, which I believe may be due to this? When I delete my go.mod
and go.sum
my change in #48 is expressed, but when I make it a module suddenly the bug it fixes appears. Any idea on how to avoid this?
Experimenting with some encoded URLs (using gompd v2.3.0 tag) I found that addid
was breaking the URLs it sends to MPD while add
was not.
After some digging I found that the way Attrs()
passes the command to cmd.client.cmd
is different to the way OK()
does it.
Ultimately, this results in printfLine
trying to handle escaped characters in URLs as Go string formatting directives and complaining that they're missing in the final formatted string.
Example of problem URL before fix: https://...?text=Sorry%!C(MISSING)+I+couldn%!t(MISSING)+understand+that
An example of a problem URL after fix: https://...?text=Sorry%2C+I+couldn%27t+understand+that
The fix appears to be, to call cmd.client.cmd
the same way it is called elsewhere:
diff --git a/mpd/response.go b/mpd/response.go
index 3f1505b..5289fea 100644
--- a/mpd/response.go
+++ b/mpd/response.go
@@ -53,7 +53,7 @@ func (cmd *Command) OK() error {
// Attrs sends command to server and reads attributes returned in response.
func (cmd *Command) Attrs() (Attrs, error) {
- id, err := cmd.client.cmd(cmd.cmd)
+ id, err := cmd.client.cmd("%v", cmd.cmd)
if err != nil {
return nil, err
}
This isn't really an issue, but rather a question. I created a Client
when my program starts and was trying to reuse it after that. When my program doesn't send requests for some time and then tries to send one after that, I get read tcp [::1]:13364->[::1]:6600: read: connection reset by peer
or EOF
. Here is an example on how to reproduce the problem:
package main
import "github.com/fhs/gompd/mpd"
import "time"
func main() {
c, _ := mpd.Dial("tcp", "localhost:6600")
time.Sleep(time.Minute)
if err := c.Pause(true); err != nil {
panic(err)
}
}
Am I supposed to create a new Client
for every event that I create? If so: Would you take a pull request, where I document this, or do you think this is common knowledge?
The function quote()
in client.go
takes care of escaping double quotes while enclosing the passed string in double quotes.
According to MPD's docs on escaping, the following characters must be escaped too:
Especially the fact that backslash doesn't get escaped makes it difficult to implement escaping outside of this function.
Thank you for this project. As I want to package d'Uss for Debian which requires a never version than 2.2.0 and as the last release is already two years old I'd like to ask if it's possible to create a new release?
This is a problem since mpd 0.18 - Affected commands are "command_list_begin" and "command_list_ok_begin".
See bug report: http://bugs.musicpd.org/view.php?id=3854
Commands must end with LF only. Unfortunately, textproto appends CRLF, when using Cmd()
or PrintfLine()
.
I recently had trouble using the Client.Update or AddId methods with a file named:
"04 - ILL - DECAYED LOVE feat.℃iel.ogg"
gompd received a message from mpd saying the file didn't exist, even though other files in the same directory were fine, and even though I was able to add this file at the command line with mpc using my shell's autocomplete feature.
I noticed in the source of the library that that all file parameters are sent into a format string as a %q value. If I print the above song title using:
log.Printf("%q\n", "04 - ILL - DECAYED LOVE feat.℃iel.ogg")
It expands to:
2013/10/07 23:40:00 "04 - ILL - DECAYED LOVE\u3000feat.℃iel.ogg"
Note the \u3000 for the full-width space. is this being sent literally to mpd? I was able to work around this issue on my end by using strings.Map to convert all unicode spaces to the normal ASCII space character in the file name before working with it, but the library seems to have problems with the full-width space unless I'm mistaken.
There's currently no function for the rescan
command in gompd:
rescan [URI]
Same as update, but also rescans unmodified files.
There's currently no function for the listfiles
mpd command.
listfiles {URI}
Lists the contents of the directory URI, including files are not recognized by MPD. URI can be a path relative to the music directory or an URI understood by one of the storage plugins. The response contains at least one line for each directory entry with the prefix “file: ” or “directory: “, and may be followed by file attributes such as “Last-Modified” and “size”.
The only way to list files from MPD's database is to use the GetFiles()
function that retrieves the entire file list at once. When the list is large this may introduce a performance penalty.
it would be great if this package supported client-to-client channels. i haven't looked at this package in too much detail yet, so i don't know how difficult this would be to implement.
Mpd has a feature called partitions. A partition is one frontend of a multi-player MPD process: it has separate queue, player and outputs. A client is assigned to one partition at a time.
https://www.musicpd.org/doc/html/protocol.html#partition-commands
Following should be added to client.go
//Partition commands
// Partition Switches the client to a different partition.
func (c *Client) Partition(name string) error {
return c.Command("partition %s", name).OK()
}
// ListPartitions Print a list of partitions and their information.
func (c *Client) ListPartitions() ([]Attrs, error) {
return c.Command("listpartitions").AttrsList("partition")
}
// NewPartition creates a new partition with the given name.
func (c *Client) NewPartition(name string) error {
return c.Command("newpartition %s", name).OK()
}
// DelPartition deletes partition with the given name.
func (c *Client) DelPartition(name string) error {
return c.Command("delpartition %s", name).OK()
}
// MoveOutput Move an output with the given name to the current partition.
func (c *Client) MoveOutput(name string) error {
return c.Command("moveoutput %s", name).OK()
}
I have added this in my local branch, but it is not yet fully tested, as my mpd version on my dev machine does not yet support this feature, and I am currently having issues with updating it to the most recent version.
Should I sent a pull request, when I have fully tested this?
Hey,
i had another idea to solve this problem.
Please checkout https://github.com/ushis/gompd/blob/watcher-experiments/mpd/watcher.go
What do you think?
It still blocks, if the caller doesn't read from the channels, but i think it's a matter of documentation. If you think thats a problem i would use buffered channels. It's way cleaner and the overhead is not that crazy.
Lines 8 to 9 in c269f23
contains unexported reference to Client
instance.
Now when I need both watcher for mpd's subsystem events and also retrieve current song information, I have to create another instance with DialAuthenticated, while there is already one.
Would it be possible to allow shared access to Watcher
's connection instance? I'm aware there can be a conflicting behavior, like closing from other party but such situations can happen by external causes anyway and connection instance should be handled in a defensive way in all cases.
See https://www.musicpd.org/doc/html/protocol.html#reflection
Available as of MPD 0.17 (released 2012-06-27). It allows to find out what the music directory is.
A.k.a. albumart
command.
Trying to call Find("artist "David Bowie"") threw ACK 2@0 too few args.
Removed quote function from client.go, and it works. (line 554: id, err := c.cmd("find " + quote(uri)) )
Is there a correct way to pass this argument through the quote function without having to bypass it? The quote function is beyond my comprehension.
Hi, congrats for the this lib.
I'm just new here and trying to find a way to handle the connection lost to MPD.
I'm doing some tests and when I kill MPD the client are killed too.
How to handle it?
Thank you.
Hello!
As of MPD version 0.22 embedded cover art is served by MPD with the readpicture
binary command.
Official support for this would be ideal
Many thanks!
From #22.
The last comment mentions using an interface in the old pull request. I liked the idea and I want to implement it.
Here's how I'm imagining it would look like:
// Reactor represents an MPD connection that reacts to events.
type Reactor struct{ ... }
// NewReactor connects to MPD and reacts to events. Set handlers and other options
// by passing ReactorOptions.
func NewReactor(network, addr, password string, options ...ReactorOption) *Reactor
// Subsystems restricts subsystems watched for.
func (r *Reactor) Subsystems(subsystems ...string)
// Interrupt stops watching for event temporarily and runs the interrupt handler with args.
func (r *Reactor) Interrupt(args ...interface{})
// ReactorOption
type ReactorOption func(r *Reactor)
// ReactorSubsystems restricts the subsystems watched for.
func ReactorSubsystems(subsystems ...string) ReactorOption
// ReactorEventHandler is run for each change in MPD. The first argument is the subsystem
// that changed. See the list of subsystems:
// https://mpd.readthedocs.io/en/stable/protocol.html#command-idle
func ReactorEventHandler(f func(c *Client, subsystem string)) ReactorOption
func ReactorErrorHandler(f func(c *Client, err error)) ReactorOption
func ReactorInterruptHandler(f func(c *Client, args ...interface{})) ReactorOption
Instead of an interface, this uses the functional options pattern. This makes the API easier to use and makes any or all functionality optional.
This also adds an interrupt system, which allows using Client
for external events. Interrupt will simply call noidle
and send args
on a channel.
We could also add ReactorOption
s that send on a channel, so Watcher
could be implemented in terms of Reactor
.
Hello! Been playing with this package recently and it seems to work rather well. The API is nice too, but my one complaint is that since everything is a map[string]string
, it requires manual parsing to deal with types such as integers, or compound fields such as audio
(ex: 44100:16:2
).
To remedy this issue, I've been working on: https://github.com/mdlayher/mpdx.
As stated, package mpdx
is an extension of package mpd
. I built it to nicely wrap some of the functions provided by this package. It returns struct
types with standard field names and types.
Is this functionality something you'd be interested in merging into your package? If not, I'm happy to maintain mpdx
as an extension to this package. Let me know!
The test seems to sometimes hang during tear-down (closing the Watcher).
=== RUN TestWatcher
panic: test timed out after 10m0s
goroutine 43 [running]:
testing.(*M).startAlarm.func1()
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:1460 +0x11c
created by time.goFunc
/opt/hostedtoolcache/go/1.14.1/x64/src/time/sleep.go:168 +0x52
goroutine 1 [chan receive]:
testing.(*T).Run(0xc0000a4000, 0x6a38fc, 0xb, 0x6ae2f8, 0x1)
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:1044 +0x699
testing.runTests.func1(0xc0000a4000)
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:1285 +0xa7
testing.tRunner(0xc0000a4000, 0xc00007dd50)
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:992 +0x1ec
testing.runTests(0xc00000e080, 0x84aee0, 0x13, 0x13, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:1283 +0x528
testing.(*M).Run(0xc0000a0000, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:1200 +0x300
main.main()
_testmain.go:80 +0x224
goroutine 56 [chan receive]:
github.com/fhs/gompd/v2/mpd.(*Watcher).Close(0xc00015d8f0, 0x833120, 0xc000001980)
/home/runner/work/gompd/gompd/mpd/watcher.go:115 +0xbe
github.com/fhs/gompd/v2/mpd.TestWatcher(0xc00016aea0)
/home/runner/work/gompd/gompd/mpd/watcher_test.go:91 +0x97d
testing.tRunner(0xc00016aea0, 0x6ae2f8)
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:992 +0x1ec
created by testing.(*T).Run
/opt/hostedtoolcache/go/1.14.1/x64/src/testing/testing.go:1043 +0x661
goroutine 7 [IO wait]:
internal/poll.runtime_pollWait(0x7fb530cbbfa8, 0x72, 0x72)
/opt/hostedtoolcache/go/1.14.1/x64/src/runtime/netpoll.go:203 +0x55
internal/poll.(*pollDesc).wait(0xc000106018, 0x72, 0x0, 0x0, 0x6a291a)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:87 +0xe4
internal/poll.(*pollDesc).waitRead(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc000106000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_unix.go:384 +0x2c9
net.(*netFD).accept(0xc000106000, 0xc00010a100, 0x6e40c0, 0x6e40a0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/fd_unix.go:238 +0x56
net.(*TCPListener).accept(0xc00011e000, 0xc00010a100, 0xc000198000, 0x1000)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/tcpsock_posix.go:139 +0x50
net.(*TCPListener).Accept(0xc00011e000, 0x6ae310, 0xc000126000, 0xc00013abd0, 0xc00010a100)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/tcpsock.go:261 +0x50
github.com/fhs/gompd/v2/mpd/internal/server.Listen(0x6a20db, 0x3, 0x6a43e9, 0xe, 0xc0000662a0)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:899 +0x160
created by github.com/fhs/gompd/v2/mpd.localDial
/home/runner/work/gompd/gompd/mpd/client_test.go:44 +0x26b
goroutine 18 [select]:
github.com/fhs/gompd/v2/mpd/internal/server.(*server).broadcastIdleEvents(0xc000126000)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:852 +0x4a9
created by github.com/fhs/gompd/v2/mpd/internal/server.Listen
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:896 +0x12c
goroutine 58 [IO wait]:
internal/poll.runtime_pollWait(0x7fb530cbbc28, 0x72, 0x6e43e0)
/opt/hostedtoolcache/go/1.14.1/x64/src/runtime/netpoll.go:203 +0x55
internal/poll.(*pollDesc).wait(0xc000107498, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:87 +0xe4
internal/poll.(*pollDesc).waitRead(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000107480, 0xc000198000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_unix.go:169 +0x253
net.(*netFD).Read(0xc000107480, 0xc000198000, 0x1000, 0x1000, 0x1d, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/fd_unix.go:202 +0x66
net.(*conn).Read(0xc00010a100, 0xc000198000, 0x1000, 0x1000, 0x1d, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/net.go:184 +0xa1
bufio.(*Reader).fill(0xc00010c9c0)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:100 +0x19a
bufio.(*Reader).ReadSlice(0xc00010c9c0, 0x47a70a, 0xc00011ee80, 0xc000041d10, 0x47a90f, 0xc000139540, 0xc000041d70)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:359 +0x96
bufio.(*Reader).ReadLine(0xc00010c9c0, 0x61d1a0, 0xc000139580, 0xc000036a80, 0x2, 0x7fb55a0687d0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:388 +0x45
net/textproto.(*Reader).readLineSlice(0xc00013abd0, 0x473427, 0x412630, 0x7fb52c011238, 0xc00013ac18, 0x473427)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/textproto/reader.go:58 +0x9e
net/textproto.(*Reader).ReadLine(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/textproto/reader.go:39
github.com/fhs/gompd/v2/mpd/internal/server.(*server).readRequest(0xc000126000, 0xc00013abd0, 0xc000126000, 0xc00013abd0, 0x5)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:684 +0x53
github.com/fhs/gompd/v2/mpd/internal/server.(*server).handleConnection(0xc000126000, 0xc00013abd0)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:767 +0x1e1
created by github.com/fhs/gompd/v2/mpd/internal/server.Listen
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:904 +0x241
goroutine 57 [IO wait]:
internal/poll.runtime_pollWait(0x7fb530cbbd08, 0x72, 0x6e43e0)
/opt/hostedtoolcache/go/1.14.1/x64/src/runtime/netpoll.go:203 +0x55
internal/poll.(*pollDesc).wait(0xc000107298, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:87 +0xe4
internal/poll.(*pollDesc).waitRead(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000107280, 0xc00018c000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_unix.go:169 +0x253
net.(*netFD).Read(0xc000107280, 0xc00018c000, 0x1000, 0x1000, 0x9, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/fd_unix.go:202 +0x66
net.(*conn).Read(0xc00010a0f0, 0xc00018c000, 0x1000, 0x1000, 0x9, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/net.go:184 +0xa1
bufio.(*Reader).fill(0xc00010c900)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:100 +0x19a
bufio.(*Reader).ReadSlice(0xc00010c900, 0x47a70a, 0xc0000e2060, 0xc000165d10, 0x47a90f, 0xc00000ec00, 0xc000165d70)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:359 +0x96
bufio.(*Reader).ReadLine(0xc00010c900, 0x61d1a0, 0xc000013c40, 0xc000036700, 0x1, 0x7fb55a068108, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:388 +0x45
net/textproto.(*Reader).readLineSlice(0xc00013aab0, 0x473427, 0x412630, 0x7fb52c031038, 0xc00013ab10, 0x473427)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/textproto/reader.go:58 +0x9e
net/textproto.(*Reader).ReadLine(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/textproto/reader.go:39
github.com/fhs/gompd/v2/mpd/internal/server.(*server).readRequest(0xc000126000, 0xc00013aab0, 0xc00000ec00, 0x2, 0x2)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:684 +0x53
github.com/fhs/gompd/v2/mpd/internal/server.(*server).handleConnection(0xc000126000, 0xc00013aab0)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:767 +0x1e1
created by github.com/fhs/gompd/v2/mpd/internal/server.Listen
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:904 +0x241
goroutine 59 [IO wait]:
internal/poll.runtime_pollWait(0x7fb530cbbde8, 0x72, 0x6e43e0)
/opt/hostedtoolcache/go/1.14.1/x64/src/runtime/netpoll.go:203 +0x55
internal/poll.(*pollDesc).wait(0xc000107418, 0x72, 0x1000, 0x1000, 0xffffffffffffffff)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:87 +0xe4
internal/poll.(*pollDesc).waitRead(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000107400, 0xc000196000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/internal/poll/fd_unix.go:169 +0x253
net.(*netFD).Read(0xc000107400, 0xc000196000, 0x1000, 0x1000, 0xc000042800, 0xc0000428e8, 0x4ca88c)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/fd_unix.go:202 +0x66
net.(*conn).Read(0xc00010a0f8, 0xc000196000, 0x1000, 0x1000, 0x0, 0xc000042bc8, 0x0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/net.go:184 +0xa1
bufio.(*Reader).fill(0xc00010c960)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:100 +0x19a
bufio.(*Reader).ReadSlice(0xc00010c960, 0xa, 0xc000153ba0, 0x9, 0xc000153ba0, 0x9, 0x9)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:359 +0x96
bufio.(*Reader).ReadLine(0xc00010c960, 0x9, 0x2, 0x1, 0x2, 0xc000153ba0, 0xc000153ba7)
/opt/hostedtoolcache/go/1.14.1/x64/src/bufio/bufio.go:388 +0x45
net/textproto.(*Reader).readLineSlice(0xc00013ab40, 0x6a2936, 0x7, 0x6a1f87, 0x2, 0xc000153ba0)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/textproto/reader.go:58 +0x9e
net/textproto.(*Reader).ReadLine(...)
/opt/hostedtoolcache/go/1.14.1/x64/src/net/textproto/reader.go:39
github.com/fhs/gompd/v2/mpd.(*Client).readList(0xc00011ed00, 0x6a2936, 0x7, 0x0, 0x0, 0x0, 0x4, 0x0)
/home/runner/work/gompd/gompd/mpd/client.go:163 +0xe9
github.com/fhs/gompd/v2/mpd.(*Command).Strings(0xc00000ec20, 0x6a2936, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0)
/home/runner/work/gompd/gompd/mpd/response.go:86 +0x1fc
github.com/fhs/gompd/v2/mpd.(*Client).idle(0xc00011ed00, 0xc00011ede0, 0x2, 0x2, 0xc0000e2000, 0x1, 0x1, 0x0, 0x0)
/home/runner/work/gompd/gompd/mpd/client.go:284 +0x10d
github.com/fhs/gompd/v2/mpd.(*Watcher).watch(0xc00015d8f0, 0xc000105b00, 0x2, 0x2)
/home/runner/work/gompd/gompd/mpd/watcher.go:46 +0x335
created by github.com/fhs/gompd/v2/mpd.NewWatcher
/home/runner/work/gompd/gompd/mpd/watcher.go:36 +0x300
goroutine 62 [select]:
github.com/fhs/gompd/v2/mpd/internal/server.(*server).writeIdleResponse(0xc000126000, 0xc00013abd0, 0x5, 0xc000124e40, 0xc000139550, 0x2, 0x3)
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:742 +0x320
created by github.com/fhs/gompd/v2/mpd/internal/server.(*server).handleConnection
/home/runner/work/gompd/gompd/mpd/internal/server/server.go:780 +0x2e3
FAIL github.com/fhs/gompd/v2/mpd 600.013s
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.