Remember working directory, queue, playing file and position

This commit is contained in:
Trevor Slocum 2021-05-01 23:34:23 -07:00
parent bc60cdfbf2
commit eec273682c
10 changed files with 181 additions and 141 deletions

View file

@ -1,29 +0,0 @@
image: golang:latest
stages:
- validate
- build
fmt:
stage: validate
script:
- gofmt -l -s -e .
- exit $(gofmt -l -s -e . | wc -l)
vet:
stage: validate
script:
- apt-get update && apt-get install -y libasound2-dev
- go vet -composites=false ./...
test:
stage: validate
script:
- apt-get update && apt-get install -y libasound2-dev
- go test -race -v ./...
build:
stage: build
script:
- apt-get update && apt-get install -y libasound2-dev
- go build

View file

@ -1,3 +1,6 @@
0.1.9:
- Remember working directory, queue, playing file and position
0.1.8:
- Allow reordering interface elements
- Increase default volume to 100%

View file

@ -33,6 +33,9 @@ var (
playingFormat beep.Format
playingSampleRate beep.SampleRate
pauseNext bool
seekNext int
volume *effects.Volume
ctrl *beep.Ctrl
audioLock = new(sync.Mutex)
@ -42,17 +45,17 @@ type audioFile struct {
File *os.File
Streamer beep.StreamSeekCloser
Format beep.Format
Metadata *metadata
Metadata *Metadata
}
func openFile(filePath string, metadata *metadata) (*audioFile, error) {
func openFile(filePath string, Metadata *Metadata) (*audioFile, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, err
}
if metadata == nil {
metadata = readMetadata(f)
if Metadata == nil {
Metadata = readMetadata(f)
_, err = f.Seek(0, io.SeekStart)
if err != nil {
log.Fatal(err)
@ -79,7 +82,7 @@ func openFile(filePath string, metadata *metadata) (*audioFile, error) {
return nil, err
}
a := audioFile{File: f, Streamer: streamer, Format: format, Metadata: metadata}
a := audioFile{File: f, Streamer: streamer, Format: format, Metadata: Metadata}
return &a, nil
}
@ -146,6 +149,14 @@ func play(audioFile *audioFile) {
Paused: false,
}
}
if pauseNext {
ctrl.Paused = true
pauseNext = false
}
if seekNext != 0 {
_ = playingStreamer.Seek(seekNext)
seekNext = 0
}
speaker.Unlock()
if streamFdInt >= 0 {
@ -202,6 +213,7 @@ func nextTrack() {
return
}
queuePlaying = queueList.GetCurrentItemIndex()
play(audioFile)
go app.QueueUpdateDraw(updateQueue)
}

View file

@ -1,18 +1,15 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"path"
"gopkg.in/yaml.v2"
)
import "github.com/faiface/beep/speaker"
type appConfig struct {
Input map[string][]string // Keybinds
Layout string
Volume int // Starting volume
Input map[string][]string // Keybinds
Layout string
Volume int // Starting volume
Dir string
QueueFiles []*LibraryEntry
QueuePlaying int
AudioPosition int
}
var config = &appConfig{
@ -20,37 +17,15 @@ var config = &appConfig{
Volume: defaultVolume,
}
func defaultConfigPath() string {
homedir, err := os.UserHomeDir()
if err == nil && homedir != "" {
return path.Join(homedir, ".config", "ditty", "config.yaml")
func saveAppState() {
config.Dir = mainDirectory
config.QueueFiles = queueFiles
config.QueuePlaying = queuePlaying
speaker.Lock()
if playingStreamer == nil {
config.AudioPosition = 0
} else {
config.AudioPosition = playingStreamer.Position()
}
return ""
}
func readConfig(configPath string) error {
if configPath == "" {
configPath = defaultConfigPath()
if configPath == "" {
return nil
} else if _, err := os.Stat(configPath); os.IsNotExist(err) {
return nil
}
}
configData, err := ioutil.ReadFile(configPath)
if err != nil {
return fmt.Errorf("failed to read file: %s", err)
}
err = yaml.Unmarshal(configData, config)
if err == nil && (config.Volume < 0 || config.Volume > 100) {
err = fmt.Errorf("invalid volume (must be between 0 and 100): %d", config.Volume)
}
if err != nil {
return fmt.Errorf("failed to parse file: %s", err)
}
return nil
speaker.Unlock()
}

12
go.mod
View file

@ -7,18 +7,18 @@ replace github.com/faiface/beep => github.com/cswank/beep v0.0.0-20210131195430-
require (
code.rocketnine.space/tslocum/cbind v0.1.5
code.rocketnine.space/tslocum/cview v1.5.4
code.rocketnine.space/tslocum/ez v0.0.0-20210502054046-e1e0d1009c8f
github.com/dhowden/tag v0.0.0-20201120070457-d52dcb253c63
github.com/faiface/beep v1.0.2
github.com/gdamore/tcell/v2 v2.2.1-0.20210305060500-f4d402906fa3
github.com/hajimehoshi/go-mp3 v0.3.1 // indirect
github.com/gdamore/tcell/v2 v2.2.1
github.com/hajimehoshi/go-mp3 v0.3.2 // indirect
github.com/hajimehoshi/oto v0.7.1 // indirect
github.com/jfreymuth/oggvorbis v1.0.3 // indirect
github.com/mattn/go-runewidth v0.0.12
github.com/mewkiz/pkg v0.0.0-20210112042322-0b163ae15d52 // indirect
golang.org/x/exp v0.0.0-20210405174845-4513512abef3 // indirect
golang.org/x/exp v0.0.0-20210430132503-b698a44fee45 // indirect
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb // indirect
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 // indirect
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 // indirect
gopkg.in/yaml.v2 v2.4.0
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect
golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4 // indirect
)

77
go.sum
View file

@ -2,12 +2,18 @@ code.rocketnine.space/tslocum/cbind v0.1.5 h1:i6NkeLLNPNMS4NWNi3302Ay3zSU6MrqOT+
code.rocketnine.space/tslocum/cbind v0.1.5/go.mod h1:LtfqJTzM7qhg88nAvNhx+VnTjZ0SXBJtxBObbfBWo/M=
code.rocketnine.space/tslocum/cview v1.5.4 h1:zBUFAanViudrAw8ZCqNxaufqrYL6a7F1AkkIClXIzYo=
code.rocketnine.space/tslocum/cview v1.5.4/go.mod h1:JjgoZi3b528SaV923oQq14PGUCTE/g/6iggnDUxsChE=
code.rocketnine.space/tslocum/ez v0.0.0-20210502054046-e1e0d1009c8f h1:zvqqu4UY7lwNo6thsoRYeUZm9qqZ0F66diIEVhN9oDQ=
code.rocketnine.space/tslocum/ez v0.0.0-20210502054046-e1e0d1009c8f/go.mod h1:SQrM+bQ4eZdyAVTxuF2BNnyAnojHP6Kcmm2vMszoFWw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cswank/beep v0.0.0-20210131195430-fa7ec5ad8941 h1:jbQ5EjYrt5Y7uujUHPNOm5EVLd36pxBOT1gcihtsHBg=
github.com/cswank/beep v0.0.0-20210131195430-fa7ec5ad8941/go.mod h1:FQkUNVR+Fs3a8MQ6KwJh4xCdrT4fF4sSuW+iKvDdrOo=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dhowden/tag v0.0.0-20201120070457-d52dcb253c63 h1:/u5RVRk3Nh7Zw1QQnPtUH5kzcc8JmSSRpHSlGU/zGTE=
github.com/dhowden/tag v0.0.0-20201120070457-d52dcb253c63/go.mod h1:SniNVYuaD1jmdEEvi+7ywb1QFR7agjeTdGKyFb0p7Rw=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
@ -15,15 +21,18 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo
github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
github.com/gdamore/tcell/v2 v2.2.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.2.1-0.20210305060500-f4d402906fa3 h1:PqyGpJlv98ynqEPq5MMiT+hcUPPvIomSS0Rnmy5Tl9A=
github.com/gdamore/tcell/v2 v2.2.1-0.20210305060500-f4d402906fa3/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
github.com/gdamore/tcell/v2 v2.2.1 h1:Gt8wk0jd5pIK2CyXNo/fqwxNWf726j1lQjEDdfbnqTc=
github.com/gdamore/tcell/v2 v2.2.1/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
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-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/go-mp3 v0.3.1 h1:pn/SKU1+/rfK8KaZXdGEC2G/KCB2aLRjbTCrwKcokao=
github.com/hajimehoshi/go-mp3 v0.3.1/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/go-mp3 v0.3.2 h1:xSYNE2F3lxtOu9BRjCWHHceg7S91IHfXfXp5+LYQI7s=
github.com/hajimehoshi/go-mp3 v0.3.2/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
@ -37,6 +46,12 @@ github.com/jfreymuth/oggvorbis v1.0.3/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHix
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@ -53,63 +68,99 @@ github.com/mewkiz/pkg v0.0.0-20210112042322-0b163ae15d52/go.mod h1:3E2FUC/qYUfM8
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
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/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-20210405174845-4513512abef3 h1:ZsldXBaaFMK70l0+CbgvsHOcjhgd9LzPhePQIsm5aS4=
golang.org/x/exp v0.0.0-20210405174845-4513512abef3/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4=
golang.org/x/exp v0.0.0-20210430132503-b698a44fee45 h1:XqRf5+0Xvcb6/S21xhk9fABamGZ7gSWdIPyRv2EEhBc=
golang.org/x/exp v0.0.0-20210430132503-b698a44fee45/go.mod h1:cJRhTyGheUtAt9+V1LK3LYoFneBlmiX5bePSkB17RVE=
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=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
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-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 h1:h+GZ3ubjuWaQjGe8owMGcmMVCqs0xYJtRG5y2bpHaqU=
golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
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.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/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=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0=
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4 h1:UPou2i3GzKgi6igR+/0C5XyHKBngHxBp/CL5CQ0p3Zk=
golang.org/x/term v0.0.0-20210429154555-c04ba851c2a4/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
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/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=

15
gui.go
View file

@ -30,7 +30,7 @@ var (
topstatusbuf *cview.TextView
bottomstatusbuf *cview.TextView
mainFiles []*libraryEntry
mainFiles []*LibraryEntry
mainCursor = -1
mainDirectory string
mainAutoFocus string // Entry path to focus after loading display
@ -38,8 +38,9 @@ var (
mainBuffer bytes.Buffer
mainLock = new(sync.Mutex)
queueFiles []*libraryEntry
queueCursor = -1
queueFiles []*LibraryEntry
queueCursor = -1
queuePlaying int
queueBuffer bytes.Buffer
queueLock = new(sync.Mutex)
@ -189,11 +190,11 @@ func browseFolder(browse string) {
autoSelect := -1
var entryPath string
for i, entry := range mainFiles {
if !entry.File.IsDir() && entry.File.Mode()&os.ModeSymlink == 0 {
if !entry.IsDir && entry.Mode&os.ModeSymlink == 0 {
continue
}
entryPath, err = filepath.Abs(path.Join(mainDirectory, entry.File.Name()))
entryPath, err = filepath.Abs(path.Join(mainDirectory, entry.Name))
if err == nil {
if entryPath == autoSelectAbs {
autoSelect = i
@ -272,8 +273,8 @@ func updateMain() {
for _, entry := range mainFiles {
//length = ""
if entry.File.IsDir() || entry.File.Mode()&os.ModeSymlink != 0 {
line = strings.TrimSpace(entry.File.Name()) + "/"
if entry.IsDir || entry.Mode&os.ModeSymlink != 0 {
line = strings.TrimSpace(entry.Name) + "/"
} else {
line = entry.String()

View file

@ -58,7 +58,7 @@ func listSelect(cursor int) {
}
entry := mainFiles[cursor-1]
if entry.File.IsDir() || entry.File.Mode()&os.ModeSymlink != 0 {
if entry.IsDir || entry.Mode&os.ModeSymlink != 0 {
browseFolder(entry.RealPath)
return
}
@ -85,7 +85,7 @@ func queueSelect(cursor int) {
}
entry := queueFiles[cursor]
if entry.File.IsDir() || entry.File.Mode()&os.ModeSymlink != 0 {
if entry.IsDir || entry.Mode&os.ModeSymlink != 0 {
return
}
@ -100,6 +100,7 @@ func queueSelect(cursor int) {
go app.QueueUpdateDraw(updateMain)
return
}
queuePlaying = cursor
go play(audioFile)
go app.QueueUpdateDraw(updateStatus)
@ -114,7 +115,7 @@ func listQueue() {
entry := selectedMainEntry()
if entry == nil {
return
} else if entry.File.IsDir() || entry.File.Mode()&os.ModeSymlink != 0 {
} else if entry.IsDir || entry.Mode&os.ModeSymlink != 0 {
scanFiles := scanFolderRecursively(entry.RealPath)
queueLock.Lock()
@ -158,7 +159,7 @@ func listDelete() {
go app.QueueUpdateDraw(updateQueue)
}
func selectedMainEntry() *libraryEntry {
func selectedMainEntry() *LibraryEntry {
cursor := mainList.GetCurrentItemIndex()
if cursor < 0 || cursor-1 > len(mainFiles) {
return nil
@ -167,7 +168,7 @@ func selectedMainEntry() *libraryEntry {
return mainFiles[cursor-1]
}
func offsetMainEntry(offset int) *libraryEntry {
func offsetMainEntry(offset int) *LibraryEntry {
cursor := mainList.GetCurrentItemIndex()
if (cursor-1)+offset < 0 || (cursor-1)+offset >= len(mainFiles) {
return nil
@ -175,7 +176,7 @@ func offsetMainEntry(offset int) *libraryEntry {
return mainFiles[(cursor-1)+offset]
}
func selectedQueueEntry() *libraryEntry {
func selectedQueueEntry() *LibraryEntry {
cursor := queueList.GetCurrentItemIndex()
if cursor < 0 || cursor-1 > len(queueFiles) {
return nil
@ -184,7 +185,7 @@ func selectedQueueEntry() *libraryEntry {
return queueFiles[cursor]
}
func offsetQueueEntry(offset int) *libraryEntry {
func offsetQueueEntry(offset int) *LibraryEntry {
cursor := queueList.GetCurrentItemIndex()
if cursor+offset < 0 || cursor+offset >= len(queueFiles) {
return nil

View file

@ -1,6 +1,7 @@
package main
import (
"io/fs"
"io/ioutil"
"log"
"os"
@ -12,7 +13,7 @@ import (
"github.com/dhowden/tag"
)
type metadata struct {
type Metadata struct {
Title string
Artist string
Album string
@ -20,17 +21,17 @@ type metadata struct {
Length time.Duration
}
func readMetadata(f *os.File) *metadata {
var metadata metadata
func readMetadata(f *os.File) *Metadata {
var Metadata Metadata
m, err := tag.ReadFrom(f)
if err != nil || m.Title() == "" {
metadata.Title = strings.TrimSpace(path.Base(f.Name()))
Metadata.Title = strings.TrimSpace(path.Base(f.Name()))
} else {
metadata.Title = strings.TrimSpace(m.Title())
metadata.Artist = strings.TrimSpace(m.Artist())
metadata.Album = strings.TrimSpace(m.Album())
metadata.Track, _ = m.Track()
Metadata.Title = strings.TrimSpace(m.Title())
Metadata.Artist = strings.TrimSpace(m.Artist())
Metadata.Album = strings.TrimSpace(m.Album())
Metadata.Track, _ = m.Track()
/*
TODO Too slow
@ -43,22 +44,24 @@ func readMetadata(f *os.File) *metadata {
break
}
metadata.Length += frame.Duration()
Metadata.Length += frame.Duration()
}
*/
}
return &metadata
return &Metadata
}
type libraryEntry struct {
File os.FileInfo
type LibraryEntry struct {
Name string
IsDir bool
Mode fs.FileMode
Path string
RealPath string
Metadata *metadata
Metadata *Metadata
}
func (e *libraryEntry) String() string {
func (e *LibraryEntry) String() string {
if e.Metadata.Title != "" {
if e.Metadata.Artist != "" {
return e.Metadata.Artist + " - " + e.Metadata.Title
@ -67,16 +70,16 @@ func (e *libraryEntry) String() string {
return e.Metadata.Title
}
return strings.TrimSpace(e.File.Name())
return strings.TrimSpace(e.Name)
}
func scanFolder(scanPath string) []*libraryEntry {
func scanFolder(scanPath string) []*LibraryEntry {
files, err := ioutil.ReadDir(scanPath)
if err != nil {
log.Fatalf("failed to scan %s: %s", scanPath, err)
}
var entries []*libraryEntry
var entries []*LibraryEntry
for _, fileInfo := range files {
p := path.Join(scanPath, fileInfo.Name())
var r string
@ -97,7 +100,7 @@ func scanFolder(scanPath string) []*libraryEntry {
b := path.Base(p)
if fileInfo.IsDir() || fileInfo.Mode()&os.ModeSymlink != 0 {
if b != "" && (b[0] != '.' || showHiddenFolders) {
entries = append(entries, &libraryEntry{File: fileInfo, Path: p, RealPath: r, Metadata: &metadata{Title: strings.TrimSpace(fileInfo.Name())}})
entries = append(entries, &LibraryEntry{Name: fileInfo.Name(), IsDir: fileInfo.IsDir(), Mode: fileInfo.Mode(), Path: p, RealPath: r, Metadata: &Metadata{Title: strings.TrimSpace(fileInfo.Name())}})
}
continue
@ -109,15 +112,15 @@ func scanFolder(scanPath string) []*libraryEntry {
if err != nil {
continue
}
metadata := readMetadata(f)
Metadata := readMetadata(f)
f.Close()
entries = append(entries, &libraryEntry{File: fileInfo, Path: p, RealPath: r, Metadata: metadata})
entries = append(entries, &LibraryEntry{Name: fileInfo.Name(), IsDir: fileInfo.IsDir(), Mode: fileInfo.Mode(), Path: p, RealPath: r, Metadata: Metadata})
}
sort.Slice(entries, func(i, j int) bool {
iDir := entries[i].File.IsDir() || entries[i].File.Mode()&os.ModeSymlink != 0
jDir := entries[j].File.IsDir() || entries[j].File.Mode()&os.ModeSymlink != 0
iDir := entries[i].IsDir || entries[i].Mode&os.ModeSymlink != 0
jDir := entries[j].IsDir || entries[j].Mode&os.ModeSymlink != 0
if iDir != jDir {
return iDir
}
@ -126,25 +129,25 @@ func scanFolder(scanPath string) []*libraryEntry {
return entries[i].Metadata.Track < entries[j].Metadata.Track
}
return strings.ToLower(entries[i].Metadata.Album) < strings.ToLower(entries[j].Metadata.Album) && strings.ToLower(entries[i].File.Name()) < strings.ToLower(entries[j].File.Name())
return strings.ToLower(entries[i].Metadata.Album) < strings.ToLower(entries[j].Metadata.Album) && strings.ToLower(entries[i].Name) < strings.ToLower(entries[j].Name)
})
return entries
}
func scanFolderRecursively(path string) []*libraryEntry {
var entries []*libraryEntry
func scanFolderRecursively(path string) []*LibraryEntry {
var entries []*LibraryEntry
scanFiles := scanFolder(path)
for _, entry := range scanFiles {
if !entry.File.IsDir() && entry.File.Mode()&os.ModeSymlink == 0 {
if !entry.IsDir && entry.Mode&os.ModeSymlink == 0 {
continue
}
entries = append(entries, scanFolderRecursively(entry.RealPath)...)
}
for _, entry := range scanFiles {
if entry.File.IsDir() || entry.File.Mode()&os.ModeSymlink != 0 {
if entry.IsDir || entry.Mode&os.ModeSymlink != 0 {
continue
}

31
main.go
View file

@ -13,6 +13,8 @@ import (
"strings"
"syscall"
"time"
"code.rocketnine.space/tslocum/ez"
)
const (
@ -96,7 +98,8 @@ func main() {
defer pprof.StopCPUProfile()
}
err := readConfig(configPath)
ez.SetAppName("ditty")
err := ez.ReadConfig(config, configPath)
if err != nil {
log.Fatalf("failed to read configuration file: %s", err)
}
@ -147,7 +150,11 @@ func main() {
startPath := strings.Join(flag.Args(), " ")
if startPath == "" {
if restrictLibrary == "" {
if config.Dir != "" {
startPath = config.Dir
} else if restrictLibrary != "" {
startPath = restrictLibrary
} else {
wd, err := os.Getwd()
if err != nil || wd == "" {
homeDir, err := os.UserHomeDir()
@ -157,8 +164,6 @@ func main() {
} else {
startPath = wd
}
} else {
startPath = restrictLibrary
}
}
if startPath == "" {
@ -169,6 +174,7 @@ func main() {
log.Fatal(err)
}
var playing bool
if fileInfo.IsDir() {
browseFolder(startPath)
} else {
@ -180,9 +186,23 @@ func main() {
app.QueueUpdateDraw(updateMain)
} else {
play(audioFile)
playing = true
}
}
if config.QueueFiles != nil {
queueFiles = config.QueueFiles
app.QueueUpdateDraw(func() {
updateQueue()
queueList.SetCurrentItem(config.QueuePlaying)
if len(queueFiles) > 0 && !playing {
pauseNext = true
seekNext = config.AudioPosition
go queueSelect(config.QueuePlaying)
}
})
}
defer func() {
if app != nil {
app.Stop()
@ -193,6 +213,9 @@ func main() {
for {
select {
case <-done:
saveAppState()
ez.SaveConfig(config, configPath) // Failing isn't an issue, this could be logged though
if streamFd != nil {
streamFd.Close()
}