commit
9390fbf46e
@ -1,8 +1,11 @@
|
||||
package main
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/fhs/gompd/mpd"
|
||||
|
||||
"strings"
|
||||
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
@ -10,10 +13,23 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
CONN *mpd.Client
|
||||
ArtistTree map[string]map[string]map[string]string
|
||||
NotificationServer interface {
|
||||
Send(string)
|
||||
}
|
||||
WHITE_AND_BOLD string = "[#ffffff::b]"
|
||||
)
|
||||
|
||||
func togglePlayBack() error {
|
||||
func SetConnection(c *mpd.Client) {
|
||||
CONN = c
|
||||
}
|
||||
|
||||
func SetNotificationServer(n interface{ Send(string) }) {
|
||||
NotificationServer = n
|
||||
}
|
||||
|
||||
func TogglePlayBack() error {
|
||||
status, err := CONN.Status()
|
||||
if status["state"] == "play" && err == nil {
|
||||
CONN.Pause(true)
|
||||
@ -39,32 +55,30 @@ func UpdatePlaylist(inputTable *tview.Table) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The GenerateContentSlice returns a slice of the content to be displayed on the Search View. The Slice is generated
|
||||
because the random nature of maps as they return values randomly hence the draw function keeps changing the order
|
||||
in which the results.
|
||||
*/
|
||||
// The GenerateContentSlice returns a slice of the content to be displayed on the Search View. The Slice is generated
|
||||
// because the random nature of maps as they return values randomly hence the draw function keeps changing the order
|
||||
// in which the results appear.
|
||||
func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
|
||||
var ContentSlice []interface{}
|
||||
if strings.TrimRight(selectedSuggestion, " ") == "" {
|
||||
NOTIFICATION_SERVER.Send("Empty Search!")
|
||||
NotificationServer.Send("Empty Search!")
|
||||
return nil, errors.New("empty Search String Provided")
|
||||
}
|
||||
if _, ok := ARTIST_TREE[selectedSuggestion]; ok {
|
||||
if _, ok := ArtistTree[selectedSuggestion]; ok {
|
||||
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Artists :")
|
||||
ContentSlice = append(ContentSlice, selectedSuggestion)
|
||||
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Artist Albums :")
|
||||
for albumName := range ARTIST_TREE[selectedSuggestion] {
|
||||
for albumName := range ArtistTree[selectedSuggestion] {
|
||||
ContentSlice = append(ContentSlice, [2]string{albumName, selectedSuggestion})
|
||||
}
|
||||
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Artist Tracks :")
|
||||
for albumName, trackList := range ARTIST_TREE[selectedSuggestion] {
|
||||
for albumName, trackList := range ArtistTree[selectedSuggestion] {
|
||||
for track := range trackList {
|
||||
ContentSlice = append(ContentSlice, [3]string{track, selectedSuggestion, albumName})
|
||||
}
|
||||
}
|
||||
}
|
||||
if aMap := QueryArtistTreeForAlbums(ARTIST_TREE, selectedSuggestion); len(aMap) != 0 {
|
||||
if aMap := QueryArtistTreeForAlbums(ArtistTree, selectedSuggestion); len(aMap) != 0 {
|
||||
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Albums :")
|
||||
for mSlice := range aMap {
|
||||
ContentSlice = append(ContentSlice, mSlice)
|
||||
@ -76,7 +90,7 @@ func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if tMap := QueryArtistTreeForTracks(ARTIST_TREE, selectedSuggestion); len(tMap) != 0 {
|
||||
if tMap := QueryArtistTreeForTracks(ArtistTree, selectedSuggestion); len(tMap) != 0 {
|
||||
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Tracks :")
|
||||
for mSlice := range tMap {
|
||||
ContentSlice = append(ContentSlice, mSlice)
|
||||
@ -85,11 +99,9 @@ func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
|
||||
return ContentSlice, nil
|
||||
}
|
||||
|
||||
/*
|
||||
UpdateSearchView as the name suggests Updates the Search View the idea is to basically keep a fourth option called
|
||||
Search in the Navigation bar which will render things from a global ContentSlice at least in the context of the main
|
||||
function this will also help in persisting the Search Results.
|
||||
*/
|
||||
// UpdateSearchView as the name suggests Updates the Search View the idea is to basically keep a fourth option called
|
||||
// Search in the Navigation bar which will render things from a global ContentSlice at least in the context of the main
|
||||
// function this will also help in persisting the Search Results.
|
||||
func UpdateSearchView(inputTable *tview.Table, c []interface{}) {
|
||||
inputTable.Clear()
|
||||
_, _, width, _ := inputTable.GetInnerRect()
|
||||
@ -122,8 +134,8 @@ func UpdateSearchView(inputTable *tview.Table, c []interface{}) {
|
||||
func Update(f []FileNode, inputTable *tview.Table) {
|
||||
inputTable.Clear()
|
||||
for i, j := range f {
|
||||
if len(j.children) == 0 {
|
||||
_songAttributes, err := CONN.ListAllInfo(j.absolutePath)
|
||||
if len(j.Children) == 0 {
|
||||
_songAttributes, err := CONN.ListAllInfo(j.AbsolutePath)
|
||||
if err == nil && _songAttributes[0]["Title"] != "" {
|
||||
_, _, w, _ := inputTable.GetInnerRect()
|
||||
inputTable.SetCell(i, 0,
|
||||
@ -140,19 +152,21 @@ func Update(f []FileNode, inputTable *tview.Table) {
|
||||
|
||||
} else if _songAttributes[0]["Title"] == "" {
|
||||
inputTable.SetCell(i, 0,
|
||||
tview.NewTableCell("[blue]"+j.path).
|
||||
tview.NewTableCell("[blue]"+j.Path).
|
||||
SetAlign(tview.AlignLeft))
|
||||
}
|
||||
} else {
|
||||
inputTable.SetCell(i, 0,
|
||||
tview.NewTableCell("[yellow::b]"+j.path).
|
||||
tview.NewTableCell("[yellow::b]"+j.Path).
|
||||
SetAlign(tview.AlignLeft))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateArtistTree Artist Tree is a map of Artist to their Album Map
|
||||
// Album Tree is a map of the tracks in that particular album.
|
||||
func GenerateArtistTree() (map[string]map[string]map[string]string, error) {
|
||||
ArtistTree := make(map[string]map[string]map[string]string)
|
||||
ArtistTree = make(map[string]map[string]map[string]string)
|
||||
AllInfo, err := CONN.ListAllInfo("/")
|
||||
if err == nil {
|
||||
for _, i := range AllInfo {
|
||||
@ -184,56 +198,50 @@ func PrintArtistTree(a map[string]map[string]map[string]string) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Adds All tracks from a specified album to a playlist
|
||||
*/
|
||||
// Adds All tracks from a specified album to a playlist
|
||||
func AddAlbum(a map[string]map[string]map[string]string, alb string, artist string) {
|
||||
for _, v := range a[artist][alb] {
|
||||
err := CONN.Add(v)
|
||||
if err != nil {
|
||||
NOTIFICATION_SERVER.Send("Could Not Add Song : " + v)
|
||||
NotificationServer.Send("Could Not Add Song : " + v)
|
||||
}
|
||||
}
|
||||
NOTIFICATION_SERVER.Send("Album Added : " + alb)
|
||||
NotificationServer.Send("Album Added : " + alb)
|
||||
}
|
||||
|
||||
/*
|
||||
Adds All tracks from a specified artist to a playlist
|
||||
*/
|
||||
// Adds All tracks from a specified artist to a playlist
|
||||
func AddArtist(a map[string]map[string]map[string]string, artist string) {
|
||||
if val, ok := a[artist]; ok {
|
||||
for _, v := range val {
|
||||
for _, path := range v {
|
||||
err := CONN.Add(path)
|
||||
if err != nil {
|
||||
NOTIFICATION_SERVER.Send("Could Not Add Song : " + path)
|
||||
NotificationServer.Send("Could Not Add Song : " + path)
|
||||
}
|
||||
}
|
||||
}
|
||||
NOTIFICATION_SERVER.Send("Artist Added : " + artist)
|
||||
NotificationServer.Send("Artist Added : " + artist)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Adds Specified Track to the Playlist
|
||||
*/
|
||||
// Adds Specified Track to the Playlist
|
||||
func AddTitle(a map[string]map[string]map[string]string, artist, alb, track string, addAndPlay bool) {
|
||||
if addAndPlay {
|
||||
id, err := CONN.AddId(a[artist][alb][track], -1)
|
||||
CONN.PlayId(id)
|
||||
if err != nil {
|
||||
NOTIFICATION_SERVER.Send("Could Not Add Track : " + track)
|
||||
NotificationServer.Send("Could Not Add Track : " + track)
|
||||
}
|
||||
} else {
|
||||
err := CONN.Add(a[artist][alb][track])
|
||||
if err != nil {
|
||||
NOTIFICATION_SERVER.Send("Could Not Add Track : " + track)
|
||||
NotificationServer.Send("Could Not Add Track : " + track)
|
||||
}
|
||||
}
|
||||
NOTIFICATION_SERVER.Send("Track Added : " + track)
|
||||
NotificationServer.Send("Track Added : " + track)
|
||||
}
|
||||
|
||||
/* Querys the Artist Tree for a track and returns a TrackMap (i.e [3]string{artist, album, track} -> path) which will help us
|
||||
/* Querys the Artist Tree for a track and returns a TrackMap (i.e [3]string{artist, album, track} -> Path) which will help us
|
||||
to add tracks to the playlist */
|
||||
func QueryArtistTreeForTracks(a map[string]map[string]map[string]string, track string) map[[3]string]string {
|
||||
TrackMap := make(map[[3]string]string)
|
||||
@ -249,7 +257,7 @@ func QueryArtistTreeForTracks(a map[string]map[string]map[string]string, track s
|
||||
return TrackMap
|
||||
}
|
||||
|
||||
/* Querys the Artist Tree for an album and returns a AlbumMap (i.e [3]string{artist, album } ->[]path of songs in the album)
|
||||
/* Querys the Artist Tree for an album and returns a AlbumMap (i.e [3]string{artist, album } ->[]Path of songs in the album)
|
||||
which will help us to add all album tracks to the playlist */
|
||||
func QueryArtistTreeForAlbums(a map[string]map[string]map[string]string, album string) map[[2]string][][2]string {
|
||||
AlbumMap := make(map[[2]string][][2]string)
|
||||
@ -272,17 +280,17 @@ func AddToPlaylist(a interface{}, addAndPlay bool) {
|
||||
case [3]string:
|
||||
{
|
||||
b := a.([3]string)
|
||||
AddTitle(ARTIST_TREE, b[1], b[2], b[0], addAndPlay)
|
||||
AddTitle(ArtistTree, b[1], b[2], b[0], addAndPlay)
|
||||
}
|
||||
case [2]string:
|
||||
{
|
||||
b := a.([2]string)
|
||||
AddAlbum(ARTIST_TREE, b[0], b[1])
|
||||
AddAlbum(ArtistTree, b[0], b[1])
|
||||
}
|
||||
case string:
|
||||
{
|
||||
b := a.(string)
|
||||
AddArtist(ARTIST_TREE, b)
|
||||
AddArtist(ArtistTree, b)
|
||||
}
|
||||
}
|
||||
}
|
69
client/files.go
Normal file
69
client/files.go
Normal file
@ -0,0 +1,69 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FileNode struct {
|
||||
Children []FileNode
|
||||
Path string
|
||||
Parent *FileNode
|
||||
AbsolutePath string
|
||||
}
|
||||
|
||||
func (f *FileNode) AddChildren(path string) {
|
||||
if f.Path != "" {
|
||||
f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + "/" + path})
|
||||
} else {
|
||||
f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + path})
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileNode) AddChildNode(m FileNode) {
|
||||
m.Parent = f
|
||||
f.Children = append(f.Children, m)
|
||||
}
|
||||
|
||||
func GenerateDirectoryTree(path []string) *FileNode {
|
||||
var head *FileNode = new(FileNode)
|
||||
var head1 *FileNode = head
|
||||
for i := range path {
|
||||
sepPaths := strings.Split(path[i], "/")
|
||||
for j := range sepPaths {
|
||||
if len(head.Children) == 0 {
|
||||
head.AddChildren(sepPaths[j])
|
||||
head = &(head.Children[len(head.Children)-1])
|
||||
} else {
|
||||
var headIsChanged = false
|
||||
for k := range head.Children {
|
||||
if head.Children[k].Path == sepPaths[j] {
|
||||
head = &(head.Children[k])
|
||||
headIsChanged = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !headIsChanged {
|
||||
head.AddChildren(sepPaths[j])
|
||||
head = &(head.Children[len(head.Children)-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
head = head1
|
||||
}
|
||||
return head
|
||||
}
|
||||
|
||||
func (f FileNode) Print(count int) {
|
||||
if len(f.Children) == 0 {
|
||||
return
|
||||
} else {
|
||||
for i := range f.Children {
|
||||
for j := 0; j < count; j++ {
|
||||
fmt.Print("---")
|
||||
}
|
||||
fmt.Println(f.Children[i].AbsolutePath)
|
||||
f.Children[i].Print(count + 1)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FileNode struct {
|
||||
children []FileNode
|
||||
path string
|
||||
parent *FileNode
|
||||
absolutePath string
|
||||
}
|
||||
|
||||
func (f *FileNode) addChildren(path string) {
|
||||
if f.path != "" {
|
||||
f.children = append(f.children, FileNode{children: make([]FileNode, 0), path: path, parent: f, absolutePath: f.absolutePath + "/" + path})
|
||||
} else {
|
||||
f.children = append(f.children, FileNode{children: make([]FileNode, 0), path: path, parent: f, absolutePath: f.absolutePath + path})
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileNode) addChildNode(m FileNode) {
|
||||
m.parent = f
|
||||
f.children = append(f.children, m)
|
||||
}
|
||||
|
||||
func generateDirectoryTree(path []string) *FileNode {
|
||||
var head *FileNode = new(FileNode)
|
||||
var head1 *FileNode = head
|
||||
for i := range path {
|
||||
sepPaths := strings.Split(path[i], "/")
|
||||
for j := range sepPaths {
|
||||
if len(head.children) == 0 {
|
||||
head.addChildren(sepPaths[j])
|
||||
head = &(head.children[len(head.children)-1])
|
||||
} else {
|
||||
var headIsChanged = false
|
||||
for k := range head.children {
|
||||
if head.children[k].path == sepPaths[j] {
|
||||
head = &(head.children[k])
|
||||
headIsChanged = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !headIsChanged {
|
||||
head.addChildren(sepPaths[j])
|
||||
head = &(head.children[len(head.children)-1])
|
||||
}
|
||||
}
|
||||
}
|
||||
head = head1
|
||||
}
|
||||
return head
|
||||
}
|
||||
|
||||
func (f FileNode) Print(count int) {
|
||||
if len(f.children) == 0 {
|
||||
return
|
||||
} else {
|
||||
for i := range f.children {
|
||||
for j := 0; j < count; j++ {
|
||||
fmt.Print("---")
|
||||
}
|
||||
fmt.Println(f.children[i].absolutePath)
|
||||
f.children[i].Print(count + 1)
|
||||
}
|
||||
}
|
||||
}
|
172
main.go
172
main.go
@ -4,6 +4,12 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/aditya-K2/gomp/ui/notify"
|
||||
|
||||
"github.com/aditya-K2/gomp/render"
|
||||
"github.com/aditya-K2/gomp/ui"
|
||||
|
||||
"github.com/aditya-K2/gomp/client"
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
|
||||
"github.com/aditya-K2/fuzzy"
|
||||
@ -14,92 +20,110 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
CONN *mpd.Client
|
||||
UI *Application
|
||||
NOTIFICATION_SERVER *NotificationServer
|
||||
Volume int64
|
||||
Random bool
|
||||
Repeat bool
|
||||
InsidePlaylist bool = true
|
||||
InsideSearchView bool = false
|
||||
ARTIST_TREE map[string]map[string]map[string]string
|
||||
)
|
||||
|
||||
func main() {
|
||||
config.ReadConfig()
|
||||
// Connect to MPD server
|
||||
var mpdConnectionError error
|
||||
CONN, mpdConnectionError = mpd.Dial("tcp", "localhost:"+viper.GetString("MPD_PORT"))
|
||||
CONN, mpdConnectionError := mpd.Dial("tcp", "localhost:"+viper.GetString("MPD_PORT"))
|
||||
if mpdConnectionError != nil {
|
||||
panic(mpdConnectionError)
|
||||
}
|
||||
defer CONN.Close()
|
||||
|
||||
ui.GenerateFocusMap()
|
||||
|
||||
client.SetConnection(CONN)
|
||||
ui.SetConnection(CONN)
|
||||
render.SetConnection(CONN)
|
||||
|
||||
cache.SetCacheDir(viper.GetString("CACHE_DIR"))
|
||||
r := newRenderer()
|
||||
|
||||
Renderer := render.NewRenderer()
|
||||
// Connecting the Renderer to the Main UI
|
||||
ui.ConnectRenderer(Renderer)
|
||||
|
||||
c, _ := CONN.CurrentSong()
|
||||
if len(c) != 0 {
|
||||
r.Start(c["file"])
|
||||
Renderer.Start(c["file"])
|
||||
} else {
|
||||
r.Start("stop")
|
||||
Renderer.Start("stop")
|
||||
}
|
||||
|
||||
UI = newApplication(r)
|
||||
UI := ui.NewApplication()
|
||||
|
||||
// Connecting the Notification Server to the Main UI
|
||||
notify.ConnectUI(UI)
|
||||
|
||||
fileMap, err := CONN.GetFiles()
|
||||
dirTree := generateDirectoryTree(fileMap)
|
||||
|
||||
UpdatePlaylist(UI.ExpandedView)
|
||||
// Generating the Directory Tree for File Navigation.
|
||||
dirTree := client.GenerateDirectoryTree(fileMap)
|
||||
|
||||
// Default View upon Opening is of Playlist.
|
||||
client.UpdatePlaylist(UI.ExpandedView)
|
||||
|
||||
_v, _ := CONN.Status()
|
||||
Volume, _ = strconv.ParseInt(_v["volume"], 10, 64)
|
||||
Random, _ = strconv.ParseBool(_v["random"])
|
||||
Repeat, _ = strconv.ParseBool(_v["repeat"])
|
||||
// Setting Volume, Random and Repeat Values
|
||||
Volume, _ := strconv.ParseInt(_v["volume"], 10, 64)
|
||||
Random, _ := strconv.ParseBool(_v["random"])
|
||||
Repeat, _ := strconv.ParseBool(_v["repeat"])
|
||||
|
||||
ARTIST_TREE, err = GenerateArtistTree()
|
||||
ARTIST_TREE_CONTENT := utils.ConvertToArray(ARTIST_TREE)
|
||||
NOTIFICATION_SERVER = NewNotificationServer()
|
||||
NOTIFICATION_SERVER.Start()
|
||||
ArtistTree, err := client.GenerateArtistTree()
|
||||
|
||||
var SEARCH_CONTENT_SLICE []interface{}
|
||||
// Used for Fuzzy Searching
|
||||
ArtistTreeContent := utils.ConvertToArray(ArtistTree)
|
||||
|
||||
Notify := notify.NewNotificationServer()
|
||||
Notify.Start()
|
||||
|
||||
// Connecting Notification Server to Client and Rendering Module so that they can send Notifications
|
||||
client.SetNotificationServer(Notify)
|
||||
render.SetNotificationServer(Notify)
|
||||
|
||||
// This is the Slice that is used to Display Content in the SearchView
|
||||
var SearchContentSlice []interface{}
|
||||
|
||||
// This Function Is Responsible for Changing the Focus it uses the Focus Map and Based on it Chooses
|
||||
// the Draw Function
|
||||
UI.ExpandedView.SetDrawFunc(func(s tcell.Screen, x, y, width, height int) (int, int, int, int) {
|
||||
if InsidePlaylist {
|
||||
UpdatePlaylist(UI.ExpandedView)
|
||||
} else if InsideSearchView {
|
||||
UpdateSearchView(UI.ExpandedView, SEARCH_CONTENT_SLICE)
|
||||
} else {
|
||||
Update(dirTree.children, UI.ExpandedView)
|
||||
if ui.HasFocus("Playlist") {
|
||||
client.UpdatePlaylist(UI.ExpandedView)
|
||||
} else if ui.HasFocus("SearchView") {
|
||||
client.UpdateSearchView(UI.ExpandedView, SearchContentSlice)
|
||||
} else if ui.HasFocus("FileBrowser") {
|
||||
client.Update(dirTree.Children, UI.ExpandedView)
|
||||
}
|
||||
return UI.ExpandedView.GetInnerRect()
|
||||
})
|
||||
|
||||
var FUNC_MAP = map[string]func(){
|
||||
// Function Maps is used For Mapping Keys According to the Value mapped to the Key the respective Function is called
|
||||
// For e.g. in the config if the User Maps T to togglePlayBack then whenever in the input handler the T is received
|
||||
// the respective function in this case togglePlayBack is called.
|
||||
var FuncMap = map[string]func(){
|
||||
"showChildrenContent": func() {
|
||||
r, _ := UI.ExpandedView.GetSelection()
|
||||
if !InsidePlaylist && !InsideSearchView {
|
||||
if len(dirTree.children[r].children) == 0 {
|
||||
id, _ := CONN.AddId(dirTree.children[r].absolutePath, -1)
|
||||
if ui.HasFocus("FileBrowser") {
|
||||
if len(dirTree.Children[r].Children) == 0 {
|
||||
id, _ := CONN.AddId(dirTree.Children[r].AbsolutePath, -1)
|
||||
CONN.PlayId(id)
|
||||
} else {
|
||||
Update(dirTree.children[r].children, UI.ExpandedView)
|
||||
dirTree = &dirTree.children[r]
|
||||
client.Update(dirTree.Children[r].Children, UI.ExpandedView)
|
||||
dirTree = &dirTree.Children[r]
|
||||
}
|
||||
} else if InsidePlaylist {
|
||||
} else if ui.HasFocus("Playlist") {
|
||||
CONN.Play(r)
|
||||
} else if InsideSearchView {
|
||||
} else if ui.HasFocus("SearchView") {
|
||||
r, _ := UI.ExpandedView.GetSelection()
|
||||
AddToPlaylist(SEARCH_CONTENT_SLICE[r], true)
|
||||
client.AddToPlaylist(SearchContentSlice[r], true)
|
||||
}
|
||||
},
|
||||
"togglePlayBack": func() {
|
||||
togglePlayBack()
|
||||
client.TogglePlayBack()
|
||||
},
|
||||
"showParentContent": func() {
|
||||
if !InsidePlaylist && !InsideSearchView {
|
||||
if dirTree.parent != nil {
|
||||
Update(dirTree.parent.children, UI.ExpandedView)
|
||||
dirTree = dirTree.parent
|
||||
if ui.HasFocus("FileBrowser") {
|
||||
if dirTree.Parent != nil {
|
||||
client.Update(dirTree.Parent.Children, UI.ExpandedView)
|
||||
dirTree = dirTree.Parent
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -108,18 +132,18 @@ func main() {
|
||||
},
|
||||
"clearPlaylist": func() {
|
||||
CONN.Clear()
|
||||
NOTIFICATION_SERVER.Send("PlayList Cleared")
|
||||
Notify.Send("Playlist Cleared")
|
||||
},
|
||||
"previousSong": func() {
|
||||
CONN.Previous()
|
||||
},
|
||||
"addToPlaylist": func() {
|
||||
if !InsidePlaylist && !InsideSearchView {
|
||||
if ui.HasFocus("FileBrowser") {
|
||||
r, _ := UI.ExpandedView.GetSelection()
|
||||
CONN.Add(dirTree.children[r].absolutePath)
|
||||
} else if InsideSearchView {
|
||||
CONN.Add(dirTree.Children[r].AbsolutePath)
|
||||
} else if ui.HasFocus("SearchView") {
|
||||
r, _ := UI.ExpandedView.GetSelection()
|
||||
AddToPlaylist(SEARCH_CONTENT_SLICE[r], false)
|
||||
client.AddToPlaylist(SearchContentSlice[r], false)
|
||||
}
|
||||
},
|
||||
"toggleRandom": func() {
|
||||
@ -151,25 +175,20 @@ func main() {
|
||||
CONN.SetVolume(int(Volume))
|
||||
},
|
||||
"navigateToFiles": func() {
|
||||
InsidePlaylist = false
|
||||
InsideSearchView = false
|
||||
ui.SetFocus("FileBrowser")
|
||||
UI.Navbar.Select(1, 0)
|
||||
Update(dirTree.children, UI.ExpandedView)
|
||||
client.Update(dirTree.Children, UI.ExpandedView)
|
||||
},
|
||||
"navigateToPlaylist": func() {
|
||||
InsidePlaylist = true
|
||||
InsideSearchView = false
|
||||
ui.SetFocus("Playlist")
|
||||
UI.Navbar.Select(0, 0)
|
||||
UpdatePlaylist(UI.ExpandedView)
|
||||
client.UpdatePlaylist(UI.ExpandedView)
|
||||
},
|
||||
"navigateToMostPlayed": func() {
|
||||
InsideSearchView = false
|
||||
InsidePlaylist = false
|
||||
UI.Navbar.Select(2, 0)
|
||||
},
|
||||
"navigateToSearch": func() {
|
||||
InsideSearchView = true
|
||||
InsidePlaylist = false
|
||||
ui.SetFocus("SearchView")
|
||||
UI.Navbar.Select(3, 0)
|
||||
},
|
||||
"quit": func() {
|
||||
@ -177,17 +196,17 @@ func main() {
|
||||
},
|
||||
"stop": func() {
|
||||
CONN.Stop()
|
||||
NOTIFICATION_SERVER.Send("Playback Stopped")
|
||||
Notify.Send("Playback Stopped")
|
||||
},
|
||||
"updateDB": func() {
|
||||
_, err = CONN.Update("")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
NOTIFICATION_SERVER.Send("Database Updated")
|
||||
Notify.Send("Database Updated")
|
||||
},
|
||||
"deleteSongFromPlaylist": func() {
|
||||
if InsidePlaylist {
|
||||
if ui.HasFocus("Playlist") {
|
||||
r, _ := UI.ExpandedView.GetSelection()
|
||||
CONN.Delete(r, -1)
|
||||
}
|
||||
@ -197,12 +216,15 @@ func main() {
|
||||
},
|
||||
}
|
||||
|
||||
config.GenerateKeyMap(FUNC_MAP)
|
||||
// Generating the Key Map Based on the Function Map Here Basically the Values will be flipped
|
||||
// In the config if togglePlayBack is mapped to [ T , P, SPACE ] then here Basically we will receive a map
|
||||
// for each event T, P, SPACE mapped to the same function togglePlayBack
|
||||
config.GenerateKeyMap(FuncMap)
|
||||
|
||||
UI.SearchBar.SetAutocompleteFunc(func(c string) []string {
|
||||
if c != "" && c != " " && c != " " {
|
||||
_, _, w, _ := UI.SearchBar.GetRect()
|
||||
matches := fuzzy.Find(c, ARTIST_TREE_CONTENT)
|
||||
matches := fuzzy.Find(c, ArtistTreeContent)
|
||||
var suggestions []string
|
||||
for i, match := range matches {
|
||||
if i == 10 {
|
||||
@ -216,9 +238,10 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
// Input Handler
|
||||
UI.ExpandedView.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
|
||||
if val, ok := config.KEY_MAP[int(e.Rune())]; ok {
|
||||
FUNC_MAP[val]()
|
||||
FuncMap[val]()
|
||||
return nil
|
||||
} else {
|
||||
return e
|
||||
@ -228,12 +251,11 @@ func main() {
|
||||
UI.SearchBar.SetDoneFunc(func(e tcell.Key) {
|
||||
if e == tcell.KeyEnter {
|
||||
UI.ExpandedView.Select(0, 0)
|
||||
InsideSearchView = true
|
||||
InsidePlaylist = false
|
||||
SEARCH_CONTENT_SLICE = nil
|
||||
SEARCH_CONTENT_SLICE, err = GenerateContentSlice(UI.SearchBar.GetText())
|
||||
ui.SetFocus("SearchView")
|
||||
SearchContentSlice = nil
|
||||
SearchContentSlice, err = client.GenerateContentSlice(UI.SearchBar.GetText())
|
||||
if err != nil {
|
||||
NOTIFICATION_SERVER.Send("Could Not Retrieve the Results")
|
||||
Notify.Send("Could Not Retrieve the Results")
|
||||
} else {
|
||||
UI.SearchBar.SetText("")
|
||||
UI.App.SetFocus(UI.ExpandedView)
|
||||
@ -241,7 +263,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
if e == tcell.KeyEscape {
|
||||
InsideSearchView = false
|
||||
ui.FocusMap["SearchView"] = false
|
||||
UI.App.SetFocus(UI.ExpandedView)
|
||||
}
|
||||
})
|
||||
|
122
render.go
122
render.go
@ -1,122 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"os"
|
||||
|
||||
"github.com/aditya-K2/gomp/cache"
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/spf13/viper"
|
||||
"gitlab.com/diamondburned/ueberzug-go"
|
||||
)
|
||||
|
||||
/*
|
||||
Renderer is just a channel on which we will send the Path to the song whose
|
||||
Image is to be Rendered. This channel is passed to the openImage which in turn is called
|
||||
by the Start() function as a go routine.
|
||||
*/
|
||||
type Renderer struct {
|
||||
c chan string
|
||||
}
|
||||
|
||||
/*
|
||||
Returns a new Renderer with a string channel
|
||||
*/
|
||||
func newRenderer() *Renderer {
|
||||
c := make(chan string)
|
||||
return &Renderer{
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Send Image Path to Renderer
|
||||
*/
|
||||
func (self *Renderer) Send(path string) {
|
||||
self.c <- path
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Go Routine that will Be Called and will listen on the channel c
|
||||
for changes and on getting a string over the channel will open the Image and
|
||||
keep listening again. This will keep the image blocked ( i.e no need to use time.Sleep() etc. )
|
||||
and saves resources too.
|
||||
|
||||
*/
|
||||
func openImage(path string, c chan string) {
|
||||
fw, fh := utils.GetFontWidth()
|
||||
var im *ueberzug.Image
|
||||
if path != "stop" {
|
||||
extractedImage := getImagePath(path)
|
||||
img2, _ := GetImg(extractedImage)
|
||||
im, _ = ueberzug.NewImage(img2, int(float32(IMG_X)*fw)+viper.GetInt("ADDITIONAL_PADDING_X"), int(float32(IMG_Y)*fh)+viper.GetInt("ADDITIONAL_PADDING_Y"))
|
||||
}
|
||||
d := <-c
|
||||
if im != nil {
|
||||
im.Clear()
|
||||
}
|
||||
if d != "stop" {
|
||||
openImage(d, c)
|
||||
} else {
|
||||
openImage("stop", c)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Initialises the Renderer and calls the go routine openImage and passes the channel
|
||||
as argument.
|
||||
*/
|
||||
func (self *Renderer) Start(path string) {
|
||||
go openImage(path, self.c)
|
||||
}
|
||||
|
||||
/*
|
||||
This Function returns the path to the image that is to be rendered it checks first for the image in the cache
|
||||
else it adds the image to the cache and then extracts it and renders it.
|
||||
*/
|
||||
func getImagePath(path string) string {
|
||||
a, err := CONN.ListInfo(path)
|
||||
var extractedImage string
|
||||
if err == nil && len(a) != 0 {
|
||||
if cache.Exists(a[0]["artist"], a[0]["album"]) {
|
||||
extractedImage = cache.GenerateName(a[0]["artist"], a[0]["album"])
|
||||
} else {
|
||||
imagePath := cache.GenerateName(a[0]["artist"], a[0]["album"])
|
||||
absPath := utils.CheckDirectoryFmt(viper.GetString("MUSIC_DIRECTORY")) + path
|
||||
extractedImage = utils.ExtractImageFromFile(absPath, imagePath)
|
||||
if extractedImage == viper.GetString("DEFAULT_IMAGE_PATH") && viper.GetString("GET_COVER_ART_FROM_LAST_FM") == "TRUE" {
|
||||
downloadedImage, err := getImageFromLastFM(a[0]["artist"], a[0]["album"], imagePath)
|
||||
if err == nil {
|
||||
NOTIFICATION_SERVER.Send("Image From LastFM")
|
||||
extractedImage = downloadedImage
|
||||
} else {
|
||||
NOTIFICATION_SERVER.Send("Falling Back to Default Image.")
|
||||
}
|
||||
} else {
|
||||
NOTIFICATION_SERVER.Send("Extracted Image Successfully")
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedImage
|
||||
}
|
||||
|
||||
func GetImg(uri string) (image.Image, error) {
|
||||
f, err := os.Open(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fw, fh := utils.GetFontWidth()
|
||||
img = resize.Resize(
|
||||
uint(float32(IMG_W)*(fw+float32(viper.GetFloat64("IMAGE_WIDTH_EXTRA_X")))), uint(float32(IMG_H)*(fh+float32(viper.GetFloat64("IMAGE_WIDTH_EXTRA_Y")))),
|
||||
img,
|
||||
resize.Bilinear,
|
||||
)
|
||||
return img, nil
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package utils
|
||||
package render
|
||||
|
||||
import (
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -67,17 +68,17 @@ func ExtractImageFromFile(uri string, imagePath string) string {
|
||||
if strings.HasSuffix(uri, ".mp3") {
|
||||
imagePath := GetMp3Image(uri, imagePath)
|
||||
if imagePath == "" {
|
||||
Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i)
|
||||
utils.Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i)
|
||||
return viper.GetString("DEFAULT_IMAGE_PATH")
|
||||
}
|
||||
} else if strings.HasSuffix(uri, ".flac") {
|
||||
imagePath := GetFlacImage(uri, imagePath)
|
||||
if imagePath == "" {
|
||||
Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i)
|
||||
utils.Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i)
|
||||
return viper.GetString("DEFAULT_IMAGE_PATH")
|
||||
}
|
||||
} else {
|
||||
Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i)
|
||||
utils.Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i)
|
||||
return viper.GetString("DEFAULT_IMAGE_PATH")
|
||||
}
|
||||
return imagePath
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package render
|
||||
|
||||
import (
|
||||
"errors"
|
124
render/render.go
Normal file
124
render/render.go
Normal file
@ -0,0 +1,124 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"image"
|
||||
"os"
|
||||
|
||||
"github.com/aditya-K2/gomp/ui"
|
||||
"github.com/fhs/gompd/mpd"
|
||||
|
||||
"github.com/aditya-K2/gomp/cache"
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
"github.com/nfnt/resize"
|
||||
"github.com/spf13/viper"
|
||||
"gitlab.com/diamondburned/ueberzug-go"
|
||||
)
|
||||
|
||||
var (
|
||||
CONN *mpd.Client
|
||||
Notify interface{ Send(string) }
|
||||
)
|
||||
|
||||
func SetConnection(c *mpd.Client) {
|
||||
CONN = c
|
||||
}
|
||||
|
||||
func SetNotificationServer(n interface{ Send(string) }) {
|
||||
Notify = n
|
||||
}
|
||||
|
||||
// Renderer is just a channel on which we will send the Path to the song whose
|
||||
// Image is to be Rendered. This channel is passed to the OpenImage which in turn is called
|
||||
// by the Start() function as a go routine.
|
||||
type Renderer struct {
|
||||
c chan string
|
||||
}
|
||||
|
||||
// Returns a new Renderer with a string channel
|
||||
func NewRenderer() *Renderer {
|
||||
c := make(chan string)
|
||||
return &Renderer{
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Send Image Path to Renderer
|
||||
func (self *Renderer) Send(path string) {
|
||||
self.c <- path
|
||||
}
|
||||
|
||||
// Go Routine that will Be Called and will listen on the channel c
|
||||
// for changes and on getting a string over the channel will open the Image and
|
||||
// keep listening again. This will keep the image blocked ( i.e no need to use time.Sleep() etc. )
|
||||
// and saves resources too.
|
||||
func OpenImage(path string, c chan string) {
|
||||
fw, fh := utils.GetFontWidth()
|
||||
var im *ueberzug.Image
|
||||
if path != "stop" {
|
||||
extractedImage := GetImagePath(path)
|
||||
img2, _ := GetImg(extractedImage)
|
||||
im, _ = ueberzug.NewImage(img2, int(float32(ui.IMG_X)*fw)+viper.GetInt("ADDITIONAL_PADDING_X"), int(float32(ui.IMG_Y)*fh)+viper.GetInt("ADDITIONAL_PADDING_Y"))
|
||||
}
|
||||
d := <-c
|
||||
if im != nil {
|
||||
im.Clear()
|
||||
}
|
||||
if d != "stop" {
|
||||
OpenImage(d, c)
|
||||
} else {
|
||||
OpenImage("stop", c)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialises the Renderer and calls the go routine OpenImage and passes the channel
|
||||
// as argument.
|
||||
func (self *Renderer) Start(path string) {
|
||||
go OpenImage(path, self.c)
|
||||
}
|
||||
|
||||
// This Function returns the path to the image that is to be rendered it checks first for the image in the cache
|
||||
// else it adds the image to the cache and then extracts it and renders it.
|
||||
func GetImagePath(path string) string {
|
||||
a, err := CONN.ListInfo(path)
|
||||
var extractedImage string
|
||||
if err == nil && len(a) != 0 {
|
||||
if cache.Exists(a[0]["artist"], a[0]["album"]) {
|
||||
extractedImage = cache.GenerateName(a[0]["artist"], a[0]["album"])
|
||||
} else {
|
||||
imagePath := cache.GenerateName(a[0]["artist"], a[0]["album"])
|
||||
absPath := utils.CheckDirectoryFmt(viper.GetString("MUSIC_DIRECTORY")) + path
|
||||
extractedImage = ExtractImageFromFile(absPath, imagePath)
|
||||
if extractedImage == viper.GetString("DEFAULT_IMAGE_PATH") && viper.GetString("GET_COVER_ART_FROM_LAST_FM") == "TRUE" {
|
||||
downloadedImage, err := getImageFromLastFM(a[0]["artist"], a[0]["album"], imagePath)
|
||||
if err == nil {
|
||||
Notify.Send("Image From LastFM")
|
||||
extractedImage = downloadedImage
|
||||
} else {
|
||||
Notify.Send("Falling Back to Default Image.")
|
||||
}
|
||||
} else {
|
||||
Notify.Send("Extracted Image Successfully")
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedImage
|
||||
}
|
||||
|
||||
func GetImg(uri string) (image.Image, error) {
|
||||
f, err := os.Open(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fw, fh := utils.GetFontWidth()
|
||||
img = resize.Resize(
|
||||
uint(float32(ui.IMG_W)*(fw+float32(viper.GetFloat64("IMAGE_WIDTH_EXTRA_X")))), uint(float32(ui.IMG_H)*(fh+float32(viper.GetFloat64("IMAGE_WIDTH_EXTRA_Y")))),
|
||||
img,
|
||||
resize.Bilinear,
|
||||
)
|
||||
return img, nil
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package ui
|
||||
|
||||
import (
|
||||
"github.com/aditya-K2/tview"
|
||||
@ -16,9 +16,9 @@ type Application struct {
|
||||
Pages *tview.Pages
|
||||
}
|
||||
|
||||
func newApplication(r *Renderer) *Application {
|
||||
func NewApplication() *Application {
|
||||
|
||||
var pBar *progressBar = newProgressBar(r)
|
||||
var pBar *progressBar = newProgressBar()
|
||||
expandedView := tview.NewTable()
|
||||
Navbar := tview.NewTable()
|
||||
searchBar := tview.NewInputField()
|
||||
@ -60,7 +60,7 @@ func newApplication(r *Renderer) *Application {
|
||||
AddItem(searchBar, 3, 1, false).
|
||||
AddItem(sNavExpViewFlex, 0, 1, false)
|
||||
|
||||
mainFlex := tview.NewFlex().SetDirection(tview.FlexRow).
|
||||
lex := tview.NewFlex().SetDirection(tview.FlexRow).
|
||||
AddItem(searchBarFlex, 0, 8, false).
|
||||
AddItem(pBar.t, 5, 1, false)
|
||||
|
||||
@ -68,7 +68,7 @@ func newApplication(r *Renderer) *Application {
|
||||
expandedView.SetSelectable(true, false)
|
||||
|
||||
rootPages := tview.NewPages()
|
||||
rootPages.AddPage("Main", mainFlex, true, true)
|
||||
rootPages.AddPage("Main", lex, true, true)
|
||||
|
||||
App := tview.NewApplication()
|
||||
App.SetRoot(rootPages, true).SetFocus(expandedView)
|
24
ui/focus.go
Normal file
24
ui/focus.go
Normal file
@ -0,0 +1,24 @@
|
||||
package ui
|
||||
|
||||
// The Focus Map Helps to keep track of which UI Element Currently Has the Focus It can be queried to get the Current
|
||||
// UI Element with Focus and also can set UI Focus keep in mind that it isn't Focus Map that is Responsible to change
|
||||
// the Focus that is Done through the Update Function of UI.ExpandedView */
|
||||
var FocusMap map[string]bool
|
||||
|
||||
func GenerateFocusMap() {
|
||||
FocusMap = make(map[string]bool)
|
||||
FocusMap["Playlist"] = true
|
||||
FocusMap["FileBrowser"] = false
|
||||
FocusMap["SearchView"] = false
|
||||
}
|
||||
|
||||
func HasFocus(s string) bool {
|
||||
return FocusMap[s]
|
||||
}
|
||||
|
||||
func SetFocus(s string) {
|
||||
for k := range FocusMap {
|
||||
FocusMap[k] = false
|
||||
}
|
||||
FocusMap[s] = true
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/aditya-K2/gomp/ui"
|
||||
"time"
|
||||
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
@ -9,6 +10,14 @@ import (
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
UI *ui.Application
|
||||
)
|
||||
|
||||
func ConnectUI(a *ui.Application) {
|
||||
UI = a
|
||||
}
|
||||
|
||||
/* Notification Primitive */
|
||||
type Notification struct {
|
||||
*tview.Box
|
@ -1,16 +1,30 @@
|
||||
package main
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/fhs/gompd/mpd"
|
||||
|
||||
"github.com/aditya-K2/gomp/utils"
|
||||
|
||||
"github.com/aditya-K2/tview"
|
||||
"github.com/gdamore/tcell/v2"
|
||||
)
|
||||
|
||||
var CurrentSong string
|
||||
var (
|
||||
CurrentSong string
|
||||
CONN *mpd.Client
|
||||
RENDERER interface{ Send(string) }
|
||||
)
|
||||
|
||||
func SetConnection(c *mpd.Client) {
|
||||
CONN = c
|
||||
}
|
||||
|
||||
func ConnectRenderer(r interface{ Send(string) }) {
|
||||
RENDERER = r
|
||||
}
|
||||
|
||||
// The progressBar is just a string which is separated by the color formatting String
|
||||
// for e.g
|
||||
@ -26,7 +40,7 @@ type progressBar struct {
|
||||
// This Function returns a progressBar with a table of two rows
|
||||
// the First row will contain information about the current Song
|
||||
// and the Second one will contain the progressBar
|
||||
func newProgressBar(r *Renderer) *progressBar {
|
||||
func newProgressBar() *progressBar {
|
||||
p := progressBar{}
|
||||
|
||||
a := tview.NewTable().
|
||||
@ -38,7 +52,7 @@ func newProgressBar(r *Renderer) *progressBar {
|
||||
a.SetBorder(true)
|
||||
|
||||
a.SetDrawFunc(func(s tcell.Screen, x, y, width, height int) (int, int, int, int) {
|
||||
p.updateTitle(r)
|
||||
p.updateTitle()
|
||||
p.updateProgress()
|
||||
return p.t.GetInnerRect()
|
||||
})
|
||||
@ -49,16 +63,16 @@ func newProgressBar(r *Renderer) *progressBar {
|
||||
return &p
|
||||
}
|
||||
|
||||
func (s *progressBar) updateTitle(r *Renderer) {
|
||||
func (s *progressBar) updateTitle() {
|
||||
_currentAttributes, err := CONN.CurrentSong()
|
||||
if err == nil {
|
||||
song := "[green::bi]" + _currentAttributes["Title"] + "[-:-:-] - " + "[blue::b]" + _currentAttributes["Artist"] + "\n"
|
||||
s.t.GetCell(0, 0).Text = song
|
||||
if len(_currentAttributes) == 0 && CurrentSong != "" {
|
||||
CurrentSong = ""
|
||||
r.Send("stop")
|
||||
RENDERER.Send("stop")
|
||||
} else if song != CurrentSong && len(_currentAttributes) != 0 {
|
||||
r.Send(_currentAttributes["file"])
|
||||
RENDERER.Send(_currentAttributes["file"])
|
||||
CurrentSong = song
|
||||
}
|
||||
}
|
||||
@ -72,14 +86,28 @@ func (s *progressBar) updateProgress() {
|
||||
if du != 0 {
|
||||
percentage := el / du * 100
|
||||
if err == nil && err1 == nil {
|
||||
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]", utils.FormatString(_status["state"]), utils.FormatString(_status["random"]), utils.FormatString(_status["repeat"]), _status["volume"])).SetTitleAlign(tview.AlignRight)
|
||||
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]",
|
||||
utils.FormatString(_status["state"]),
|
||||
utils.FormatString(_status["random"]),
|
||||
utils.FormatString(_status["repeat"]),
|
||||
_status["volume"])).
|
||||
SetTitleAlign(tview.AlignRight)
|
||||
s.t.GetCell(2, 0).Text = utils.GetText(float64(_width), percentage, utils.StrTime(el)+"/"+utils.StrTime(du)+"("+strconv.FormatFloat(percentage, 'f', 2, 32)+"%"+")")
|
||||
} else {
|
||||
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s]", utils.FormatString(_status["state"]), utils.FormatString(_status["random"]), utils.FormatString(_status["repeat"]))).SetTitleAlign(tview.AlignRight)
|
||||
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s]",
|
||||
utils.FormatString(_status["state"]),
|
||||
utils.FormatString(_status["random"]),
|
||||
utils.FormatString(_status["repeat"]))).
|
||||
SetTitleAlign(tview.AlignRight)
|
||||
s.t.GetCell(2, 0).Text = ""
|
||||
}
|
||||
} else {
|
||||
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]", utils.FormatString(_status["state"]), utils.FormatString(_status["random"]), utils.FormatString(_status["repeat"]), _status["volume"])).SetTitleAlign(tview.AlignRight)
|
||||
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]",
|
||||
utils.FormatString(_status["state"]),
|
||||
utils.FormatString(_status["random"]),
|
||||
utils.FormatString(_status["repeat"]),
|
||||
_status["volume"])).
|
||||
SetTitleAlign(tview.AlignRight)
|
||||
s.t.GetCell(2, 0).Text = utils.GetText(float64(_width), 0, " ---:---")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user