gomu/queue.go
2020-07-10 16:52:37 +08:00

252 lines
4.3 KiB
Go

// Copyright (C) 2020 Raziman
package main
import (
"bufio"
"crypto/sha1"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"github.com/gdamore/tcell"
"github.com/rivo/tview"
)
type Queue struct {
*tview.List
SavedQueuePath string
Items []*AudioFile
}
// highlight the next item in the queue
func (q *Queue) next() {
currIndex := q.GetCurrentItem()
idx := currIndex + 1
if currIndex == q.GetItemCount()-1 {
idx = 0
}
q.SetCurrentItem(idx)
}
// highlight the previous item in the queue
func (q *Queue) prev() {
currIndex := q.GetCurrentItem()
q.SetCurrentItem(currIndex - 1)
}
// usually used with GetCurrentItem which can return -1 if
// no item highlighted
func (q *Queue) DeleteItem(index int) {
if index != -1 {
q.RemoveItem(index)
}
}
// gets the first item and remove it from the queue
// app.Draw() must be called after calling this function
func (q *Queue) Dequeue() (string, error) {
if q.GetItemCount() == 0 {
return "", errors.New("Empty list")
}
q.Items = q.Items[1:]
_, first := q.GetItemText(0)
q.DeleteItem(0)
return first, nil
}
// Add item to the list and returns the length of the queue
func (q *Queue) Enqueue(audioFile *AudioFile) int {
q.Items = append(q.Items, audioFile)
if !gomu.Player.IsRunning {
gomu.Player.IsRunning = true
go func() {
// we dont need the primary text as it will be popped anyway
q.AddItem("", audioFile.Path, 0, nil)
gomu.Player.Run()
}()
return q.GetItemCount()
}
songLength, err := GetLength(audioFile.Path)
if err != nil {
appLog(err)
}
queueItemView := fmt.Sprintf("[ %s ] %s", fmtDuration(songLength), GetName(audioFile.Name))
q.AddItem(queueItemView, audioFile.Path, 0, nil)
return q.GetItemCount()
}
// GetItems is used to get the secondary text
// which is used to store the path of the audio file
// this is for the sake of convenience
func (q *Queue) GetItems() []string {
items := []string{}
for i := 0; i < q.GetItemCount(); i++ {
_, second := q.GetItemText(i)
items = append(items, second)
}
return items
}
// Save the current queue in a csv file
func (q *Queue) SaveQueue() error {
songPaths := q.GetItems()
songNames := make([]string, 0, len(songPaths))
var content string
for _, songPath := range songPaths {
hashed := Sha1Hex(GetName(songPath))
songNames = append(songNames, hashed)
}
for _, v := range songNames {
content += v + "\n"
}
cachePath := expandTilde(q.SavedQueuePath)
err := ioutil.WriteFile(cachePath, []byte(content), 0644)
if err != nil {
return err
}
return nil
}
// Loads previously saved list
func (q *Queue) LoadQueue() error {
songs, err := q.GetSavedQueue()
if err != nil {
return err
}
for _, v := range songs {
audioFile := gomu.Playlist.FindAudioFile(v)
if audioFile != nil {
q.Enqueue(audioFile)
}
}
return nil
}
// Get saved queue, if not exist, create it
func (q *Queue) GetSavedQueue() ([]string, error) {
queuePath := expandTilde(q.SavedQueuePath)
if _, err := os.Stat(queuePath); os.IsNotExist(err) {
dir, _ := path.Split(queuePath)
err := os.MkdirAll(dir, 0744)
if err != nil {
return nil, err
}
_, err = os.Create(queuePath)
if err != nil {
return nil, err
}
return []string{}, nil
}
f, err := os.Open(queuePath)
if err != nil {
return nil, err
}
defer f.Close()
records := []string{}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
records = append(records, scanner.Text())
}
if err := scanner.Err(); err != nil {
return nil, err
}
return records, nil
}
// Initiliaze new queue with default values
func NewQueue() *Queue {
list := tview.NewList().
ShowSecondaryText(false)
queue := &Queue{
List: list,
SavedQueuePath: "~/.local/share/gomu/queue.cache",
Items: []*AudioFile{},
}
queue.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
switch e.Rune() {
case 'j':
queue.next()
case 'k':
queue.prev()
case 'd':
queue.DeleteItem(queue.GetCurrentItem())
}
return nil
})
queue.SetHighlightFullLine(true)
queue.SetBorder(true).SetTitle(" Queue ")
queue.SetSelectedBackgroundColor(tcell.ColorDarkCyan)
queue.SetSelectedTextColor(tcell.ColorWhite)
return queue
}
func Sha1Hex(input string) string {
h := sha1.New()
h.Write([]byte(input))
return hex.EncodeToString(h.Sum(nil))
}