日常生活中,我们都是使用网易云音乐之类的音乐软件听歌,但是你有没有想过,作为程序员,该如何使用命令行来听(zhuang)歌(bi)呢?今天就让我们来实现这个功能吧。
写代码,一般需要搞清楚三点,输入,输出和算法。如果使用命令行听歌,输入很明确,肯定是音频数据流,数据一般可以通过网上获取,那么输出呢,肯定就是我们耳朵中听到的声音,这两点都比较简单。关键是处理数据和输出数据的算法,之前并没有怎么搞过音乐格式编码和解码之类的东西,不过不要慌,已经有强大的 mpg123
这个命令行工具帮我们搞定这类事情了。
mpg123
需要额外安装,macOS
用户可以使用 homebrew
进行安装。mpg123
可以帮助我们处理 MPEG 1.0/2.0/2.5
格式的数据流,并使用系统默认的音屏设备播放。
1 | $ mpg123 [ options ] file-or-URL... |
上面是它的简单使用,[options]
代表额外选项,真正的参数可以是本地音频文件地址或者 URL
地址。一般来说 file/URL
都需要是 MPEG
格式的音频比特流( audio bit stream
)。
问题的关键解决之后,下面就可以利用它写一个简单的音乐播放器了,这里播放器具有两种状态,Stopped
和 Playing
,播放器的核心操作依赖 mpg123
实现,exec.Cmd
用于代表这个命令。除此之外,还需要指定输入和输出,输入( io.ReadCloser
)可以来自 HTTP
得到的数据流,而输出( io.WriteCloser
)则是该命令的输入管道。
1 | type State int |
因为播放音乐需要 mpg123
这个依赖,所以,在程序运行时需要检查其是否存在,exec.LookPath
会在系统路径( $PATH
)下面寻找,如果不存在,则返回 error
。
1 | func NewPlayer() (*Player, error) { |
使用命令行听歌的关键还是在于对数据流的处理,通过 io.Copy
方法将数据流进行重定向。
1 | func stream(dst io.WriteCloser, src io.ReadCloser) { |
因为 mpg123
需要读取音频数据流,在构造命令时,我们使用 -
来指定mpg123
从标准输入中获取数据( exec.Command("mpg123", "-q", "-")
),通过 StdinPipe()
方法可以获得连接到此命令的标准输入管道。输入的数据流可以利用 http.Get
获取,然后再利用上述 stream
方法将数据流重定向到 mpg123
的标准输入( stdin
)中去,这样就可以实现音乐播放了。
1 | func (p *Player) Play(URL string) (err error) { |
一个音乐播放器自然少不了暂停操作。因为输入和输出分别是 io.ReadCloser
和 io.WriteCloser
类型,所以都可以调用 Close
方法来将它们关闭。除此之外还需要将对应的 mpg123
的进程停掉( p.mpg123.Process.Kill()
)。
1 | func (p *Player) Stop() { |
剩下最后一个问题就是如何获取各大平台音乐的链接地址,下面给获取网易云音乐歌曲外链地址的方法,这里的参数 id
表示音乐的 id
,其他平台获取方法也应该类似,感兴趣的读者可以自行寻找。
1 | func getMusicLink(id int) string { |