Merge pull request #28 from aditya-K2/refactor

Seeking Functionality. Refactoring ProgressBar, FuncMap, and others
This commit is contained in:
Aditya Kurdunkar 2022-09-12 00:02:48 +05:30 committed by GitHub
commit bc794b3743
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 680 additions and 508 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ gomp
.idea .idea
*.jpg *.jpg
e.go e.go
.fuse*

View File

@ -4,34 +4,28 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/fhs/gompd/mpd" "github.com/aditya-K2/fuzzy"
"github.com/aditya-K2/gomp/notify"
"github.com/fhs/gompd/v2/mpd"
"strings" "strings"
) )
var ( var (
CONN *mpd.Client Conn *mpd.Client
ArtistTree map[string]map[string]map[string]string ArtistTree map[string]map[string]map[string]string
NotificationServer interface { WHITE_AND_BOLD string = "[white::b]"
Send(string) DirTree *FileNode
} Matches fuzzy.Matches
WHITE_AND_BOLD string = "[white::b]" SearchContentSlice []interface{}
) )
func SetConnection(c *mpd.Client) {
CONN = c
}
func SetNotificationServer(n interface{ Send(string) }) {
NotificationServer = n
}
func TogglePlayBack() error { func TogglePlayBack() error {
status, err := CONN.Status() status, err := Conn.Status()
if status["state"] == "play" && err == nil { if status["state"] == "play" && err == nil {
CONN.Pause(true) Conn.Pause(true)
} else if status["state"] == "pause" && err == nil { } else if status["state"] == "pause" && err == nil {
CONN.Play(-1) Conn.Play(-1)
} }
return err return err
} }
@ -42,7 +36,7 @@ func TogglePlayBack() error {
func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) { func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
var ContentSlice []interface{} var ContentSlice []interface{}
if strings.TrimRight(selectedSuggestion, " ") == "" { if strings.TrimRight(selectedSuggestion, " ") == "" {
NotificationServer.Send("Empty Search!") notify.Notify.Send("Empty Search!")
return nil, errors.New("empty Search String Provided") return nil, errors.New("empty Search String Provided")
} }
if _, ok := ArtistTree[selectedSuggestion]; ok { if _, ok := ArtistTree[selectedSuggestion]; ok {
@ -84,7 +78,7 @@ func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
// Album Tree is a map of the tracks in that particular album. // Album Tree is a map of the tracks in that particular album.
func GenerateArtistTree() (map[string]map[string]map[string]string, error) { 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("/") AllInfo, err := Conn.ListAllInfo("/")
if err == nil { if err == nil {
for _, i := range AllInfo { for _, i := range AllInfo {
if _, ArtistExists := ArtistTree[i["Artist"]]; !ArtistExists { if _, ArtistExists := ArtistTree[i["Artist"]]; !ArtistExists {
@ -118,12 +112,12 @@ 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) { func AddAlbum(a map[string]map[string]map[string]string, alb string, artist string) {
for _, v := range a[artist][alb] { for _, v := range a[artist][alb] {
err := CONN.Add(v) err := Conn.Add(v)
if err != nil { if err != nil {
NotificationServer.Send("Could Not Add Song : " + v) notify.Notify.Send("Could Not Add Song : " + v)
} }
} }
NotificationServer.Send("Album Added : " + alb) notify.Notify.Send("Album Added : " + alb)
} }
// Adds All tracks from a specified artist to a playlist // Adds All tracks from a specified artist to a playlist
@ -131,31 +125,31 @@ func AddArtist(a map[string]map[string]map[string]string, artist string) {
if val, ok := a[artist]; ok { if val, ok := a[artist]; ok {
for _, v := range val { for _, v := range val {
for _, path := range v { for _, path := range v {
err := CONN.Add(path) err := Conn.Add(path)
if err != nil { if err != nil {
NotificationServer.Send("Could Not Add Song : " + path) notify.Notify.Send("Could Not Add Song : " + path)
} }
} }
} }
NotificationServer.Send("Artist Added : " + artist) notify.Notify.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) { func AddTitle(a map[string]map[string]map[string]string, artist, alb, track string, addAndPlay bool) {
if addAndPlay { if addAndPlay {
id, err := CONN.AddId(a[artist][alb][track], -1) id, err := Conn.AddID(a[artist][alb][track], -1)
CONN.PlayId(id) Conn.PlayID(id)
if err != nil { if err != nil {
NotificationServer.Send("Could Not Add Track : " + track) notify.Notify.Send("Could Not Add Track : " + track)
} }
} else { } else {
err := CONN.Add(a[artist][alb][track]) err := Conn.Add(a[artist][alb][track])
if err != nil { if err != nil {
NotificationServer.Send("Could Not Add Track : " + track) notify.Notify.Send("Could Not Add Track : " + track)
} }
} }
NotificationServer.Send("Track Added : " + track) notify.Notify.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

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/fhs/gompd/mpd" "github.com/fhs/gompd/v2/mpd"
) )
type FileNode struct { type FileNode struct {

View File

@ -1,140 +0,0 @@
package client
import (
"strings"
"github.com/aditya-K2/fuzzy"
"github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview"
"github.com/gdamore/tcell/v2"
)
func GetCell(text string, foreground tcell.Color, bold bool) *tview.TableCell {
return tview.NewTableCell(text).
SetAlign(tview.AlignLeft).
SetStyle(tcell.StyleDefault.
Foreground(foreground).
Background(tcell.ColorBlack).
Bold(bold))
}
func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode) {
inputTable.Clear()
if m == nil || len(m) == 0 {
Update(f, inputTable)
} else {
for k, v := range m {
if len(f[v.Index].Children) != 0 {
inputTable.SetCell(k, 0,
GetCell(
utils.GetMatchedString(
utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[blue:-:bi]"),
tcell.ColorYellow, true))
} else {
inputTable.SetCell(k, 0,
GetCell(
utils.GetMatchedString(
utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[yellow:-:bi]"),
tcell.ColorGreen, true))
}
if k == 15 {
break
}
}
}
}
func UpdatePlaylist(inputTable *tview.Table) {
_playlistAttr, _ := CONN.PlaylistInfo(-1, -1)
inputTable.Clear()
for i, j := range _playlistAttr {
_, _, w, _ := inputTable.GetInnerRect()
if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" {
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(j["file"], w/3), tcell.ColorBlue, true))
} else {
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(j["Title"], w/3), tcell.ColorGreen, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(j["Artist"], w/3), tcell.ColorPurple, false))
inputTable.SetCell(i, 2,
GetCell(j["Album"], tcell.ColorYellow, false))
}
}
}
// 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()
for i, content := range c {
switch content.(type) {
case [3]string:
{
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(content.([3]string)[0], width/3), tcell.ColorGreen, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(content.([3]string)[1], width/3), tcell.ColorPurple, false))
inputTable.SetCell(i, 2,
GetCell(content.([3]string)[2], tcell.ColorYellow, false))
}
case [2]string:
{
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(content.([2]string)[0], width/3), tcell.ColorYellow, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(content.([2]string)[1], width/3), tcell.ColorPurple, false))
}
case string:
{
b := content.(string)
if !strings.HasPrefix(b, WHITE_AND_BOLD) {
inputTable.SetCell(i, 0,
GetCell(content.(string), tcell.ColorPurple, false))
} else {
inputTable.SetCell(i, 0,
GetCell(content.(string), tcell.ColorWhite, true).SetSelectable(false))
}
}
}
}
}
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 err == nil && _songAttributes[0]["Title"] != "" {
_, _, w, _ := inputTable.GetInnerRect()
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(_songAttributes[0]["Title"], w/3), tcell.ColorGreen, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(_songAttributes[0]["Artist"], w/3), tcell.ColorPurple, false))
inputTable.SetCell(i, 2,
GetCell(_songAttributes[0]["Album"], tcell.ColorYellow, false))
} else if _songAttributes[0]["Title"] == "" {
inputTable.SetCell(i, 0,
GetCell(j.Path, tcell.ColorBlue, true))
}
} else {
inputTable.SetCell(i, 0,
GetCell(j.Path, tcell.ColorYellow, true))
}
}
}

View File

@ -24,6 +24,7 @@ var (
"PORT": "6600", "PORT": "6600",
"DEFAULT_IMAGE_PATH": "default.jpg", "DEFAULT_IMAGE_PATH": "default.jpg",
"CACHE_DIR": utils.CheckDirectoryFmt(USER_CACHE_DIR), "CACHE_DIR": utils.CheckDirectoryFmt(USER_CACHE_DIR),
"SEEK_OFFSET": 1,
} }
) )

View File

@ -50,6 +50,8 @@ var (
100: "deleteSongFromPlaylist", 100: "deleteSongFromPlaylist",
63: "FocusSearch", 63: "FocusSearch",
47: "FocusBuffSearch", 47: "FocusBuffSearch",
98: "SeekBackward",
102: "SeekForward",
} }
) )

View File

@ -68,6 +68,13 @@ This is the Fallback Image that will be rendered if gomp doesn't find the embedd
```yml ```yml
DEFAULT_IMAGE_PATH : "/path/to/default/image" DEFAULT_IMAGE_PATH : "/path/to/default/image"
``` ```
## Seek Offset
The amount of seconds by which the current song should seek forward or backward.
```yml
SEEK_OFFSET : 5
```
## Additional Padding and Extra Image Width ## Additional Padding and Extra Image Width
@ -187,6 +194,8 @@ Following functions are provided :
| deleteSongFromPlaylist | <kbd>d</kbd> | | deleteSongFromPlaylist | <kbd>d</kbd> |
| FocusSearch | <kbd>?</kbd> | | FocusSearch | <kbd>?</kbd> |
| FocusBuffSearch | <kbd>/</kbd> | | FocusBuffSearch | <kbd>/</kbd> |
| SeekForward | <kbd>f</kbd> |
| SeekBackward | <kbd>b</kbd> |
## Getting Album Art from [LastFm API](https://www.last.fm/api) ## Getting Album Art from [LastFm API](https://www.last.fm/api)

2
go.mod
View File

@ -6,7 +6,7 @@ require (
github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4
github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c
github.com/bogem/id3v2 v1.2.0 github.com/bogem/id3v2 v1.2.0
github.com/fhs/gompd v1.0.1 github.com/fhs/gompd/v2 v2.2.0
github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1 github.com/gdamore/tcell/v2 v2.4.1-0.20210905002822-f057f0a857a1
github.com/mewkiz/flac v1.0.7 github.com/mewkiz/flac v1.0.7
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646

4
go.sum
View File

@ -90,8 +90,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fhs/gompd v1.0.1 h1:kBcAhjnAPJQAylZXR0TeH+d2vpjawXlTtKYguqNlF4A= github.com/fhs/gompd/v2 v2.2.0 h1:zdSYAAOzQ5cCCgYa5CoXkL0Vr0Cqb/b5JmTobirLc90=
github.com/fhs/gompd v1.0.1/go.mod h1:b219/mNa9PvRqvkUip51b23hGL3iX4d4q3gNXdtrD04= github.com/fhs/gompd/v2 v2.2.0/go.mod h1:nNdZtcpD5VpmzZbRl5rV6RhxeMmAWTxEsSIMBkmMIy4=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=

331
main.go
View File

@ -1,20 +1,20 @@
package main package main
import ( import (
"fmt"
"strconv" "strconv"
"time" "time"
"github.com/aditya-K2/gomp/cache" "github.com/aditya-K2/gomp/cache"
"github.com/aditya-K2/gomp/client" "github.com/aditya-K2/gomp/client"
"github.com/aditya-K2/gomp/config" "github.com/aditya-K2/gomp/config"
"github.com/aditya-K2/gomp/notify"
"github.com/aditya-K2/gomp/render" "github.com/aditya-K2/gomp/render"
"github.com/aditya-K2/gomp/ui" "github.com/aditya-K2/gomp/ui"
"github.com/aditya-K2/gomp/ui/notify"
"github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/gomp/views"
"github.com/aditya-K2/fuzzy" "github.com/aditya-K2/fuzzy"
"github.com/fhs/gompd/mpd" "github.com/fhs/gompd/v2/mpd"
"github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -30,33 +30,27 @@ func main() {
} else if nt == "unix" && port != "" { } else if nt == "unix" && port != "" {
port = "" port = ""
} }
CONN, mpdConnectionError := mpd.Dial(nt, client.Conn, mpdConnectionError = mpd.Dial(nt,
viper.GetString("NETWORK_ADDRESS")+del+port) viper.GetString("NETWORK_ADDRESS")+del+port)
if mpdConnectionError != nil { if mpdConnectionError != nil {
utils.Print("RED", "Could Not Connect to MPD Server\n") utils.Print("RED", "Could Not Connect to MPD Server\n")
utils.Print("GREEN", "Make Sure You Mention the Correct MPD Port in the config file.\n") utils.Print("GREEN", "Make Sure You Mention the Correct MPD Port in the config file.\n")
panic(mpdConnectionError) panic(mpdConnectionError)
} }
defer CONN.Close() Conn := client.Conn
defer Conn.Close()
ui.GenerateFocusMap() ui.SetConnection(Conn)
client.SetConnection(CONN)
ui.SetConnection(CONN)
render.SetConnection(CONN)
cache.SetCacheDir(viper.GetString("CACHE_DIR")) cache.SetCacheDir(viper.GetString("CACHE_DIR"))
Renderer := render.NewRenderer() render.Rendr = render.NewRenderer()
// Connecting the Renderer to the Main UI // Connecting the Renderer to the Main UI
ui.ConnectRenderer(Renderer) ui.ConnectRenderer(render.Rendr)
UI := ui.NewApplication() ui.Ui = ui.NewApplication()
// Connecting the Notification Server to the Main UI fileMap, err := Conn.ListAllInfo("/")
notify.ConnectUI(UI)
fileMap, err := CONN.ListAllInfo("/")
if err != nil { if err != nil {
utils.Print("RED", "Could Not Generate the File Map\n") utils.Print("RED", "Could Not Generate the File Map\n")
utils.Print("GREEN", "Make Sure You Mention the Correct MPD Port in the config file.\n") utils.Print("GREEN", "Make Sure You Mention the Correct MPD Port in the config file.\n")
@ -64,15 +58,33 @@ func main() {
} }
// Generating the Directory Tree for File Navigation. // Generating the Directory Tree for File Navigation.
dirTree := client.GenerateDirectoryTree(fileMap) client.DirTree = client.GenerateDirectoryTree(fileMap)
// Default View upon Opening is of Playlist. // Default View upon Opening is of Playlist.
client.UpdatePlaylist(UI.ExpandedView) views.PView.Update(ui.Ui.ExpandedView)
var Volume int64 var Volume int64
var Random, Repeat bool var Random, Repeat bool
var SeekOffset = viper.GetInt("SEEK_OFFSET")
var SeekFunc = func(back bool) {
if status, err := Conn.Status(); err != nil {
notify.Notify.Send("Could not get MPD Status")
} else {
if status["state"] == "play" {
var stime time.Duration
if back {
stime = -1 * time.Second * time.Duration(SeekOffset)
} else {
stime = time.Second * time.Duration(SeekOffset)
}
if err := Conn.SeekCur(stime, true); err != nil {
notify.Notify.Send("Could Not Seek Forward in the Song")
}
}
}
}
if _v, err := CONN.Status(); err != nil { if _v, err := Conn.Status(); err != nil {
utils.Print("RED", "Could Not Get the MPD Status\n") utils.Print("RED", "Could Not Get the MPD Status\n")
panic(err) panic(err)
} else { } else {
@ -92,41 +104,26 @@ func main() {
// Used for Fuzzy Searching // Used for Fuzzy Searching
ArtistTreeContent := utils.ConvertToArray(ArtistTree) ArtistTreeContent := utils.ConvertToArray(ArtistTree)
Notify := notify.NewNotificationServer() notify.Notify = notify.NewNotificationServer()
Notify.Start() notify.Notify.Start()
if c, err := CONN.CurrentSong(); err != nil { if c, err := Conn.CurrentSong(); err != nil {
utils.Print("RED", "Could Not Retrieve the Current Song\n") utils.Print("RED", "Could Not Retrieve the Current Song\n")
panic(err) panic(err)
} else { } else {
if len(c) != 0 { if len(c) != 0 {
Renderer.Start(c["file"]) render.Rendr.Start(c["file"])
} else { } else {
Renderer.Start("stop") render.Rendr.Start("stop")
} }
} }
// 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{}
var Matches fuzzy.Matches
// This Function Is Responsible for Changing the Focus it uses the Focus Map and Based on it Chooses // This Function Is Responsible for Changing the Focus it uses the Focus Map and Based on it Chooses
// the Draw Function // the Draw Function
UI.ExpandedView.SetDrawFunc(func(s tcell.Screen, x, y, width, height int) (int, int, int, int) { views.SetCurrentView(views.PView)
if ui.HasFocus("Playlist") { ui.Ui.ExpandedView.SetDrawFunc(func(s tcell.Screen, x, y, width, height int) (int, int, int, int) {
client.UpdatePlaylist(UI.ExpandedView) views.GetCurrentView().Update(ui.Ui.ExpandedView)
} else if ui.HasFocus("SearchView") { return ui.Ui.ExpandedView.GetInnerRect()
client.UpdateSearchView(UI.ExpandedView, SearchContentSlice)
} else if ui.HasFocus("FileBrowser") {
client.Update(dirTree.Children, UI.ExpandedView)
} else if ui.HasFocus("BuffSearchView") {
client.UpdateBuffSearchView(UI.ExpandedView, Matches, dirTree.Children)
}
return UI.ExpandedView.GetInnerRect()
}) })
// Function Maps is used For Mapping Keys According to the Value mapped to the Key the respective Function is called // Function Maps is used For Mapping Keys According to the Value mapped to the Key the respective Function is called
@ -134,116 +131,43 @@ func main() {
// the respective function in this case togglePlayBack is called. // the respective function in this case togglePlayBack is called.
var FuncMap = map[string]func(){ var FuncMap = map[string]func(){
"showChildrenContent": func() { "showChildrenContent": func() {
if ui.HasFocus("FileBrowser") { views.GetCurrentView().ShowChildrenContent()
r, _ := UI.ExpandedView.GetSelection()
ui.SetFocus("FileBrowser")
if len(dirTree.Children[r].Children) == 0 {
if id, err := CONN.AddId(dirTree.Children[r].AbsolutePath, -1); err != nil {
Notify.Send(fmt.Sprintf("Could not Add Song %s",
dirTree.Children[r].Path))
} else {
if err := CONN.PlayId(id); err != nil {
Notify.Send(fmt.Sprintf("Could Not Play Song %s",
dirTree.Children[r].Path))
}
}
} else {
client.Update(dirTree.Children[r].Children, UI.ExpandedView)
dirTree = &dirTree.Children[r]
UI.ExpandedView.Select(0, 0)
}
} else if ui.HasFocus("Playlist") {
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Play(r); err != nil {
Notify.Send("Could Not Play the Song")
}
} else if ui.HasFocus("SearchView") {
r, _ := UI.ExpandedView.GetSelection()
client.AddToPlaylist(SearchContentSlice[r], true)
} else if ui.HasFocus("BuffSearchView") {
r, _ := UI.ExpandedView.GetSelection()
ui.SetFocus("FileBrowser")
if len(dirTree.Children[r].Children) == 0 {
if id, err := CONN.AddId(dirTree.Children[Matches[r].Index].AbsolutePath, -1); err != nil {
Notify.Send(fmt.Sprintf("Could Not add the Song %s to the Playlist",
dirTree.Children[Matches[r].Index].AbsolutePath))
} else {
if err := CONN.PlayId(id); err != nil {
Notify.Send("Could not Play the Song")
}
}
} else {
client.Update(dirTree.Children[Matches[r].Index].Children, UI.ExpandedView)
dirTree = &dirTree.Children[Matches[r].Index]
}
UI.SearchBar.SetText("")
// Resetting Matches
Matches = nil
}
}, },
"togglePlayBack": func() { "togglePlayBack": func() {
if err := client.TogglePlayBack(); err != nil { if err := client.TogglePlayBack(); err != nil {
Notify.Send("Could not Toggle Play Back") notify.Notify.Send("Could not Toggle Play Back")
} }
}, },
"showParentContent": func() { "showParentContent": func() {
if ui.HasFocus("FileBrowser") { views.GetCurrentView().ShowParentContent()
if dirTree.Parent != nil {
client.Update(dirTree.Parent.Children, UI.ExpandedView)
dirTree = dirTree.Parent
}
} else {
Notify.Send("Not Allowed in this View")
return
}
}, },
"nextSong": func() { "nextSong": func() {
if err := CONN.Next(); err != nil { if err := Conn.Next(); err != nil {
Notify.Send("Could not Select the Next Song") notify.Notify.Send("Could not Select the Next Song")
} }
}, },
"clearPlaylist": func() { "clearPlaylist": func() {
if err := CONN.Clear(); err != nil { if err := Conn.Clear(); err != nil {
Notify.Send("Could not Clear the Playlist") notify.Notify.Send("Could not Clear the Playlist")
} else { } else {
Notify.Send("Playlist Cleared") notify.Notify.Send("Playlist Cleared")
} }
}, },
"previousSong": func() { "previousSong": func() {
if err := CONN.Previous(); err != nil { if err := Conn.Previous(); err != nil {
Notify.Send("Could Not Select the Previous Song") notify.Notify.Send("Could Not Select the Previous Song")
} }
}, },
"addToPlaylist": func() { "addToPlaylist": func() {
if ui.HasFocus("FileBrowser") { views.GetCurrentView().AddToPlaylist()
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Add(dirTree.Children[r].AbsolutePath); err != nil {
Notify.Send(fmt.Sprintf("Could not add %s to the Playlist",
dirTree.Children[r].Path))
}
} else if ui.HasFocus("SearchView") {
r, _ := UI.ExpandedView.GetSelection()
client.AddToPlaylist(SearchContentSlice[r], false)
} else if ui.HasFocus("BuffSearchView") {
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Add(dirTree.Children[Matches[r].Index].AbsolutePath); err != nil {
Notify.Send(fmt.Sprintf("Could Not Add URI %s to the Playlist",
dirTree.Children[Matches[r].Index].Path))
} else {
ui.SetFocus("FileBrowser")
Notify.Send(fmt.Sprintf("URI Added %s to the Playlist",
dirTree.Children[Matches[r].Index].Path))
ui.SetFocus("BuffSearchView")
}
}
}, },
"toggleRandom": func() { "toggleRandom": func() {
if err := CONN.Random(!Random); err == nil { if err := Conn.Random(!Random); err == nil {
Random = !Random Random = !Random
} }
}, },
"toggleRepeat": func() { "toggleRepeat": func() {
if err := CONN.Repeat(!Repeat); err == nil { if err := Conn.Repeat(!Repeat); err == nil {
Repeat = !Repeat Repeat = !Repeat
} }
}, },
@ -253,8 +177,8 @@ func main() {
} else { } else {
Volume -= 10 Volume -= 10
} }
if err := CONN.SetVolume(int(Volume)); err != nil { if err := Conn.SetVolume(int(Volume)); err != nil {
Notify.Send("Could Not Decrease the Volume") notify.Notify.Send("Could Not Decrease the Volume")
} }
}, },
"increaseVolume": func() { "increaseVolume": func() {
@ -263,67 +187,60 @@ func main() {
} else { } else {
Volume += 10 Volume += 10
} }
if err := CONN.SetVolume(int(Volume)); err != nil { if err := Conn.SetVolume(int(Volume)); err != nil {
Notify.Send("Could Not Increase the Volume") notify.Notify.Send("Could Not Increase the Volume")
} }
}, },
"navigateToFiles": func() { "navigateToFiles": func() {
ui.SetFocus("FileBrowser") views.SetCurrentView(views.FView)
UI.Navbar.Select(1, 0) ui.Ui.Navbar.Select(1, 0)
client.Update(dirTree.Children, UI.ExpandedView) views.FView.Update(ui.Ui.ExpandedView)
}, },
"navigateToPlaylist": func() { "navigateToPlaylist": func() {
ui.SetFocus("Playlist") views.SetCurrentView(views.PView)
UI.Navbar.Select(0, 0) ui.Ui.Navbar.Select(0, 0)
client.UpdatePlaylist(UI.ExpandedView) views.PView.Update(ui.Ui.ExpandedView)
}, },
"navigateToMostPlayed": func() { "navigateToMostPlayed": func() {
UI.Navbar.Select(2, 0) ui.Ui.Navbar.Select(2, 0)
}, },
"navigateToSearch": func() { "navigateToSearch": func() {
ui.SetFocus("SearchView") views.SetCurrentView(views.SView)
UI.Navbar.Select(3, 0) ui.Ui.Navbar.Select(3, 0)
views.SView.Update(ui.Ui.ExpandedView)
}, },
"quit": func() { "quit": func() {
if ui.HasFocus("BuffSearchView") { views.GetCurrentView().Quit()
ui.SetFocus("FileBrowser")
UI.SearchBar.SetText("")
Matches = nil
} else {
UI.App.Stop()
}
}, },
"stop": func() { "stop": func() {
if err := CONN.Stop(); err != nil { if err := Conn.Stop(); err != nil {
Notify.Send("Could not Stop the Playback") notify.Notify.Send("Could not Stop the Playback")
} else { } else {
Notify.Send("Playback Stopped") notify.Notify.Send("Playback Stopped")
} }
}, },
"updateDB": func() { "updateDB": func() {
_, err = CONN.Update("") _, err = Conn.Update("")
if err != nil { if err != nil {
Notify.Send("Could Not Update the Database") notify.Notify.Send("Could Not Update the Database")
} else { } else {
Notify.Send("Database Updated") notify.Notify.Send("Database Updated")
} }
}, },
"deleteSongFromPlaylist": func() { "deleteSongFromPlaylist": func() {
if ui.HasFocus("Playlist") { views.GetCurrentView().DeleteSongFromPlaylist()
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Delete(r, -1); err != nil {
Notify.Send("Could not Remove the Song from Playlist")
}
}
}, },
"FocusSearch": func() { "FocusSearch": func() {
UI.App.SetFocus(UI.SearchBar) ui.Ui.App.SetFocus(ui.Ui.SearchBar)
}, },
"FocusBuffSearch": func() { "FocusBuffSearch": func() {
if ui.HasFocus("FileBrowser") || ui.HasFocus("BuffSearchView") { views.GetCurrentView().FocusBuffSearchView()
ui.SetFocus("BuffSearchView") },
UI.App.SetFocus(UI.SearchBar) "SeekForward": func() {
} SeekFunc(false)
},
"SeekBackward": func() {
SeekFunc(true)
}, },
} }
@ -332,12 +249,12 @@ func main() {
// for each event T, P, SPACE mapped to the same function togglePlayBack // for each event T, P, SPACE mapped to the same function togglePlayBack
config.GenerateKeyMap(FuncMap) config.GenerateKeyMap(FuncMap)
UI.SearchBar.SetAutocompleteFunc(func(c string) []string { ui.Ui.SearchBar.SetAutocompleteFunc(func(c string) []string {
if ui.HasFocus("BuffSearchView") { if views.GetCurrentView().GetViewName() == "BuffSearchView" {
return nil return nil
} else { } else {
if c != "" && c != " " && c != " " { if c != "" && c != " " && c != " " {
_, _, w, _ := UI.SearchBar.GetRect() _, _, w, _ := ui.Ui.SearchBar.GetRect()
matches := fuzzy.Find(c, ArtistTreeContent) matches := fuzzy.Find(c, ArtistTreeContent)
var suggestions []string var suggestions []string
for i, match := range matches { for i, match := range matches {
@ -354,83 +271,87 @@ func main() {
}) })
// Input Handler // Input Handler
UI.ExpandedView.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { ui.Ui.ExpandedView.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
if val, ok := config.KEY_MAP[int(e.Rune())]; ok { if val, ok := config.KEY_MAP[int(e.Rune())]; ok {
FuncMap[val]() FuncMap[val]()
return nil return nil
} else { } else {
if ui.HasFocus("Playlist") { if views.GetCurrentView().GetViewName() == "PlaylistView" {
if e.Rune() == 'j' || e.Rune() == 'k' { if e.Rune() == 'j' || e.Rune() == 'k' {
if p, err := CONN.PlaylistInfo(-1, -1); err != nil { if p, err := Conn.PlaylistInfo(-1, -1); err != nil {
Notify.Send("Error Getting PlaylistInfo") notify.Notify.Send("Error Getting PlaylistInfo")
} else { } else {
if len(p) == 0 { if len(p) == 0 {
Notify.Send("Empty Playlist") notify.Notify.Send("Empty Playlist")
return nil return nil
} }
} }
} }
} else if views.GetCurrentView().GetViewName() == "SearchView" {
if e.Rune() == 'j' || e.Rune() == 'k' {
if client.SearchContentSlice == nil || len(client.SearchContentSlice) == 0 {
notify.Notify.Send("No Search Results")
return nil
}
}
} }
return e return e
} }
}) })
UI.SearchBar.SetDoneFunc(func(e tcell.Key) { ui.Ui.SearchBar.SetDoneFunc(func(e tcell.Key) {
if e == tcell.KeyEnter { if e == tcell.KeyEnter {
UI.ExpandedView.Select(0, 0) ui.Ui.ExpandedView.Select(0, 0)
if ui.HasFocus("BuffSearchView") { if views.GetCurrentView().GetViewName() == "BuffSearchView" {
UI.App.SetFocus(UI.ExpandedView) ui.Ui.App.SetFocus(ui.Ui.ExpandedView)
} else { } else {
ui.SetFocus("SearchView") views.SetCurrentView(views.SView)
SearchContentSlice = nil client.SearchContentSlice = nil
SearchContentSlice, err = client.GenerateContentSlice(UI.SearchBar.GetText()) client.SearchContentSlice, err = client.GenerateContentSlice(ui.Ui.SearchBar.GetText())
if err != nil { if err != nil {
Notify.Send("Could Not Retrieve the Results") notify.Notify.Send("Could Not Retrieve the Results")
} else { } else {
UI.SearchBar.SetText("") ui.Ui.SearchBar.SetText("")
UI.App.SetFocus(UI.ExpandedView) ui.Ui.App.SetFocus(ui.Ui.ExpandedView)
UI.Navbar.Select(3, 0) ui.Ui.Navbar.Select(3, 0)
} }
} }
} }
if e == tcell.KeyEscape { if e == tcell.KeyEscape {
if ui.HasFocus("SearchView") { if views.GetCurrentView().GetViewName() == "BuffSearchView" {
ui.FocusMap["SearchView"] = false client.Matches = nil
} else if ui.HasFocus("BuffSearchView") {
ui.SetFocus("FileBrowser")
Matches = nil
} }
UI.SearchBar.SetText("") ui.Ui.SearchBar.SetText("")
UI.App.SetFocus(UI.ExpandedView) ui.Ui.App.SetFocus(ui.Ui.ExpandedView)
} }
}) })
UI.ExpandedView.SetDoneFunc(func(e tcell.Key) { ui.Ui.ExpandedView.SetDoneFunc(func(e tcell.Key) {
if e == tcell.KeyEscape { if e == tcell.KeyEscape {
if ui.HasFocus("BuffSearchView") { if views.GetCurrentView().GetViewName() == "BuffSearchView" {
ui.SetFocus("FileBrowser") views.SetCurrentView(views.FView)
UI.SearchBar.SetText("") ui.Ui.SearchBar.SetText("")
Matches = nil client.Matches = nil
} }
} }
}) })
UI.SearchBar.SetChangedFunc(func(text string) { ui.Ui.SearchBar.SetChangedFunc(func(text string) {
if ui.HasFocus("BuffSearchView") { if views.GetCurrentView().GetViewName() == "BuffSearchView" {
var f client.FileNodes = dirTree.Children var f client.FileNodes = client.DirTree.Children
Matches = fuzzy.FindFrom(text, f) client.Matches = fuzzy.FindFrom(text, f)
client.UpdateBuffSearchView(UI.ExpandedView, Matches, dirTree.Children) views.BuffSView.Update(ui.Ui.ExpandedView)
} }
}) })
go func() { go func() {
for { for {
UI.App.Draw() ui.Ui.App.Draw()
time.Sleep(time.Second) time.Sleep(time.Second)
} }
}() }()
if err := UI.App.Run(); err != nil { if err := ui.Ui.App.Run(); err != nil {
panic(err) panic(err)
} }
} }

View File

@ -4,7 +4,6 @@ import (
"time" "time"
"github.com/aditya-K2/gomp/ui" "github.com/aditya-K2/gomp/ui"
"github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview" "github.com/aditya-K2/tview"
@ -12,13 +11,9 @@ import (
) )
var ( var (
UI *ui.Application Notify *NotificationServer
) )
func ConnectUI(a *ui.Application) {
UI = a
}
/* Notification Primitive */ /* Notification Primitive */
type Notification struct { type Notification struct {
*tview.Box *tview.Box
@ -79,11 +74,11 @@ func NotificationRoutine(c chan string, s string) {
if s != "EMPTY NOTIFICATION" { if s != "EMPTY NOTIFICATION" {
go func() { go func() {
currentTime := time.Now().String() currentTime := time.Now().String()
UI.Pages.AddPage(currentTime, NewNotification(s), false, true) ui.Ui.Pages.AddPage(currentTime, NewNotification(s), false, true)
UI.App.SetFocus(UI.ExpandedView) ui.Ui.App.SetFocus(ui.Ui.ExpandedView)
time.Sleep(time.Second * 1) time.Sleep(time.Second * 1)
UI.Pages.RemovePage(currentTime) ui.Ui.Pages.RemovePage(currentTime)
UI.App.SetFocus(UI.ExpandedView) ui.Ui.App.SetFocus(ui.Ui.ExpandedView)
}() }()
} }
NewNotification := <-c NewNotification := <-c

View File

@ -4,8 +4,9 @@ import (
"image" "image"
"os" "os"
"github.com/aditya-K2/gomp/client"
"github.com/aditya-K2/gomp/notify"
"github.com/aditya-K2/gomp/ui" "github.com/aditya-K2/gomp/ui"
"github.com/fhs/gompd/mpd"
"github.com/aditya-K2/gomp/cache" "github.com/aditya-K2/gomp/cache"
"github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/gomp/utils"
@ -15,18 +16,9 @@ import (
) )
var ( var (
CONN *mpd.Client Rendr *Renderer
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 // 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 // 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. // by the Start() function as a go routine.
@ -82,7 +74,7 @@ func (r *Renderer) Start(path string) {
// rendered it checks first for the image in the cache // 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. // else it adds the image to the cache and then extracts it and renders it.
func GetImagePath(path string) string { func GetImagePath(path string) string {
a, err := CONN.ListInfo(path) a, err := client.Conn.ListInfo(path)
var extractedImage string var extractedImage string
if err == nil && len(a) != 0 { if err == nil && len(a) != 0 {
if cache.Exists(a[0]["artist"], a[0]["album"]) { if cache.Exists(a[0]["artist"], a[0]["album"]) {
@ -95,13 +87,13 @@ func GetImagePath(path string) string {
viper.GetString("GET_COVER_ART_FROM_LAST_FM") == "TRUE" { viper.GetString("GET_COVER_ART_FROM_LAST_FM") == "TRUE" {
downloadedImage, err := getImageFromLastFM(a[0]["artist"], a[0]["album"], imagePath) downloadedImage, err := getImageFromLastFM(a[0]["artist"], a[0]["album"], imagePath)
if err == nil { if err == nil {
Notify.Send("Image From LastFM") notify.Notify.Send("Image From LastFM")
extractedImage = downloadedImage extractedImage = downloadedImage
} else { } else {
Notify.Send("Falling Back to Default Image.") notify.Notify.Send("Falling Back to Default Image.")
} }
} else { } else {
Notify.Send("Extracted Image Successfully") notify.Notify.Send("Extracted Image Successfully")
} }
} }
} }

View File

@ -63,6 +63,10 @@ DEFAULT_IMAGE_PATH: "default.jpg"
# Note It is neccessary to use /home/your_user_name instead of ~ # Note It is neccessary to use /home/your_user_name instead of ~
# Read more about it here: https://github.com/aditya-K2/gomp/issues/1#issuecomment-1205090265 # Read more about it here: https://github.com/aditya-K2/gomp/issues/1#issuecomment-1205090265
SEEK_OFFSET : 1
# The amount of seconds by which the song should seek forward or backward
# Defaults to 1 if not provided
GET_COVER_ART_FROM_LAST_FM : "TRUE" # Turn On Getting Album art from lastfm api GET_COVER_ART_FROM_LAST_FM : "TRUE" # Turn On Getting Album art from lastfm api
LASTFM_API_KEY: "YOUR API KEY HERE" LASTFM_API_KEY: "YOUR API KEY HERE"
LASTFM_API_SECRET: "YOUR API SECRET HERE" LASTFM_API_SECRET: "YOUR API SECRET HERE"

View File

@ -10,6 +10,7 @@ var (
ImgW int ImgW int
ImgH int ImgH int
ImgX int ImgX int
Ui *Application
) )
type Application struct { type Application struct {
@ -17,13 +18,14 @@ type Application struct {
ExpandedView *tview.Table ExpandedView *tview.Table
Navbar *tview.Table Navbar *tview.Table
SearchBar *tview.InputField SearchBar *tview.InputField
ProgressBar *progressBar ProgressBar *ProgressBar
Pages *tview.Pages Pages *tview.Pages
} }
func NewApplication() *Application { func NewApplication() *Application {
var pBar *progressBar = newProgressBar() pBar := NewProgressBar()
pBar.SetProgressFunc(progressFunction)
expandedView := tview.NewTable() expandedView := tview.NewTable()
Navbar := tview.NewTable() Navbar := tview.NewTable()
searchBar := tview.NewInputField() searchBar := tview.NewInputField()
@ -67,7 +69,7 @@ func NewApplication() *Application {
MainFlex := tview.NewFlex().SetDirection(tview.FlexRow). MainFlex := tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(searchBarFlex, 0, 8, false). AddItem(searchBarFlex, 0, 8, false).
AddItem(pBar.t, 5, 1, false) AddItem(pBar, 5, 1, false)
expandedView.SetBorderPadding(1, 1, 1, 1).SetBorder(true) expandedView.SetBorderPadding(1, 1, 1, 1).SetBorder(true)
expandedView.SetSelectable(true, false) expandedView.SetSelectable(true, false)

View File

@ -1,25 +0,0 @@
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
FocusMap["BuffSearchView"] = false
}
func HasFocus(s string) bool {
return FocusMap[s]
}
func SetFocus(s string) {
for k := range FocusMap {
FocusMap[k] = false
}
FocusMap[s] = true
}

View File

@ -3,17 +3,17 @@ package ui
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"strings"
"github.com/fhs/gompd/mpd" "github.com/fhs/gompd/v2/mpd"
"github.com/gdamore/tcell/v2"
"github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview" "github.com/aditya-K2/tview"
"github.com/gdamore/tcell/v2"
) )
var ( var (
CurrentSong string CurrentSong string = ""
CONN *mpd.Client CONN *mpd.Client
RENDERER interface{ Send(string) } RENDERER interface{ Send(string) }
) )
@ -26,48 +26,70 @@ func ConnectRenderer(r interface{ Send(string) }) {
RENDERER = r RENDERER = r
} }
// The progressBar is just a string which is separated by the color formatting String // ProgressBar is a two-lined Box. First line is the BarTitle
// for e.g // Second being the actual progress done.
// "[:#fbff00:]******************`innerText`[-:-:-] " // Use SetProgressFunc to provide the callback which provides the Fields each time the ProgressBar will be Drawn.
// the above string shows represents the progress until [-:-:-] // The progressFunc must return (BarTitle, BarTopTitle, BarText, percentage) respectively
// [-:-:-] this string represents resetting colors so the substring before it would be with a type ProgressBar struct {
// colored background. this is done by calculating the innerRect of the table and taking that length as *tview.Box
// 100% and then representing the rest of the information in relation to it BarTitle string
type progressBar struct { BarText string
t *tview.Table BarTopTitle string
progressFunc func() (BarTitle string,
BarTopTitle string,
BarText string,
percentage float64)
} }
// This Function returns a progressBar with a table of two rows func (self *ProgressBar) SetProgressFunc(pfunc func() (string, string, string, float64)) *ProgressBar {
// the First row will contain information about the current Song self.progressFunc = pfunc
// and the Second one will contain the progressBar return self
func newProgressBar() *progressBar {
p := progressBar{}
a := tview.NewTable().
SetCell(0, 0, tview.NewTableCell("")).
SetCell(1, 0, tview.NewTableCell("")).
SetCell(2, 0, tview.NewTableCell(""))
a.SetBackgroundColor(tcell.ColorDefault)
a.SetBorder(true)
a.SetDrawFunc(func(s tcell.Screen, x, y, width, height int) (int, int, int, int) {
p.updateTitle()
p.updateProgress()
return p.t.GetInnerRect()
})
CurrentSong = ""
p = progressBar{a}
return &p
} }
func (s *progressBar) updateTitle() { func NewProgressBar() *ProgressBar {
return &ProgressBar{
Box: tview.NewBox(),
}
}
func GetProgressGlyph(width, percentage float64, btext string) string {
q := "[black:white:b]"
var a string
a += strings.Repeat(" ", int(width)-len(btext))
a = utils.InsertAt(a, btext, int(width/2)-10)
a = utils.InsertAt(a, "[-:-:-]", int(width*percentage/100))
q += a
return q
}
func (self *ProgressBar) Draw(screen tcell.Screen) {
var (
OFFSET int = 1
)
self.Box.SetBorder(true)
self.Box.SetBackgroundColor(tcell.ColorDefault)
var percentage float64
self.BarTitle, self.BarTopTitle, self.BarText, percentage = self.progressFunc()
self.DrawForSubclass(screen, self.Box)
self.Box.SetTitle(self.BarTopTitle)
self.Box.SetTitleAlign(tview.AlignRight)
x, y, _width, _ := self.Box.GetInnerRect()
tview.Print(screen, self.BarTitle, x+OFFSET, y, _width, tview.AlignLeft, tcell.ColorWhite)
tview.Print(screen,
GetProgressGlyph(float64(_width-OFFSET-1),
percentage,
self.BarText),
x, y+2, _width-OFFSET, tview.AlignRight, tcell.ColorWhite)
}
func progressFunction() (string, string, string, float64) {
_currentAttributes, err := CONN.CurrentSong() _currentAttributes, err := CONN.CurrentSong()
var song, top, text string
var percentage float64
if err == nil { if err == nil {
song := "[green::bi]" + _currentAttributes["Title"] + "[-:-:-] - " + "[blue::b]" + _currentAttributes["Artist"] + "\n" song = "[green::bi]" +
s.t.GetCell(0, 0).Text = song _currentAttributes["Title"] + "[-:-:-] - " + "[blue::b]" +
_currentAttributes["Artist"] + "\n"
if len(_currentAttributes) == 0 && CurrentSong != "" { if len(_currentAttributes) == 0 && CurrentSong != "" {
CurrentSong = "" CurrentSong = ""
RENDERER.Send("stop") RENDERER.Send("stop")
@ -75,39 +97,32 @@ func (s *progressBar) updateTitle() {
RENDERER.Send(_currentAttributes["file"]) RENDERER.Send(_currentAttributes["file"])
CurrentSong = song CurrentSong = song
} }
} else {
utils.Print("RED", "Error Retrieving Current Song\n")
panic(err)
} }
}
func (s *progressBar) updateProgress() {
_status, err := CONN.Status() _status, err := CONN.Status()
_, _, _width, _ := s.t.GetInnerRect()
el, err1 := strconv.ParseFloat(_status["elapsed"], 8) el, err1 := strconv.ParseFloat(_status["elapsed"], 8)
du, err := strconv.ParseFloat(_status["duration"], 8) du, err := strconv.ParseFloat(_status["duration"], 8)
top = fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]",
utils.FormatString(_status["state"]),
utils.FormatString(_status["random"]),
utils.FormatString(_status["repeat"]),
_status["volume"])
if du != 0 { if du != 0 {
percentage := el / du * 100 percentage = el / du * 100
if err == nil && err1 == nil { if err == nil && err1 == nil {
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]", text = utils.StrTime(el) + "/" + utils.StrTime(du) +
utils.FormatString(_status["state"]), "(" + strconv.FormatFloat(percentage, 'f', 2, 32) + "%" + ")"
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 { } else {
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s]", text = ""
utils.FormatString(_status["state"]),
utils.FormatString(_status["random"]),
utils.FormatString(_status["repeat"]))).
SetTitleAlign(tview.AlignRight)
s.t.GetCell(2, 0).Text = ""
} }
} else { } else {
s.t.SetTitle(fmt.Sprintf("[[::i] %s [-:-:-]Shuffle: %s Repeat: %s Volume: %s ]", text = " ---:---"
utils.FormatString(_status["state"]), percentage = 0
utils.FormatString(_status["random"]),
utils.FormatString(_status["repeat"]),
_status["volume"])).
SetTitleAlign(tview.AlignRight)
s.t.GetCell(2, 0).Text = utils.GetText(float64(_width), 0, " ---:---")
} }
if percentage > 100 {
percentage = 0
}
return song, top, text, percentage
} }

View File

@ -58,16 +58,6 @@ func InsertAt(inputString, stringTobeInserted string, index int) string {
return s return s
} }
func GetText(width, percentage float64, eta string) string {
q := "[black:white:b]"
var a string
a += strings.Repeat(" ", int(width)-len(eta))
a = InsertAt(a, eta, int(width/2)-10)
a = InsertAt(a, "[-:-:-]", int(width*percentage/100))
q += a
return q
}
func ConvertToArray(ArtistTree map[string]map[string]map[string]string) []string { func ConvertToArray(ArtistTree map[string]map[string]map[string]string) []string {
var p []string var p []string
for k2, v := range ArtistTree { for k2, v := range ArtistTree {

105
views/buffsearchview.go Normal file
View File

@ -0,0 +1,105 @@
package views
import (
"fmt"
"github.com/aditya-K2/gomp/client"
"github.com/aditya-K2/gomp/notify"
"github.com/aditya-K2/gomp/ui"
"github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview"
"github.com/gdamore/tcell/v2"
)
type BuffSearchView struct {
}
func (s BuffSearchView) GetViewName() string {
return "BuffSearchView"
}
func (s BuffSearchView) ShowChildrenContent() {
UI := ui.Ui
CONN := client.Conn
r, _ := UI.ExpandedView.GetSelection()
SetCurrentView(FView)
if len(client.DirTree.Children[r].Children) == 0 {
if id, err := CONN.AddID(client.DirTree.Children[client.Matches[r].Index].AbsolutePath, -1); err != nil {
notify.Notify.Send(fmt.Sprintf("Could Not add the Song %s to the Playlist",
client.DirTree.Children[client.Matches[r].Index].AbsolutePath))
} else {
if err := CONN.PlayID(id); err != nil {
notify.Notify.Send("Could not Play the Song")
}
}
} else {
client.DirTree = &client.DirTree.Children[client.Matches[r].Index]
FView.Update(UI.ExpandedView)
}
UI.SearchBar.SetText("")
// Resetting client.Matches
client.Matches = nil
}
func (s BuffSearchView) ShowParentContent() {
notify.Notify.Send("Not Allowed in this View")
return
}
func (s BuffSearchView) AddToPlaylist() {
UI := ui.Ui
CONN := client.Conn
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Add(client.DirTree.Children[client.Matches[r].Index].AbsolutePath); err != nil {
notify.Notify.Send(fmt.Sprintf("Could Not Add URI %s to the Playlist",
client.DirTree.Children[client.Matches[r].Index].Path))
} else {
SetCurrentView(FView)
notify.Notify.Send(fmt.Sprintf("URI Added %s to the Playlist",
client.DirTree.Children[client.Matches[r].Index].Path))
SetCurrentView(BuffSView)
}
}
func (s BuffSearchView) Quit() {
UI := ui.Ui
SetCurrentView(FView)
UI.SearchBar.SetText("")
client.Matches = nil
}
func (f BuffSearchView) FocusBuffSearchView() {
UI := ui.Ui
SetCurrentView(BuffSView)
UI.App.SetFocus(UI.SearchBar)
}
func (f BuffSearchView) DeleteSongFromPlaylist() {}
func (s BuffSearchView) Update(inputTable *tview.Table) {
m := client.Matches
f := client.DirTree.Children
inputTable.Clear()
if m == nil || len(m) == 0 {
FView.Update(inputTable)
} else {
for k, v := range m {
if len(f[v.Index].Children) != 0 {
inputTable.SetCell(k, 0,
GetCell(
utils.GetMatchedString(
utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[blue:-:bi]"),
tcell.ColorYellow, true))
} else {
inputTable.SetCell(k, 0,
GetCell(
utils.GetMatchedString(
utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[yellow:-:bi]"),
tcell.ColorGreen, true))
}
if k == 15 {
break
}
}
}
}

99
views/fileview.go Normal file
View File

@ -0,0 +1,99 @@
package views
import (
"fmt"
"github.com/aditya-K2/gomp/client"
"github.com/aditya-K2/gomp/notify"
"github.com/aditya-K2/gomp/ui"
"github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview"
"github.com/gdamore/tcell/v2"
)
type FileView struct {
}
func (f FileView) GetViewName() string {
return "FileView"
}
func (f FileView) ShowChildrenContent() {
UI := ui.Ui
CONN := client.Conn
r, _ := UI.ExpandedView.GetSelection()
SetCurrentView(FView)
if len(client.DirTree.Children[r].Children) == 0 {
if id, err := CONN.AddID(client.DirTree.Children[r].AbsolutePath, -1); err != nil {
notify.Notify.Send(fmt.Sprintf("Could not Add Song %s",
client.DirTree.Children[r].Path))
} else {
if err := CONN.PlayID(id); err != nil {
notify.Notify.Send(fmt.Sprintf("Could Not Play Song %s",
client.DirTree.Children[r].Path))
}
}
} else {
client.DirTree = &client.DirTree.Children[r]
FView.Update(UI.ExpandedView)
UI.ExpandedView.Select(0, 0)
}
}
func (f FileView) ShowParentContent() {
UI := ui.Ui
if client.DirTree.Parent != nil {
client.DirTree = client.DirTree.Parent
FView.Update(UI.ExpandedView)
}
}
func (f FileView) AddToPlaylist() {
UI := ui.Ui
CONN := client.Conn
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Add(client.DirTree.Children[r].AbsolutePath); err != nil {
notify.Notify.Send(fmt.Sprintf("Could not add %s to the Playlist",
client.DirTree.Children[r].Path))
}
}
func (f FileView) Quit() {
ui.Ui.App.Stop()
}
func (f FileView) FocusBuffSearchView() {
UI := ui.Ui
SetCurrentView(BuffSView)
UI.App.SetFocus(UI.SearchBar)
}
func (f FileView) DeleteSongFromPlaylist() {}
func (f FileView) Update(inputTable *tview.Table) {
inputTable.Clear()
for i, j := range client.DirTree.Children {
if len(j.Children) == 0 {
_songAttributes, err := client.Conn.ListAllInfo(j.AbsolutePath)
if err == nil && _songAttributes[0]["Title"] != "" {
_, _, w, _ := inputTable.GetInnerRect()
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(_songAttributes[0]["Title"], w/3), tcell.ColorGreen, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(_songAttributes[0]["Artist"], w/3), tcell.ColorPurple, false))
inputTable.SetCell(i, 2,
GetCell(_songAttributes[0]["Album"], tcell.ColorYellow, false))
} else if _songAttributes[0]["Title"] == "" {
inputTable.SetCell(i, 0,
GetCell(j.Path, tcell.ColorBlue, true))
}
} else {
inputTable.SetCell(i, 0,
GetCell(j.Path, tcell.ColorYellow, true))
}
}
}

82
views/playlistview.go Normal file
View File

@ -0,0 +1,82 @@
package views
import (
"github.com/aditya-K2/gomp/client"
"github.com/aditya-K2/gomp/notify"
"github.com/aditya-K2/gomp/ui"
"github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview"
"github.com/gdamore/tcell/v2"
)
type PlaylistView struct {
}
func (s PlaylistView) GetViewName() string {
return "PlaylistView"
}
func GetCell(text string, foreground tcell.Color, bold bool) *tview.TableCell {
return tview.NewTableCell(text).
SetAlign(tview.AlignLeft).
SetStyle(tcell.StyleDefault.
Foreground(foreground).
Background(tcell.ColorBlack).
Bold(bold))
}
func (p PlaylistView) ShowChildrenContent() {
UI := ui.Ui
CONN := client.Conn
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Play(r); err != nil {
notify.Notify.Send("Could Not Play the Song")
return
}
}
func (s PlaylistView) ShowParentContent() {
notify.Notify.Send("Not Allowed in this View")
return
}
func (p PlaylistView) AddToPlaylist() {}
func (p PlaylistView) Quit() {
ui.Ui.App.Stop()
}
func (p PlaylistView) FocusBuffSearchView() {}
func (p PlaylistView) DeleteSongFromPlaylist() {
UI := ui.Ui
CONN := client.Conn
r, _ := UI.ExpandedView.GetSelection()
if err := CONN.Delete(r, -1); err != nil {
notify.Notify.Send("Could not Remove the Song from Playlist")
}
}
func (p PlaylistView) Update(inputTable *tview.Table) {
CONN := client.Conn
_playlistAttr, _ := CONN.PlaylistInfo(-1, -1)
inputTable.Clear()
for i, j := range _playlistAttr {
_, _, w, _ := inputTable.GetInnerRect()
if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" {
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(j["file"], w/3), tcell.ColorBlue, true))
} else {
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(j["Title"], w/3), tcell.ColorGreen, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(j["Artist"], w/3), tcell.ColorPurple, false))
inputTable.SetCell(i, 2,
GetCell(j["Album"], tcell.ColorYellow, false))
}
}
}

93
views/searchview.go Normal file
View File

@ -0,0 +1,93 @@
package views
import (
"strings"
"github.com/aditya-K2/gomp/client"
"github.com/aditya-K2/gomp/notify"
"github.com/aditya-K2/gomp/ui"
"github.com/aditya-K2/gomp/utils"
"github.com/aditya-K2/tview"
"github.com/gdamore/tcell/v2"
)
type SearchView struct {
}
func (s SearchView) GetViewName() string {
return "SearchView"
}
func (s SearchView) ShowChildrenContent() {
UI := ui.Ui
SearchContentSlice := client.SearchContentSlice
if len(client.SearchContentSlice) <= 0 || client.SearchContentSlice == nil {
notify.Notify.Send("No Search Results")
} else {
r, _ := UI.ExpandedView.GetSelection()
client.AddToPlaylist(SearchContentSlice[r], true)
}
}
func (s SearchView) ShowParentContent() {
notify.Notify.Send("Not Allowed in this View")
return
}
func (s SearchView) AddToPlaylist() {
UI := ui.Ui
SearchContentSlice := client.SearchContentSlice
if len(client.SearchContentSlice) <= 0 || client.SearchContentSlice == nil {
notify.Notify.Send("No Search Results")
} else {
r, _ := UI.ExpandedView.GetSelection()
client.AddToPlaylist(SearchContentSlice[r], false)
}
}
func (p SearchView) Quit() {
ui.Ui.App.Stop()
}
func (s SearchView) FocusBuffSearchView() {}
func (s SearchView) DeleteSongFromPlaylist() {}
func (s SearchView) Update(inputTable *tview.Table) {
inputTable.Clear()
c := client.SearchContentSlice
_, _, width, _ := inputTable.GetInnerRect()
for i, content := range c {
switch content.(type) {
case [3]string:
{
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(content.([3]string)[0], width/3), tcell.ColorGreen, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(content.([3]string)[1], width/3), tcell.ColorPurple, false))
inputTable.SetCell(i, 2,
GetCell(content.([3]string)[2], tcell.ColorYellow, false))
}
case [2]string:
{
inputTable.SetCell(i, 0,
GetCell(
utils.GetFormattedString(content.([2]string)[0], width/3), tcell.ColorYellow, false))
inputTable.SetCell(i, 1,
GetCell(
utils.GetFormattedString(content.([2]string)[1], width/3), tcell.ColorPurple, false))
}
case string:
{
b := content.(string)
if !strings.HasPrefix(b, client.WHITE_AND_BOLD) {
inputTable.SetCell(i, 0,
GetCell(content.(string), tcell.ColorPurple, false))
} else {
inputTable.SetCell(i, 0,
GetCell(content.(string), tcell.ColorWhite, true).SetSelectable(false))
}
}
}
}
}

32
views/views.go Normal file
View File

@ -0,0 +1,32 @@
package views
import (
"github.com/aditya-K2/tview"
)
var (
CurrentView View
BuffSView BuffSearchView
SView SearchView
FView FileView
PView PlaylistView
)
type View interface {
Update(inputTable *tview.Table)
ShowChildrenContent()
ShowParentContent()
AddToPlaylist()
Quit()
FocusBuffSearchView()
DeleteSongFromPlaylist()
GetViewName() string
}
func SetCurrentView(v View) {
CurrentView = v
}
func GetCurrentView() View {
return CurrentView
}