Use List to display library

This commit is contained in:
Trevor Slocum 2020-04-24 15:39:02 -07:00
parent aafe81b48b
commit 7ea726e453
9 changed files with 258 additions and 415 deletions

View file

@ -1,5 +1,4 @@
# ditty
[![GoDoc](https://godoc.org/gitlab.com/tslocum/ditty?status.svg)](https://godoc.org/gitlab.com/tslocum/ditty)
[![CI status](https://gitlab.com/tslocum/ditty/badges/master/pipeline.svg)](https://gitlab.com/tslocum/ditty/commits/master)
[![Donate](https://img.shields.io/liberapay/receives/rocketnine.space.svg?logo=liberapay)](https://liberapay.com/rocketnine.space)
@ -13,7 +12,7 @@ Audio player
If you are running Linux with ALSA, you can try ditty without installing:
```ssh ditty.rocketnine.space -p 20020 2> >(aplay --quiet)```
```ssh -q ditty.rocketnine.space -p 20020 2> >(aplay --quiet)```
If you can't hear anything, you may need to specify which device ```aplay```
should use with ```-D```.

View file

@ -186,7 +186,7 @@ func pause() {
}
func nextTrack() {
if queueCursor < len(queueFiles)-1 {
if queueList.GetCurrentItem() < len(queueFiles)-1 {
queueNext()
entry := selectedQueueEntry()

16
go.mod
View file

@ -3,20 +3,20 @@ module gitlab.com/tslocum/ditty
go 1.13
require (
github.com/dhowden/tag v0.0.0-20191122115059-7e5c04feccd8
github.com/dhowden/tag v0.0.0-20200412032933-5d76b8eaae27
github.com/faiface/beep v1.0.2
github.com/gdamore/tcell v1.3.0
github.com/hajimehoshi/go-mp3 v0.2.1 // indirect
github.com/hajimehoshi/oto v0.5.4 // indirect
github.com/hajimehoshi/oto v0.6.1 // indirect
github.com/jfreymuth/oggvorbis v1.0.1 // indirect
github.com/mattn/go-runewidth v0.0.8
github.com/mattn/go-runewidth v0.0.9
github.com/mewkiz/flac v1.0.6 // indirect
github.com/mewkiz/pkg v0.0.0-20200411195739-f6b5e26764c3 // indirect
github.com/pkg/errors v0.9.1 // indirect
gitlab.com/tslocum/cbind v0.1.0
gitlab.com/tslocum/cview v1.4.2-0.20200128151041-339db80f666d
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a // indirect
gitlab.com/tslocum/cbind v0.1.1
gitlab.com/tslocum/cview v1.4.5-0.20200424220521-e97629839eba
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
golang.org/x/mobile v0.0.0-20200123024942-82c397c4c527 // indirect
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 // indirect
gopkg.in/yaml.v2 v2.2.8
)

47
go.sum
View file

@ -2,8 +2,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/dhowden/tag v0.0.0-20191122115059-7e5c04feccd8 h1:nmFnmD8VZXkjDHIb1Gnfz50cgzUvGN72zLjPRXBW/hU=
github.com/dhowden/tag v0.0.0-20191122115059-7e5c04feccd8/go.mod h1:SniNVYuaD1jmdEEvi+7ywb1QFR7agjeTdGKyFb0p7Rw=
github.com/dhowden/tag v0.0.0-20200412032933-5d76b8eaae27 h1:Z6xaGRBbqfLR797upHuzQ6w4zg33BLKfAKtVCcmMDgg=
github.com/dhowden/tag v0.0.0-20200412032933-5d76b8eaae27/go.mod h1:SniNVYuaD1jmdEEvi+7ywb1QFR7agjeTdGKyFb0p7Rw=
github.com/faiface/beep v1.0.2 h1:UB5DiRNmA4erfUYnHbgU4UB6DlBOrsdEFRtcc8sCkdQ=
github.com/faiface/beep v1.0.2/go.mod h1:1yLb5yRdHMsovYYWVqYLioXkVuziCSITW1oarTeduQM=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
@ -14,7 +14,7 @@ github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebK
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20180825215210-0210a2f0f73c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherwasm v0.1.1/go.mod h1:kx4n9a+MzHH0BJJhvlsQ65hqLFXDO/m256AsaDPQ+/4=
@ -25,8 +25,8 @@ github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAe
github.com/hajimehoshi/oto v0.1.1/go.mod h1:hUiLWeBQnbDu4pZsAhOnGqMI1ZGibS6e2qhQdfpwz04=
github.com/hajimehoshi/oto v0.3.1/go.mod h1:e9eTLBB9iZto045HLbzfHJIc+jP3xaKrjZTghvb6fdM=
github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA=
github.com/hajimehoshi/oto v0.5.4 h1:Dn+WcYeF310xqStKm0tnvoruYUV5Sce8+sfUaIvWGkE=
github.com/hajimehoshi/oto v0.5.4/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/hajimehoshi/oto v0.6.1 h1:7cJz/zRQV4aJvMSSRqzN2TImoVVMpE0BCY4nrNJaDOM=
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/icza/bitio v1.0.0 h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8=
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
@ -41,33 +41,32 @@ github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9-0.20200125155203-588506649b41 h1:AkInqmD1OrueaAKIWH0RWU+irX4nL1oqScB++w2CAlU=
github.com/mattn/go-runewidth v0.0.9-0.20200125155203-588506649b41/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mewkiz/flac v1.0.5/go.mod h1:EHZNU32dMF6alpurYyKHDLYpW1lYpBZ5WrXi/VuNIGs=
github.com/mewkiz/flac v1.0.6 h1:OnMwCWZPAnjDndjEzLynOZ71Y2U+/QYHoVI4JEKgKkk=
github.com/mewkiz/flac v1.0.6/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2 h1:EyTNMdePWaoWsRSGQnXiSoQu0r6RS1eA557AwJhlzHU=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
github.com/mewkiz/pkg v0.0.0-20200411195739-f6b5e26764c3 h1:gVKRsSn2rXZ29y56Xrl+vtw8mpowYz9UmoPJM+V/g5s=
github.com/mewkiz/pkg v0.0.0-20200411195739-f6b5e26764c3/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
gitlab.com/tslocum/cbind v0.1.0 h1:Ot6y7K6mwp7Qp/MWOH5cuhf/VC5HKpJaWFvgzMC8nnM=
gitlab.com/tslocum/cbind v0.1.0/go.mod h1:xxuB0UqPYytWTkjI0l2VzOJJzqvIUf18r6YahPXYDd8=
gitlab.com/tslocum/cview v1.4.2-0.20200128151041-339db80f666d h1:5rPwwmNYGLcOsyawvAw7m/Jtwp5rAuvLoqVW5k09AP0=
gitlab.com/tslocum/cview v1.4.2-0.20200128151041-339db80f666d/go.mod h1:QbxliYQa2I32UJH2boP54jq6tnWlgm6yViaFXKGDfuM=
gitlab.com/tslocum/cbind v0.1.1 h1:JXXtxMWHgWLvoF+QkrvcNvOQ59juy7OE1RhT7hZfdt0=
gitlab.com/tslocum/cbind v0.1.1/go.mod h1:rX7vkl0pUSg/yy427MmD1FZAf99S7WwpUlxF/qTpPqk=
gitlab.com/tslocum/cview v1.4.5-0.20200424220521-e97629839eba h1:DYq4lsxeUfkR6VYGwzWcRNJWLCgjpklNZt4HfESnyLA=
gitlab.com/tslocum/cview v1.4.5-0.20200424220521-e97629839eba/go.mod h1:85Ec3ByMemrI3tUK4Rpd8jcF3J7maOFHGwzlNnCrPVI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20180710024300-14dda7b62fcd/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a h1:7Wlg8L54In96HTWOaI4sreLJ6qfyGuvSau5el3fK41Y=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
@ -78,10 +77,11 @@ golang.org/x/mobile v0.0.0-20180806140643-507816974b79/go.mod h1:z+o9i4GpDbdi3rU
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mobile v0.0.0-20200123024942-82c397c4c527 h1:470B1IvA7JOANiTULBeEJCIcp53VWOsgckscR836cN8=
golang.org/x/mobile v0.0.0-20200123024942-82c397c4c527/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 h1:JxsyO7zPDWn1rBZW8FV5RFwCKqYeXnyaS/VQPLpXu6I=
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@ -94,19 +94,18 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200103143344-a1369afcdac7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=

291
gui.go
View file

@ -20,26 +20,21 @@ import (
var (
app *cview.Application
mainbuf *cview.TextView
queuebuf *cview.TextView
mainList *cview.List
queueList *cview.List
topstatusbuf *cview.TextView
bottomstatusbuf *cview.TextView
mainBufferFiles []*libraryEntry
mainBufferCursor = 1 // Position cursor on first entry
mainBufferDirectory string
mainBufferOrigin int
mainBufHeight int
mainBufferAutoFocus string // Entry path to focus after loading display
mainFiles []*libraryEntry
mainCursor = -1
mainDirectory string
mainAutoFocus string // Entry path to focus after loading display
mainBuffer bytes.Buffer
mainLock = new(sync.Mutex)
queueFiles []*libraryEntry
queueCursor int
queueDirectory string
queueOrigin int
queueHeight int
queueFiles []*libraryEntry
queueCursor = -1
queueBuffer bytes.Buffer
queueLock = new(sync.Mutex)
@ -57,62 +52,59 @@ var (
)
func initTUI() error {
/*cview.Styles.TitleColor = tcell.ColorDefault
cview.Styles.BorderColor = tcell.ColorDefault
cview.Styles.PrimaryTextColor = tcell.ColorDefault
cview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault*/
app = cview.NewApplication()
if !disableMouse {
app.EnableMouse()
app.EnableMouse(true)
}
app.SetInputCapture(inputConfig.Capture)
app.SetAfterResizeFunc(handleResize)
app.SetMouseCapture(handleMouse)
app.SetInputCapture(inputConfig.Capture)
app.SetBeforeFocusFunc(handleBeforeFocus)
grid := cview.NewGrid().SetRows(-2, -1, 1, 1).SetColumns(-1)
mainbuf = cview.NewTextView().SetDynamicColors(true).SetWrap(true).SetWordWrap(false)
queuebuf = cview.NewTextView().SetDynamicColors(true).SetWrap(true).SetWordWrap(false)
mainList = cview.NewList().ShowSecondaryText(false)
queueList = cview.NewList().ShowSecondaryText(false)
topstatusbuf = cview.NewTextView().SetWrap(false).SetWordWrap(false)
bottomstatusbuf = cview.NewTextView().SetWrap(false).SetWordWrap(false)
mainbuf.SetBorder(true).SetTitleAlign(cview.AlignLeft)
mainList.SetBorder(true).SetTitleAlign(cview.AlignLeft)
mainList.SetSelectedFunc(handleMainSelection)
queuebuf.SetBorder(true).SetTitleAlign(cview.AlignLeft).SetTitle(" Queue ")
queueList.SetBorder(true).SetTitleAlign(cview.AlignLeft).SetTitle(" Queue ")
setTextViewParameters(mainbuf)
setTextViewParameters(queuebuf)
setTextViewParameters(topstatusbuf)
setTextViewParameters(bottomstatusbuf)
grid.AddItem(mainbuf, 0, 0, 1, 1, 0, 0, false)
grid.AddItem(queuebuf, 1, 0, 1, 1, 0, 0, false)
grid.AddItem(mainList, 0, 0, 1, 1, 0, 0, false)
grid.AddItem(queueList, 1, 0, 1, 1, 0, 0, false)
grid.AddItem(topstatusbuf, 2, 0, 1, 1, 0, 0, false)
grid.AddItem(bottomstatusbuf, 3, 0, 1, 1, 0, 0, false)
mainbuf.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (i int, i2 int, i3 int, i4 int) {
mainBufHeight = height
return mainbuf.GetInnerRect()
})
queuebuf.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (i int, i2 int, i3 int, i4 int) {
queueHeight = height
return queuebuf.GetInnerRect()
})
app.SetRoot(grid, true)
app.SetRoot(grid, true).SetFocus(mainList)
return nil
}
func handleBeforeFocus(p cview.Primitive) bool {
return p == mainList || p == queueList
}
func browseFolder(browse string) {
var err error
browse, err = filepath.Abs(browse)
if err != nil {
return
}
if browse == mainBufferDirectory {
mainBufferAutoFocus = ""
if browse == mainDirectory {
mainAutoFocus = ""
return
}
if !strings.HasPrefix(browse, restrictLibrary) {
@ -126,27 +118,30 @@ func browseFolder(browse string) {
return
}
placeCursorAtTop := mainBufferCursor == 0
mainBufferFiles = scanFolder(browse)
if !placeCursorAtTop && len(mainBufferFiles) > 0 {
mainBufferCursor = 1
} else {
mainBufferCursor = 0
}
mainBufferOrigin = 0
mainList.SetTitle(" " + cview.Escape(runewidth.Truncate(mainDirectory, screenWidth-4, "...")) + "... ")
mainBufferDirectory = browse
if mainBufferAutoFocus != "" {
autoSelectAbs, err := filepath.Abs(mainBufferAutoFocus)
if err == nil && autoSelectAbs != mainBufferDirectory {
placeCursorAtTop := mainList.GetCurrentItem() == 0
mainFiles = scanFolder(browse)
if mainCursor == -1 {
if !placeCursorAtTop && len(mainFiles) > 0 {
mainCursor = 1
} else {
mainCursor = 0
}
}
mainDirectory = browse
if mainAutoFocus != "" {
autoSelectAbs, err := filepath.Abs(mainAutoFocus)
if err == nil && autoSelectAbs != mainDirectory {
autoSelect := -1
var entryPath string
for i, entry := range mainBufferFiles {
for i, entry := range mainFiles {
if !entry.File.IsDir() {
continue
}
entryPath, err = filepath.Abs(path.Join(mainBufferDirectory, entry.File.Name()))
entryPath, err = filepath.Abs(path.Join(mainDirectory, entry.File.Name()))
if err == nil {
if entryPath == autoSelectAbs {
autoSelect = i
@ -155,36 +150,18 @@ func browseFolder(browse string) {
}
}
if autoSelect >= 0 {
mainBufferCursor = autoSelect
mainBufferNewOrigin := (mainBufferCursor - (mainBufHeight - 4)) + ((mainBufHeight - 2) / 2)
if mainBufferNewOrigin <= 0 {
mainBufferNewOrigin = 0
} else if mainBufferNewOrigin > len(mainBufferFiles)-(mainBufHeight-3) {
mainBufferNewOrigin = len(mainBufferFiles) - (mainBufHeight - 3)
}
mainBufferOrigin = mainBufferNewOrigin
mainBufferAutoFocus = ""
go listNext()
return
mainCursor = autoSelect + 1
mainAutoFocus = ""
}
}
mainBufferAutoFocus = ""
mainAutoFocus = ""
}
go app.QueueUpdateDraw(updateMain)
}
func setTextViewParameters(tv *cview.TextView) {
tv.SetTitleColor(tcell.ColorDefault)
tv.SetBorderColor(tcell.ColorDefault)
tv.SetTextColor(tcell.ColorDefault)
tv.SetBackgroundColor(tcell.ColorDefault)
}
func browseParent() {
mainBufferAutoFocus = mainBufferDirectory
go browseFolder(path.Join(mainBufferDirectory, ".."))
mainAutoFocus = mainDirectory
go browseFolder(path.Join(mainDirectory, ".."))
}
func updateMain() {
@ -196,7 +173,7 @@ func updateMain() {
if statusText != "" {
statusMessage = statusText
} else {
statusMessage = mainBufferDirectory
statusMessage = mainDirectory
}
truncated := false
@ -216,69 +193,54 @@ func updateMain() {
}
mainBuffer.WriteString(statusMessage)
mainbuf.SetTitle(" " + cview.Escape(runewidth.Truncate(mainBuffer.String(), screenWidth-4, "...")) + " ")
mainList.SetTitle(" " + cview.Escape(runewidth.Truncate(mainBuffer.String(), screenWidth-4, "...")) + " ")
mainBuffer.Reset()
l := len(mainBufferFiles) + 1
if mainCursor == -1 {
mainCursor = mainList.GetCurrentItem()
}
mainList.Clear()
var printed int
var line string
if mainBufferOrigin == 0 {
writeListItemPrefix(&mainBuffer, !queueFocused, mainBufferCursor, 0)
//var length string
if mainBufferDirectory == "/" {
line = "./"
} else {
line = "../"
}
lineWidth := runewidth.StringWidth(line)
line = cview.Escape(line)
mainBuffer.WriteString(line)
writeListItemSuffix(&mainBuffer, !queueFocused, mainBufferCursor, 0, 0, l, lineWidth, mainBufHeight-2)
printed++
if mainDirectory == "/" {
line = "./"
} else {
line = "../"
}
for i, entry := range mainBufferFiles {
if i < mainBufferOrigin-1 || i-mainBufferOrigin-1 > mainBufHeight-1 {
continue
}
line = cview.Escape(line)
if printed > 0 {
mainBuffer.WriteRune('\n')
}
mainList.AddItem(line, "", 0, nil)
writeListItemPrefix(&mainBuffer, !queueFocused, mainBufferCursor-1, i)
printed++
for _, entry := range mainFiles {
//length = ""
if entry.File.IsDir() {
line = strings.TrimSpace(entry.File.Name()) + "/"
} else {
line = entry.String()
if entry.Metadata.Length > 0 {
//m := entry.Metadata.Length / time.Minute
//length = fmt.Sprintf(" %d:%02d", m, (entry.Metadata.Length%(m*time.Minute))/time.Second)
}
}
lineWidth := runewidth.StringWidth(line)
line = cview.Escape(line)
mainBuffer.WriteString(line)
writeListItemSuffix(&mainBuffer, !queueFocused, mainBufferCursor, printed, i+1, l, lineWidth, mainBufHeight-2)
printed++
if printed == mainBufHeight-2 {
break
}
}
remaining := (mainBufHeight - 2) - printed
for i := 0; i < remaining; i++ {
if printed > 0 {
mainBuffer.WriteRune('\n')
}
writeListItemSuffix(&mainBuffer, !queueFocused, mainBufferCursor, printed, remaining-printed, l, 0, mainBufHeight-2)
mainList.AddItem(line, "", 0, nil)
printed++
}
mainbuf.SetText(mainBuffer.String())
if mainCursor >= mainList.GetItemCount() {
mainList.SetCurrentItem(mainList.GetItemCount() - 1)
} else if mainCursor >= 0 {
mainList.SetCurrentItem(mainCursor)
}
mainCursor = -1
}
func updateQueue() {
@ -287,88 +249,33 @@ func updateQueue() {
queueBuffer.Reset()
l := len(queueFiles)
if queueCursor == -1 {
queueCursor = queueList.GetCurrentItem()
}
queueList.Clear()
var printed int
var line string
for i, entry := range queueFiles {
if i < queueOrigin || i-queueOrigin > queueHeight-1 {
continue
}
if printed > 0 {
queueBuffer.WriteRune('\n')
}
writeListItemPrefix(&queueBuffer, queueFocused, queueCursor, i)
//var length string
for _, entry := range queueFiles {
line = entry.String()
lineWidth := runewidth.StringWidth(line)
//lineWidth := runewidth.StringWidth(line)
line = cview.Escape(line)
queueBuffer.WriteString(line)
queueList.AddItem(line, "", 0, nil)
writeListItemSuffix(&queueBuffer, queueFocused, queueCursor, printed, i, l, lineWidth, queueHeight-2)
printed++
if printed == queueHeight-2 {
break
}
}
remaining := (queueHeight - 2) - printed
for i := 0; i < remaining; i++ {
if printed > 0 {
queueBuffer.WriteRune('\n')
}
writeListItemSuffix(&queueBuffer, queueFocused, queueCursor, printed, remaining-printed, l, 0, queueHeight-2)
/*m := entry.Metadata.Length / time.Minute
length = fmt.Sprintf(" %d:%02d", m, (entry.Metadata.Length%(m*time.Minute))/time.Second)*/
printed++
}
queuebuf.SetText(queueBuffer.String())
}
func writeListItemPrefix(buffer *bytes.Buffer, focused bool, cursor int, i int) {
if focused {
if i == cursor {
buffer.WriteString("[::r]")
}
} else {
if i == cursor {
buffer.WriteString("[::bu]")
}
}
}
func writeListItemSuffix(buffer *bytes.Buffer, focused bool, cursor int, printed int, i int, count int, lineWidth int, height int) {
if !focused && i == cursor {
buffer.WriteString("[-:-:-]")
}
for i := lineWidth; i < screenWidth-3; i++ {
buffer.WriteRune(' ')
}
if focused && i == cursor {
buffer.WriteString("[-:-:-]")
}
scrollBlockPos := int(float64(height-1) * (float64(cursor) / float64(count-1)))
if focused {
if printed == scrollBlockPos {
buffer.WriteString("[::r]")
buffer.WriteRune(' ')
buffer.WriteString("[-:-:-]")
} else {
buffer.WriteRune('▒')
}
} else {
if printed == scrollBlockPos {
buffer.WriteRune('▓')
} else {
buffer.WriteRune('░')
}
if queueCursor >= queueList.GetItemCount() {
queueList.SetCurrentItem(queueList.GetItemCount() - 1)
} else if queueCursor >= 0 {
queueList.SetCurrentItem(queueCursor)
}
queueCursor = -1
}
func updateLists() {
@ -535,3 +442,7 @@ func handleResize(width int, height int) {
updateQueue()
updateStatus()
}
func handleMainSelection(i int, s string, s2 string, r rune) {
go listSelect(i)
}

View file

@ -30,7 +30,7 @@ const (
)
var actionHandlers = map[string]func(){
actionSelect: listSelect,
actionSelect: listSelectCurrent,
actionPause: pause,
actionRefresh: listRefresh,
actionQueue: listQueue,

View file

@ -3,6 +3,8 @@ package main
import (
"path"
"time"
"gitlab.com/tslocum/cview"
)
func listPrevious() {
@ -11,12 +13,7 @@ func listPrevious() {
return
}
if mainBufferOrigin > 0 && mainBufferCursor == mainBufferOrigin {
mainBufferOrigin--
}
if mainBufferCursor > 0 {
mainBufferCursor--
}
mainList.Transform(cview.TransformPreviousItem)
go app.QueueUpdateDraw(updateLists)
}
@ -26,53 +23,40 @@ func listNext() {
return
}
if mainBufferCursor < len(mainBufferFiles) {
mainBufferCursor++
if mainBufferCursor-mainBufferOrigin > mainBufHeight-3 {
mainBufferOrigin++
}
}
mainList.Transform(cview.TransformNextItem)
go app.QueueUpdateDraw(updateLists)
}
func queuePrevious() {
if queueOrigin > 0 && queueCursor == queueOrigin {
queueOrigin--
}
if queueCursor > 0 {
queueCursor--
}
queueList.Transform(cview.TransformPreviousItem)
go app.QueueUpdateDraw(updateQueue)
}
func queueNext() {
if queueCursor < len(queueFiles)-1 {
queueCursor++
queueOrigin = queueCursor - ((queueHeight - 3) / 2)
if queueOrigin < 0 {
queueOrigin = 0
}
if queueOrigin > (len(queueFiles)-1)-(queueHeight-3) {
queueOrigin = (len(queueFiles) - 1) - (queueHeight - 3)
}
}
queueList.Transform(cview.TransformNextItem)
go app.QueueUpdateDraw(updateQueue)
}
func listSelect() {
func listSelectCurrent() {
go listSelect(mainList.GetCurrentItem())
}
func listSelect(cursor int) {
if queueFocused {
queueSelect()
return
}
if mainBufferCursor == 0 {
browseFolder(path.Join(mainBufferDirectory, ".."))
if cursor == 0 {
browseFolder(path.Join(mainDirectory, ".."))
return
}
entry := selectedMainEntry()
if cursor < 0 || cursor-1 > len(mainFiles) {
return
}
entry := mainFiles[cursor-1]
if entry.File.IsDir() {
browseFolder(entry.Path)
return
@ -118,7 +102,7 @@ func queueSelect() {
}
func listQueue() {
if mainBufferCursor == 0 {
if mainList.GetCurrentItem() == 0 {
// TODO Show error
return
}
@ -159,120 +143,77 @@ func listDelete() {
queueLock.Lock()
defer queueLock.Unlock()
if len(queueFiles) <= queueCursor {
cursor := queueList.GetCurrentItem()
if cursor < 0 || len(queueFiles) <= cursor {
return
}
queueFiles = append(queueFiles[:queueCursor], queueFiles[queueCursor+1:]...)
if queueCursor > len(queueFiles)-1 {
queueCursor = len(queueFiles) - 1
if queueCursor < 0 {
queueCursor = 0
}
}
queueFiles = append(queueFiles[:cursor], queueFiles[cursor+1:]...)
go app.QueueUpdateDraw(updateQueue)
}
func selectedMainEntry() *libraryEntry {
return mainBufferFiles[mainBufferCursor-1]
cursor := mainList.GetCurrentItem()
if cursor < 0 || cursor-1 > len(mainFiles) {
return nil
}
return mainFiles[cursor-1]
}
func offsetMainEntry(offset int) *libraryEntry {
if (mainBufferCursor-1)+offset < 0 || (mainBufferCursor-1)+offset >= len(mainBufferFiles) {
cursor := mainList.GetCurrentItem()
if (cursor-1)+offset < 0 || (cursor-1)+offset >= len(mainFiles) {
return nil
}
return mainBufferFiles[(mainBufferCursor-1)+offset]
return mainFiles[(cursor-1)+offset]
}
func selectedQueueEntry() *libraryEntry {
return queueFiles[queueCursor]
cursor := queueList.GetCurrentItem()
if cursor < 0 || cursor-1 > len(queueFiles) {
return nil
}
return queueFiles[cursor]
}
func offsetQueueEntry(offset int) *libraryEntry {
if queueCursor+offset < 0 || queueCursor+offset >= len(queueFiles) {
cursor := queueList.GetCurrentItem()
if cursor+offset < 0 || cursor+offset >= len(queueFiles) {
return nil
}
return queueFiles[queueCursor+offset]
return queueFiles[cursor+offset]
}
func listPreviousPage() {
if !queueFocused {
if mainBufferOrigin == 0 {
mainBufferCursor = 0
go app.QueueUpdateDraw(updateMain)
return
}
mainBufferOrigin -= (mainBufHeight - 1) - 2
if mainBufferOrigin < 0 {
mainBufferOrigin = 0
}
mainBufferCursor = mainBufferOrigin
mainList.Transform(cview.TransformPreviousPage)
go app.QueueUpdateDraw(updateMain)
} else {
if queueOrigin == 0 {
queueCursor = 0
go app.QueueUpdateDraw(updateQueue)
return
}
queueOrigin -= (queueHeight - 1) - 2
if queueOrigin < 0 {
queueOrigin = 0
}
queueCursor = queueOrigin
queueList.Transform(cview.TransformPreviousPage)
go app.QueueUpdateDraw(updateQueue)
}
}
func listNextPage() {
if !queueFocused {
numEntries := len(mainBufferFiles)
if mainBufferOrigin >= numEntries-(mainBufHeight-1) {
mainBufferCursor = numEntries
go app.QueueUpdateDraw(updateMain)
return
}
mainBufferOrigin += (mainBufHeight - 1) - 2
if mainBufferOrigin > (numEntries-(mainBufHeight-1))+2 {
mainBufferOrigin = (numEntries - (mainBufHeight - 1)) + 2
}
mainBufferCursor = mainBufferOrigin
mainList.Transform(cview.TransformNextPage)
go app.QueueUpdateDraw(updateMain)
} else {
numEntries := len(queueFiles)
if queueOrigin >= numEntries-(queueHeight-1) {
queueCursor = numEntries - 1
go app.QueueUpdateDraw(updateQueue)
return
}
queueOrigin += queueHeight - 2
if queueOrigin > ((numEntries-1)-(queueHeight-1))+2 {
queueOrigin = ((numEntries - 1) - (queueHeight - 1)) + 2
}
queueCursor = queueOrigin
queueList.Transform(cview.TransformNextPage)
go app.QueueUpdateDraw(updateQueue)
}
}
func listRefresh() {
// TODO Remember cursor position
d := mainBufferDirectory
mainBufferDirectory = ""
mainCursor = mainList.GetCurrentItem()
d := mainDirectory
mainDirectory = ""
browseFolder(d)
}
@ -296,5 +237,11 @@ func listToggleHidden() {
func toggleFocusedList() {
queueFocused = !queueFocused
if queueFocused {
app.SetFocus(queueList)
} else {
app.SetFocus(mainList)
}
go app.QueueUpdateDraw(updateLists)
}

View file

@ -10,104 +10,74 @@ import (
"gitlab.com/tslocum/cview"
)
func handleMouse(event *cview.EventMouse) *cview.EventMouse {
if event.Action()&cview.MouseDown != 0 && event.Buttons()&tcell.Button1 != 0 {
mouseX, mouseY := event.Position()
if mouseY >= 0 && mouseY < mainBufHeight {
if queueFocused {
queueFocused = false
go app.QueueUpdateDraw(updateLists)
}
// TODO Delay playing while cursor is moved
if mouseY > 0 && mouseY < mainBufHeight-1 && mouseY-1 < len(mainBufferFiles)+1 {
mainBufferCursor = mainBufferOrigin + (mouseY - 1)
go app.QueueUpdateDraw(updateLists)
go listSelect()
}
return nil
} else if mouseY >= mainBufHeight && mouseY < screenHeight-2 {
if !queueFocused {
queueFocused = true
go app.QueueUpdateDraw(updateLists)
}
if mouseY > mainBufHeight && mouseY < screenHeight-3 {
mouseHit := (mouseY - mainBufHeight) - 1
if mouseHit < len(queueFiles) {
queueCursor = queueOrigin + mouseHit
go app.QueueUpdateDraw(updateLists)
go queueSelect()
}
}
return nil
} else if mouseY == screenHeight-1 {
if mouseX >= seekStart && mouseX <= seekEnd {
if strings.ToLower(path.Ext(playingFileName)) == ".flac" {
statusText = "Seeking FLAC files is unsupported"
go func() {
time.Sleep(5 * time.Second)
statusText = ""
go app.QueueUpdateDraw(updateMain)
}()
func handleMouse(event *tcell.EventMouse, action cview.MouseAction) (*tcell.EventMouse, cview.MouseAction) {
mouseX, mouseY := event.Position()
if action == cview.MouseLeftClick && mouseY == screenHeight-1 {
if mouseX >= seekStart && mouseX <= seekEnd {
if strings.ToLower(path.Ext(playingFileName)) == ".flac" {
statusText = "Seeking FLAC files is unsupported"
go func() {
time.Sleep(5 * time.Second)
statusText = ""
go app.QueueUpdateDraw(updateMain)
}()
go app.QueueUpdateDraw(updateMain)
return nil
}
return nil, 0
}
audioLock.Lock()
speaker.Lock()
if playingStreamer == nil {
speaker.Unlock()
audioLock.Unlock()
return nil, 0
}
pos := float64(mouseX-seekStart) / float64(seekEnd-seekStart)
if pos > 1 {
pos = 1
}
seekTo := int(float64(playingStreamer.Len()-1) * pos)
_ = playingStreamer.Seek(seekTo) // Ignore seek errors
speaker.Unlock()
audioLock.Unlock()
go app.QueueUpdateDraw(updateStatus)
return nil, 0
} else if mouseX >= volumeStart && mouseX <= volumeEnd+1 {
if mouseX > volumeEnd {
mouseX = volumeEnd
}
if mouseX-volumeStart <= 3 {
audioLock.Lock()
speaker.Lock()
if playingStreamer == nil {
if volume == nil {
speaker.Unlock()
audioLock.Unlock()
return nil
return nil, 0
}
pos := float64(mouseX-seekStart) / float64(seekEnd-seekStart)
if pos > 1 {
pos = 1
}
seekTo := int(float64(playingStreamer.Len()-1) * pos)
_ = playingStreamer.Seek(seekTo) // Ignore seek errors
volume.Silent = !volume.Silent
speaker.Unlock()
audioLock.Unlock()
go app.QueueUpdateDraw(updateStatus)
return nil
} else if mouseX >= volumeStart && mouseX <= volumeEnd+1 {
if mouseX > volumeEnd {
mouseX = volumeEnd
} else {
vol := -7.5 + float64(7.5)*(float64(mouseX-volumeStart-3)/float64(volumeEnd-volumeStart-3))
if vol < -7.0 {
vol = -7.0
}
setVolume(roundUnit(vol, 0.5))
if mouseX-volumeStart <= 3 {
audioLock.Lock()
speaker.Lock()
if volume == nil {
speaker.Unlock()
audioLock.Unlock()
return nil
}
volume.Silent = !volume.Silent
speaker.Unlock()
audioLock.Unlock()
go app.QueueUpdateDraw(updateStatus)
} else {
vol := -7.5 + float64(7.5)*(float64(mouseX-volumeStart-3)/float64(volumeEnd-volumeStart-3))
if vol < -7.0 {
vol = -7.0
}
setVolume(roundUnit(vol, 0.5))
go app.QueueUpdateDraw(updateStatus)
}
return nil
go app.QueueUpdateDraw(updateStatus)
}
return nil, 0
}
}
return event
return event, action
}

View file

@ -7,6 +7,7 @@ import (
"path"
"sort"
"strings"
"time"
"github.com/dhowden/tag"
)
@ -16,6 +17,7 @@ type metadata struct {
Artist string
Album string
Track int
Length time.Duration
}
func readMetadata(f *os.File) *metadata {
@ -29,6 +31,21 @@ func readMetadata(f *os.File) *metadata {
metadata.Artist = strings.TrimSpace(m.Artist())
metadata.Album = strings.TrimSpace(m.Album())
metadata.Track, _ = m.Track()
/*
TODO Too slow
d := mp3.NewDecoder(f)
var frame mp3.Frame
var skipped int
for {
err = d.Decode(&frame, &skipped)
if err != nil {
break
}
metadata.Length += frame.Duration()
}
*/
}
return &metadata