gomu/playlist.go

235 lines
4.1 KiB
Go
Raw Normal View History

2020-06-22 00:05:56 +08:00
// Copyright (C) 2020 Raziman
2020-06-19 16:22:20 +08:00
package main
import (
2020-06-23 22:27:02 +08:00
"fmt"
2020-06-19 16:22:20 +08:00
"io/ioutil"
2020-06-23 18:42:27 +08:00
"os"
2020-06-25 10:46:45 +08:00
"path"
2020-06-19 16:22:20 +08:00
"path/filepath"
"github.com/gdamore/tcell"
"github.com/rivo/tview"
2020-06-24 20:09:47 +08:00
"github.com/spf13/viper"
2020-06-19 16:22:20 +08:00
)
type AudioFile struct {
2020-06-19 16:42:30 +08:00
Name string
Path string
2020-06-19 16:22:20 +08:00
IsAudioFile bool
2020-06-19 16:42:30 +08:00
Parent *tview.TreeNode
2020-06-19 16:22:20 +08:00
}
2020-06-26 12:54:48 +08:00
type Playlist struct {
*tview.TreeView
}
2020-06-19 16:22:20 +08:00
2020-06-26 12:54:48 +08:00
func InitPlaylist() *Playlist {
2020-06-24 20:09:47 +08:00
2020-06-25 10:46:45 +08:00
rootDir, err := filepath.Abs(expandTilde(viper.GetString("music_dir")))
2020-06-19 16:22:20 +08:00
if err != nil {
2020-06-21 23:47:12 +08:00
log(err.Error())
2020-06-19 16:22:20 +08:00
}
2020-06-25 10:46:45 +08:00
root := tview.NewTreeNode(path.Base(rootDir))
2020-06-19 16:22:20 +08:00
tree := tview.NewTreeView().SetRoot(root)
2020-06-26 12:54:48 +08:00
playlist := &Playlist{tree}
2020-06-19 16:22:20 +08:00
2020-06-26 12:54:48 +08:00
playlist.SetTitle(" Playlist ").SetBorder(true)
2020-06-19 16:22:20 +08:00
2020-06-25 14:12:19 +08:00
populate(root, rootDir)
2020-06-19 16:22:20 +08:00
2020-06-25 14:12:19 +08:00
var firstChild *tview.TreeNode
2020-06-26 12:54:48 +08:00
var prevNode *tview.TreeNode
2020-06-23 18:42:27 +08:00
2020-06-25 14:12:19 +08:00
if len(root.GetChildren()) == 0 {
firstChild = root
} else {
firstChild = root.GetChildren()[0]
}
2020-06-19 16:22:20 +08:00
2020-06-25 14:12:19 +08:00
firstChild.SetColor(textColor)
2020-06-26 12:54:48 +08:00
playlist.SetCurrentNode(firstChild)
2020-06-25 14:12:19 +08:00
// keep track of prev node so we can remove the color of highlight
prevNode = firstChild.SetColor(accentColor)
2020-06-19 16:22:20 +08:00
2020-06-26 12:54:48 +08:00
playlist.SetChangedFunc(func(node *tview.TreeNode) {
2020-06-25 14:12:19 +08:00
prevNode.SetColor(textColor)
root.SetColor(textColor)
node.SetColor(accentColor)
prevNode = node
})
2020-06-23 18:42:27 +08:00
2020-06-26 12:54:48 +08:00
playlist.SetSelectedFunc(func(node *tview.TreeNode) {
node.SetExpanded(!node.IsExpanded())
})
2020-06-19 16:22:20 +08:00
2020-06-26 12:54:48 +08:00
playlist.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
currNode := playlist.GetCurrentNode()
if currNode == playlist.GetRoot() {
return e
}
audioFile := currNode.GetReference().(*AudioFile)
switch e.Rune() {
case 'l':
playlist.addToQueue(audioFile)
currNode.SetExpanded(true)
case 'h':
// if closing node with no children
// close the node's parent
// remove the color of the node
if audioFile.IsAudioFile {
parent := audioFile.Parent
currNode.SetColor(textColor)
parent.SetExpanded(false)
parent.SetColor(accentColor)
// prevPanel = parent
playlist.SetCurrentNode(parent)
}
currNode.Collapse()
case 'L':
2020-06-26 17:09:15 +08:00
if !viper.GetBool("confirm_bulk_add") {
playlist.addAllToQueue(playlist.GetCurrentNode())
return e
}
2020-06-26 12:54:48 +08:00
confirmationPopup(
"Are you sure to add this whole directory into queue?",
func(_ int, label string) {
if label == "yes" {
playlist.addAllToQueue(playlist.GetCurrentNode())
}
pages.RemovePage("confirmation-popup")
app.SetFocus(playlist)
})
}
return e
2020-06-19 16:22:20 +08:00
})
2020-06-26 12:54:48 +08:00
return playlist
2020-06-19 16:22:20 +08:00
}
func populate(root *tview.TreeNode, rootPath string) {
files, err := ioutil.ReadDir(rootPath)
if err != nil {
2020-06-21 23:47:12 +08:00
log(err.Error())
2020-06-19 16:22:20 +08:00
}
for _, file := range files {
path := filepath.Join(rootPath, file.Name())
2020-06-23 18:42:27 +08:00
f, err := os.Open(path)
if err != nil {
log(err.Error())
}
defer f.Close()
if !file.IsDir() {
filetype, err := GetFileContentType(f)
if err != nil {
log(err.Error())
}
// skip if not mp3 file
if filetype != "mpeg" {
continue
}
}
2020-06-19 16:22:20 +08:00
child := tview.NewTreeNode(file.Name())
root.AddChild(child)
audioFile := &AudioFile{
2020-06-19 16:42:30 +08:00
Name: file.Name(),
Path: path,
2020-06-19 16:22:20 +08:00
IsAudioFile: true,
2020-06-19 16:42:30 +08:00
Parent: root,
2020-06-19 16:22:20 +08:00
}
child.SetReference(audioFile)
if file.IsDir() {
audioFile.IsAudioFile = false
populate(child, path)
}
}
}
2020-06-25 10:46:45 +08:00
2020-06-26 12:54:48 +08:00
// add to queue and update queue panel
func (playlist *Playlist) addToQueue(audioFile *AudioFile) {
2020-06-25 10:46:45 +08:00
2020-06-25 14:12:19 +08:00
if audioFile.IsAudioFile {
2020-06-25 10:46:45 +08:00
2020-06-25 14:12:19 +08:00
if !player.IsRunning {
player.IsRunning = true
2020-06-26 12:54:48 +08:00
go func() {
queue.AddItem("", audioFile.Path, 0, nil)
2020-06-25 14:12:19 +08:00
player.Run()
2020-06-26 12:54:48 +08:00
}()
2020-06-25 14:12:19 +08:00
} else {
2020-06-26 12:54:48 +08:00
songLength, err := GetLength(audioFile.Path)
2020-06-25 14:12:19 +08:00
if err != nil {
log(err.Error())
}
2020-06-26 12:54:48 +08:00
queueItemView := fmt.Sprintf("[ %s ] %s", fmtDuration(songLength), audioFile.Name)
queue.AddItem(queueItemView, audioFile.Path, 0, nil)
}
2020-06-25 10:46:45 +08:00
}
2020-06-25 14:12:19 +08:00
}
2020-06-26 12:54:48 +08:00
// bulk add a playlist to queue
func (playlist *Playlist) addAllToQueue(root *tview.TreeNode) {
2020-06-25 14:12:19 +08:00
var childrens []*tview.TreeNode
2020-06-25 10:46:45 +08:00
2020-06-25 14:12:19 +08:00
childrens = root.GetChildren()
// gets the parent if highlighted item is a file
if len(childrens) == 0 {
childrens = root.GetReference().(*AudioFile).Parent.GetChildren()
2020-06-26 12:54:48 +08:00
}
2020-06-25 14:12:19 +08:00
for _, v := range childrens {
currNode := v.GetReference().(*AudioFile)
2020-06-26 12:54:48 +08:00
playlist.addToQueue(currNode)
2020-06-25 14:12:19 +08:00
}
2020-06-25 10:46:45 +08:00
}