Commit hoarding is a problem
This commit is contained in:
parent
6ff89f913d
commit
85c3cdf57f
1
go.mod
1
go.mod
@ -15,6 +15,7 @@ require (
|
|||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.12 // indirect
|
||||||
github.com/mewkiz/flac v1.0.7 // indirect
|
github.com/mewkiz/flac v1.0.7 // indirect
|
||||||
github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77 // indirect
|
github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77 // indirect
|
||||||
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
|
github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -48,6 +48,8 @@ github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC
|
|||||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/mewkiz/flac v1.0.7 h1:uIXEjnuXqdRaZttmSFM5v5Ukp4U6orrZsnYGGR3yow8=
|
github.com/mewkiz/flac v1.0.7 h1:uIXEjnuXqdRaZttmSFM5v5Ukp4U6orrZsnYGGR3yow8=
|
||||||
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
|
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
|
||||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
||||||
|
3
main.go
3
main.go
@ -13,8 +13,9 @@ func main() {
|
|||||||
log.Fatal("Expected a path to some music")
|
log.Fatal("Expected a path to some music")
|
||||||
}
|
}
|
||||||
|
|
||||||
p := tea.NewProgram(gomus.NewModel(gomus.ModelArgs{
|
p := tea.NewProgram(gomus.NewModel(gomus.ModelConfig{
|
||||||
MusicPath: os.Args[1],
|
MusicPath: os.Args[1],
|
||||||
|
GomusPath: ".gomus",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if err := p.Start(); err != nil {
|
if err := p.Start(); err != nil {
|
||||||
|
@ -31,3 +31,13 @@ func newTrackVolumeCmd(volume float64) tea.Cmd {
|
|||||||
return trackVolumeMsg{volume}
|
return trackVolumeMsg{volume}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type libraryUpdateMsg struct {
|
||||||
|
tracks []track
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLibraryUpdateCmd(tracks []track) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return libraryUpdateMsg{tracks}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ func (d trackListDelegate) Render(w io.Writer, m list.Model, index int, listItem
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(w, f)
|
fmt.Fprintf(w, fmt.Sprintf(" %s", f))
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrackListDelegate() trackListDelegate {
|
func newTrackListDelegate() trackListDelegate {
|
||||||
|
64
pkg/model.go
64
pkg/model.go
@ -1,10 +1,11 @@
|
|||||||
package gomus
|
package gomus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"errors"
|
||||||
|
"os"
|
||||||
|
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
"github.com/faiface/beep/speaker"
|
"github.com/faiface/beep"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -12,8 +13,9 @@ var (
|
|||||||
termHeight = 0
|
termHeight = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
type ModelArgs struct {
|
type ModelConfig struct {
|
||||||
MusicPath string
|
MusicPath string
|
||||||
|
GomusPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
@ -23,28 +25,32 @@ type Model struct {
|
|||||||
TrackPlayer
|
TrackPlayer
|
||||||
TrackPlayerEffects
|
TrackPlayerEffects
|
||||||
trackIndex
|
trackIndex
|
||||||
|
|
||||||
trackPlayerView
|
trackPlayerView
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModel(args ModelArgs) Model {
|
func NewModel(cfg ModelConfig) Model {
|
||||||
ti := NewDirTrackIndex(args.MusicPath)
|
if _, err := os.Stat(cfg.GomusPath); errors.Is(err, os.ErrNotExist) {
|
||||||
tpv := newTrackPlayerView(ti.tracks)
|
err := os.Mkdir(cfg.GomusPath, 0755)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
|
||||||
return Model{
|
return Model{
|
||||||
cursor: 0,
|
cursor: 0,
|
||||||
currentlyPlaying: 0,
|
currentlyPlaying: 0,
|
||||||
|
|
||||||
trackIndex: ti,
|
trackIndex: NewDirTrackIndex(cfg),
|
||||||
TrackPlayer: TrackPlayer{},
|
TrackPlayer: NewTrackPlayer(),
|
||||||
TrackPlayerEffects: newTrackPlayerEffects(),
|
TrackPlayerEffects: NewTrackPlayerEffects(),
|
||||||
|
trackPlayerView: NewTrackPlayerView(),
|
||||||
trackPlayerView: tpv,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) Init() tea.Cmd {
|
func (m Model) Init() tea.Cmd {
|
||||||
return tea.Batch(tea.EnterAltScreen, m.trackPlayerView.Init())
|
var cmds []tea.Cmd
|
||||||
|
cmds = append(cmds, tea.EnterAltScreen)
|
||||||
|
cmds = append(cmds, m.trackPlayerView.Init())
|
||||||
|
cmds = append(cmds, newLibraryUpdateCmd(m.trackIndex.tracks))
|
||||||
|
return tea.Batch(cmds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
@ -57,7 +63,6 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "ctrl+c", "q":
|
case "ctrl+c", "q":
|
||||||
m.TrackPlayer.Close()
|
|
||||||
return m, tea.Quit
|
return m, tea.Quit
|
||||||
case "enter":
|
case "enter":
|
||||||
t := m.trackPlayerView.trackList.SelectedItem().(track)
|
t := m.trackPlayerView.trackList.SelectedItem().(track)
|
||||||
@ -65,35 +70,30 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
stream, format, err := t.GetStream()
|
stream, format, err := t.GetStream()
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
|
resampled := beep.Resample(4, format.SampleRate, m.TrackPlayer.SampleRate, stream)
|
||||||
|
m.TrackPlayer.Play(resampled)
|
||||||
|
|
||||||
m.TrackPlayer.Play(&stream, &m.TrackPlayerEffects)
|
|
||||||
cmds = append(cmds, newTrackChangeCmd(t))
|
cmds = append(cmds, newTrackChangeCmd(t))
|
||||||
case " ":
|
case " ":
|
||||||
if m.TrackPlayer.playerCtrl != nil {
|
s := m.TrackPlayer.TogglePause()
|
||||||
s := m.TrackPlayer.TogglePause()
|
cmds = append(cmds, newTrackPauseCmd(s))
|
||||||
cmds = append(cmds, newTrackPauseCmd(s))
|
|
||||||
}
|
|
||||||
case "-", "=":
|
case "-", "=":
|
||||||
v := &m.TrackPlayerEffects.volume
|
pe := &m.TrackPlayerEffects
|
||||||
|
|
||||||
if msg.String() == "-" {
|
if msg.String() == "-" {
|
||||||
*v -= 0.1
|
pe.volume -= 0.1
|
||||||
if *v < minVolume {
|
if pe.volume < minVolume {
|
||||||
*v = minVolume
|
pe.volume = minVolume
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*v += 0.1
|
pe.volume += 0.1
|
||||||
if *v > maxVolume {
|
if pe.volume > maxVolume {
|
||||||
*v = maxVolume
|
pe.volume = maxVolume
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.TrackPlayer.playerVol != nil {
|
m.TrackPlayer.SetVolume(pe.volume)
|
||||||
m.TrackPlayer.SetVolume(*v)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmds = append(cmds, newTrackVolumeCmd(*v))
|
cmds = append(cmds, newTrackVolumeCmd(m.TrackPlayerEffects.volume))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
74
pkg/track.go
Normal file
74
pkg/track.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package gomus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/faiface/beep"
|
||||||
|
bflac "github.com/faiface/beep/flac"
|
||||||
|
"github.com/mewkiz/flac"
|
||||||
|
"github.com/mewkiz/flac/meta"
|
||||||
|
)
|
||||||
|
|
||||||
|
type track struct {
|
||||||
|
Title string
|
||||||
|
Album string
|
||||||
|
Artist string
|
||||||
|
TrackPath string
|
||||||
|
TrackTotal uint8
|
||||||
|
TrackNumber uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t track) FilterValue() string { return "" }
|
||||||
|
func (t track) fullName() string { return fmt.Sprintf("%s - %s", t.Artist, t.Title) }
|
||||||
|
|
||||||
|
func (t track) GetStream() (beep.StreamSeekCloser, beep.Format, error) {
|
||||||
|
f, err := os.Open(t.TrackPath)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
if strings.HasSuffix(t.TrackPath, ".flac") {
|
||||||
|
streamer, format, err := bflac.Decode(f)
|
||||||
|
check(err)
|
||||||
|
return streamer, format, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, beep.Format{}, fmt.Errorf("Could not parse track")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TrackFromFlac(path string) track {
|
||||||
|
path, err := filepath.Abs(path)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
s, err := flac.ParseFile(path)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
t := track{TrackPath: path}
|
||||||
|
for _, block := range s.Blocks {
|
||||||
|
if block.Header.Type == meta.TypeVorbisComment {
|
||||||
|
c := block.Body.(*meta.VorbisComment)
|
||||||
|
for _, tagTuple := range c.Tags {
|
||||||
|
tag, val := tagTuple[0], tagTuple[1]
|
||||||
|
switch tag {
|
||||||
|
case "TITLE":
|
||||||
|
t.Title = val
|
||||||
|
case "ARTIST":
|
||||||
|
t.Artist = val
|
||||||
|
case "ALBUM":
|
||||||
|
t.Album = val
|
||||||
|
case "TRACKNUMBER":
|
||||||
|
trackNum, err := strconv.ParseUint(val, 10, 8)
|
||||||
|
check(err)
|
||||||
|
t.TrackNumber = uint8(trackNum)
|
||||||
|
case "TRACKTOTAL":
|
||||||
|
trackTotal, err := strconv.ParseUint(val, 10, 8)
|
||||||
|
check(err)
|
||||||
|
t.TrackTotal = uint8(trackTotal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
@ -1,76 +1,80 @@
|
|||||||
package gomus
|
package gomus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"database/sql"
|
||||||
"io/ioutil"
|
"io/fs"
|
||||||
"os"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
bflac "github.com/faiface/beep/flac"
|
|
||||||
"github.com/mewkiz/flac"
|
|
||||||
"github.com/mewkiz/flac/meta"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type track struct {
|
|
||||||
Name string
|
|
||||||
Artist string
|
|
||||||
TrackPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t track) FilterValue() string { return "" }
|
|
||||||
func (t track) fullName() string { return fmt.Sprintf("%s - %s", t.Artist, t.Name) }
|
|
||||||
|
|
||||||
func (t track) GetStream() (beep.StreamSeekCloser, beep.Format, error) {
|
|
||||||
f, err := os.Open(t.TrackPath)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
if strings.HasSuffix(t.TrackPath, ".flac") {
|
|
||||||
streamer, format, err := bflac.Decode(f)
|
|
||||||
check(err)
|
|
||||||
return streamer, format, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, beep.Format{}, fmt.Errorf("Could not parse track")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TrackFromFlac(path string) track {
|
|
||||||
s, err := flac.ParseFile(path)
|
|
||||||
check(err)
|
|
||||||
|
|
||||||
t := track{TrackPath: path}
|
|
||||||
for _, block := range s.Blocks {
|
|
||||||
if block.Header.Type == meta.TypeVorbisComment {
|
|
||||||
c := block.Body.(*meta.VorbisComment)
|
|
||||||
for _, tag := range c.Tags {
|
|
||||||
if tag[0] == "ARTIST" {
|
|
||||||
t.Artist = tag[1]
|
|
||||||
} else if tag[0] == "TITLE" {
|
|
||||||
t.Name = tag[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
type trackIndex struct {
|
type trackIndex struct {
|
||||||
tracks []track
|
tracks []track
|
||||||
|
db *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDirTrackIndex(path string) trackIndex {
|
func NewDirTrackIndex(cfg ModelConfig) trackIndex {
|
||||||
files, err := ioutil.ReadDir(path)
|
dbPath := filepath.Join(cfg.GomusPath, "gomus.db")
|
||||||
check(err)
|
db, err := sql.Open("sqlite3", dbPath)
|
||||||
|
if err != nil {
|
||||||
tracks := []track{}
|
log.Fatalf("Failed to open gomus database: %v", err)
|
||||||
for _, file := range files {
|
|
||||||
if !file.IsDir() && strings.HasSuffix(file.Name(), ".flac") {
|
|
||||||
p := filepath.Join(path, file.Name())
|
|
||||||
tracks = append(tracks, TrackFromFlac(p))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return trackIndex{tracks: tracks}
|
tblStmt := `
|
||||||
|
CREATE TABLE IF NOT EXISTS track (
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
album TEXT,
|
||||||
|
artist TEXT NOT NULL,
|
||||||
|
uri TEXT NOT NULL,
|
||||||
|
trackNumber INTEGER,
|
||||||
|
trackTotal INTEGER
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = db.Exec(tblStmt)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%q: %s\n", err, tblStmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := cfg.MusicPath
|
||||||
|
tracks, err := ScanDirectory(path)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
ti := trackIndex{tracks, db}
|
||||||
|
ti.IndexTracks(tracks)
|
||||||
|
|
||||||
|
return ti
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti trackIndex) IndexTracks(tracks []track) error {
|
||||||
|
tx, err := ti.db.Begin()
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
stmt, err := tx.Prepare("insert into track(title, album, artist, uri, trackNumber, trackTotal) values (?, ?, ?, ?, ?, ?)")
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
for _, t := range tracks {
|
||||||
|
stmt.Exec(t.Title, t.Album, t.Artist, t.TrackPath, t.TrackNumber, t.TrackTotal)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScanDirectory(path string) ([]track, error) {
|
||||||
|
tracks := []track{}
|
||||||
|
filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
check(err)
|
||||||
|
if !d.IsDir() && strings.HasSuffix(d.Name(), ".flac") {
|
||||||
|
t := TrackFromFlac(path)
|
||||||
|
tracks = append(tracks, t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return tracks, nil
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package gomus
|
package gomus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/faiface/beep"
|
"github.com/faiface/beep"
|
||||||
"github.com/faiface/beep/effects"
|
"github.com/faiface/beep/effects"
|
||||||
"github.com/faiface/beep/speaker"
|
"github.com/faiface/beep/speaker"
|
||||||
@ -17,44 +19,51 @@ type TrackPlayerEffects struct {
|
|||||||
volume float64
|
volume float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrackPlayerEffects() TrackPlayerEffects {
|
func NewTrackPlayerEffects() TrackPlayerEffects {
|
||||||
return TrackPlayerEffects{volume: startVolume}
|
return TrackPlayerEffects{volume: startVolume}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrackPlayer struct {
|
type TrackPlayer struct {
|
||||||
streamer *beep.StreamSeekCloser
|
*beep.Ctrl
|
||||||
playerCtrl *beep.Ctrl
|
*effects.Volume
|
||||||
playerVol *effects.Volume
|
|
||||||
|
beep.SampleRate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TrackPlayer) Play(streamer *beep.StreamSeekCloser, trackEffects *TrackPlayerEffects) {
|
func NewTrackPlayer() TrackPlayer {
|
||||||
if t.streamer != nil {
|
sr := beep.SampleRate(44100)
|
||||||
t.Close()
|
speaker.Init(sr, sr.N(time.Second/10))
|
||||||
|
|
||||||
|
ctrl := &beep.Ctrl{Streamer: beep.Silence(1), Paused: false}
|
||||||
|
volume := &effects.Volume{Streamer: ctrl, Base: base, Volume: startVolume, Silent: false}
|
||||||
|
|
||||||
|
return TrackPlayer{
|
||||||
|
SampleRate: sr,
|
||||||
|
Ctrl: ctrl,
|
||||||
|
Volume: volume,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctrl := &beep.Ctrl{Streamer: beep.Loop(-1, *streamer), Paused: false}
|
func (t *TrackPlayer) Play(streamer beep.Streamer) {
|
||||||
volume := &effects.Volume{Streamer: ctrl, Base: base, Volume: trackEffects.volume, Silent: false}
|
speaker.Clear()
|
||||||
speaker.Play(volume)
|
|
||||||
|
|
||||||
t.streamer = streamer
|
speaker.Lock()
|
||||||
t.playerCtrl = ctrl
|
t.Ctrl.Streamer = streamer
|
||||||
t.playerVol = volume
|
speaker.Unlock()
|
||||||
|
|
||||||
|
speaker.Play(t.Volume)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TrackPlayer) TogglePause() bool {
|
func (t *TrackPlayer) TogglePause() bool {
|
||||||
speaker.Lock()
|
speaker.Lock()
|
||||||
newState := !t.playerCtrl.Paused
|
newState := !t.Ctrl.Paused
|
||||||
t.playerCtrl.Paused = newState
|
t.Ctrl.Paused = newState
|
||||||
speaker.Unlock()
|
speaker.Unlock()
|
||||||
return newState
|
return newState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TrackPlayer) SetVolume(volume float64) {
|
func (t *TrackPlayer) SetVolume(volume float64) {
|
||||||
speaker.Lock()
|
speaker.Lock()
|
||||||
(*t.playerVol).Volume = volume
|
t.Volume.Volume = volume
|
||||||
speaker.Unlock()
|
speaker.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TrackPlayer) Close() {
|
|
||||||
(*t.streamer).Close()
|
|
||||||
}
|
|
||||||
|
@ -11,20 +11,15 @@ type trackPlayerView struct {
|
|||||||
statusBar
|
statusBar
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrackPlayerView(tracks []track) trackPlayerView {
|
func NewTrackPlayerView() trackPlayerView {
|
||||||
c := mapList(tracks, func(t track) list.Item {
|
l := list.New([]list.Item{}, newTrackListDelegate(), 0, 0)
|
||||||
return t
|
|
||||||
})
|
|
||||||
|
|
||||||
l := list.New(c, newTrackListDelegate(), 0, 0)
|
|
||||||
l.SetShowTitle(false)
|
l.SetShowTitle(false)
|
||||||
l.SetShowStatusBar(false)
|
l.SetShowStatusBar(false)
|
||||||
l.SetShowHelp(false)
|
l.SetShowHelp(false)
|
||||||
l.SetFilteringEnabled(false)
|
l.SetFilteringEnabled(false)
|
||||||
|
l.SetShowPagination(false)
|
||||||
s := statusBar{currentVolume: startVolume}
|
s := statusBar{currentVolume: startVolume}
|
||||||
|
return trackPlayerView{statusBar: s, trackList: l}
|
||||||
return trackPlayerView{trackList: l, statusBar: s}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v trackPlayerView) Init() tea.Cmd {
|
func (v trackPlayerView) Init() tea.Cmd {
|
||||||
@ -42,6 +37,11 @@ func (v trackPlayerView) Update(msg tea.Msg) (trackPlayerView, tea.Cmd) {
|
|||||||
case tea.WindowSizeMsg:
|
case tea.WindowSizeMsg:
|
||||||
v.trackList.SetHeight(msg.Height - 2)
|
v.trackList.SetHeight(msg.Height - 2)
|
||||||
v.trackList.SetWidth(msg.Width)
|
v.trackList.SetWidth(msg.Width)
|
||||||
|
case libraryUpdateMsg:
|
||||||
|
c := MapList(msg.tracks, func(t track) list.Item {
|
||||||
|
return t
|
||||||
|
})
|
||||||
|
v.trackList.SetItems(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
|
Loading…
x
Reference in New Issue
Block a user