2021-10-09 05:51:47 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2021-11-14 02:06:24 -07:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-10-18 00:42:10 -06:00
|
|
|
"strings"
|
|
|
|
|
2021-11-15 09:18:17 -07:00
|
|
|
"github.com/aditya-K2/tview"
|
2021-10-09 05:51:47 -06:00
|
|
|
)
|
|
|
|
|
2021-11-16 05:33:36 -07:00
|
|
|
var (
|
|
|
|
WHITE_AND_BOLD string = "[#ffffff::b]"
|
|
|
|
)
|
|
|
|
|
2021-10-18 00:42:10 -06:00
|
|
|
func getFormattedString(s string, width int) string {
|
|
|
|
if len(s) < width {
|
|
|
|
s += strings.Repeat(" ", (width - len(s)))
|
|
|
|
} else {
|
|
|
|
s = s[:(width - 2)]
|
|
|
|
s += " "
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
2021-10-17 10:12:02 -06:00
|
|
|
|
2021-11-12 23:02:00 -07:00
|
|
|
func togglePlayBack() error {
|
|
|
|
status, err := CONN.Status()
|
2021-10-17 10:12:02 -06:00
|
|
|
if status["state"] == "play" && err == nil {
|
2021-11-12 23:02:00 -07:00
|
|
|
CONN.Pause(true)
|
2021-10-17 10:12:02 -06:00
|
|
|
} else if status["state"] == "pause" && err == nil {
|
2021-11-12 23:02:00 -07:00
|
|
|
CONN.Play(-1)
|
2021-10-09 05:51:47 -06:00
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2021-10-14 10:32:29 -06:00
|
|
|
|
2021-11-12 23:02:00 -07:00
|
|
|
func UpdatePlaylist(inputTable *tview.Table) {
|
|
|
|
_playlistAttr, _ := CONN.PlaylistInfo(-1, -1)
|
2021-10-17 13:57:30 -06:00
|
|
|
|
2021-10-28 22:14:55 -06:00
|
|
|
inputTable.Clear()
|
2021-10-17 13:57:30 -06:00
|
|
|
for i, j := range _playlistAttr {
|
2021-10-28 22:14:55 -06:00
|
|
|
_, _, w, _ := inputTable.GetInnerRect()
|
2021-10-17 13:57:30 -06:00
|
|
|
if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" {
|
2021-10-28 22:14:55 -06:00
|
|
|
inputTable.SetCell(i, 0, tview.NewTableCell(getFormattedString(j["file"], w/3)))
|
2021-10-17 13:57:30 -06:00
|
|
|
} else {
|
2021-10-28 22:14:55 -06:00
|
|
|
inputTable.SetCell(i, 0, tview.NewTableCell(getFormattedString("[green]"+j["Title"], w/3)))
|
|
|
|
inputTable.SetCell(i, 1, tview.NewTableCell(getFormattedString("[magenta]"+j["Artist"], w/3)))
|
|
|
|
inputTable.SetCell(i, 2, tview.NewTableCell("[yellow]"+j["Album"]))
|
2021-10-17 13:57:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 02:47:50 -07:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) {
|
|
|
|
var ContentSlice []interface{}
|
|
|
|
if strings.TrimRight(selectedSuggestion, " ") == "" {
|
|
|
|
NOTIFICATION_SERVER.Send("Empty Search!")
|
|
|
|
return nil, errors.New("empty Search String Provided")
|
|
|
|
}
|
|
|
|
if _, ok := ARTIST_TREE[selectedSuggestion]; ok {
|
2021-11-16 05:33:36 -07:00
|
|
|
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Artists :")
|
2021-11-16 02:47:50 -07:00
|
|
|
ContentSlice = append(ContentSlice, selectedSuggestion)
|
2021-11-16 05:33:36 -07:00
|
|
|
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Artist Albums :")
|
2021-11-16 02:47:50 -07:00
|
|
|
for albumName := range ARTIST_TREE[selectedSuggestion] {
|
|
|
|
ContentSlice = append(ContentSlice, [2]string{albumName, selectedSuggestion})
|
|
|
|
}
|
2021-11-16 05:33:36 -07:00
|
|
|
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Artist Tracks :")
|
2021-11-16 02:47:50 -07:00
|
|
|
for albumName, trackList := range ARTIST_TREE[selectedSuggestion] {
|
|
|
|
for track := range trackList {
|
|
|
|
ContentSlice = append(ContentSlice, [3]string{track, selectedSuggestion, albumName})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if aMap := QueryArtistTreeForAlbums(ARTIST_TREE, selectedSuggestion); len(aMap) != 0 {
|
2021-11-16 05:33:36 -07:00
|
|
|
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Albums :")
|
2021-11-16 02:47:50 -07:00
|
|
|
for mSlice := range aMap {
|
|
|
|
ContentSlice = append(ContentSlice, mSlice)
|
|
|
|
}
|
2021-11-16 05:33:36 -07:00
|
|
|
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Album Tracks :")
|
2021-11-16 02:47:50 -07:00
|
|
|
for a, pathSlice := range aMap {
|
|
|
|
for _, path := range pathSlice {
|
2021-11-17 02:36:18 -07:00
|
|
|
ContentSlice = append(ContentSlice, [3]string{path[0], a[1], a[0]})
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if tMap := QueryArtistTreeForTracks(ARTIST_TREE, selectedSuggestion); len(tMap) != 0 {
|
2021-11-16 05:33:36 -07:00
|
|
|
ContentSlice = append(ContentSlice, WHITE_AND_BOLD+"Tracks :")
|
2021-11-16 02:47:50 -07:00
|
|
|
for mSlice := range tMap {
|
|
|
|
ContentSlice = append(ContentSlice, mSlice)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
func UpdateSearchView(inputTable *tview.Table, c []interface{}) {
|
|
|
|
inputTable.Clear()
|
2021-11-16 05:09:44 -07:00
|
|
|
_, _, width, _ := inputTable.GetInnerRect()
|
2021-11-16 02:47:50 -07:00
|
|
|
for i, content := range c {
|
|
|
|
switch content.(type) {
|
|
|
|
case [3]string:
|
|
|
|
{
|
2021-11-16 05:09:44 -07:00
|
|
|
inputTable.SetCell(i, 0, tview.NewTableCell(getFormattedString("[green]"+content.([3]string)[0], width/3)))
|
|
|
|
inputTable.SetCell(i, 1, tview.NewTableCell(getFormattedString("[magenta]"+content.([3]string)[1], width/3)))
|
|
|
|
inputTable.SetCell(i, 2, tview.NewTableCell(getFormattedString("[yellow]"+content.([3]string)[2], width/3)))
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
|
|
|
case [2]string:
|
|
|
|
{
|
2021-11-16 05:09:44 -07:00
|
|
|
inputTable.SetCell(i, 0, tview.NewTableCell(getFormattedString("[green]"+content.([2]string)[0], width/3)))
|
|
|
|
inputTable.SetCell(i, 1, tview.NewTableCell(getFormattedString("[magenta]"+content.([2]string)[1], width/3)))
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
|
|
|
case string:
|
|
|
|
{
|
2021-11-16 05:27:05 -07:00
|
|
|
b := content.(string)
|
2021-11-16 05:33:36 -07:00
|
|
|
if !strings.HasPrefix(b, WHITE_AND_BOLD) {
|
2021-11-16 05:27:05 -07:00
|
|
|
inputTable.SetCell(i, 0, tview.NewTableCell("[green]"+content.(string)))
|
|
|
|
} else {
|
|
|
|
inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)).SetSelectable(false))
|
|
|
|
}
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-17 10:12:02 -06:00
|
|
|
func join(stringSlice []string) string {
|
2021-10-14 10:32:29 -06:00
|
|
|
var _s string = stringSlice[0]
|
2021-10-17 10:12:02 -06:00
|
|
|
for i := 1; i < len(stringSlice); i++ {
|
|
|
|
if _s != "" {
|
|
|
|
_s += ("/" + stringSlice[i])
|
2021-10-14 10:32:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return _s
|
|
|
|
}
|
|
|
|
|
2021-11-12 23:02:00 -07:00
|
|
|
func Update(f []FileNode, inputTable *tview.Table) {
|
2021-10-17 10:12:02 -06:00
|
|
|
inputTable.Clear()
|
|
|
|
for i, j := range f {
|
2021-10-14 10:32:29 -06:00
|
|
|
if len(j.children) == 0 {
|
2021-11-12 23:02:00 -07:00
|
|
|
_songAttributes, err := CONN.ListAllInfo(j.absolutePath)
|
2021-10-17 10:12:02 -06:00
|
|
|
if err == nil && _songAttributes[0]["Title"] != "" {
|
2021-10-18 00:42:10 -06:00
|
|
|
_, _, w, _ := inputTable.GetInnerRect()
|
2021-10-14 10:32:29 -06:00
|
|
|
inputTable.SetCell(i, 0,
|
2021-10-18 01:48:56 -06:00
|
|
|
tview.NewTableCell("[green]"+getFormattedString(_songAttributes[0]["Title"], w/3)).
|
2021-10-17 10:12:02 -06:00
|
|
|
SetAlign(tview.AlignLeft))
|
2021-10-14 10:32:29 -06:00
|
|
|
|
|
|
|
inputTable.SetCell(i, 1,
|
2021-10-18 01:48:56 -06:00
|
|
|
tview.NewTableCell("[magenta]"+getFormattedString(_songAttributes[0]["Artist"], w/3)).
|
2021-10-17 10:12:02 -06:00
|
|
|
SetAlign(tview.AlignLeft))
|
2021-10-14 10:32:29 -06:00
|
|
|
|
|
|
|
inputTable.SetCell(i, 2,
|
2021-10-18 01:48:56 -06:00
|
|
|
tview.NewTableCell("[yellow]"+_songAttributes[0]["Album"]).
|
2021-10-17 10:12:02 -06:00
|
|
|
SetAlign(tview.AlignLeft))
|
2021-10-14 10:32:29 -06:00
|
|
|
|
2021-10-17 10:12:02 -06:00
|
|
|
} else if _songAttributes[0]["Title"] == "" {
|
|
|
|
inputTable.SetCell(i, 0,
|
|
|
|
tview.NewTableCell("[blue]"+j.path).
|
|
|
|
SetAlign(tview.AlignLeft))
|
2021-10-14 10:32:29 -06:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
inputTable.SetCell(i, 0,
|
2021-10-18 01:48:56 -06:00
|
|
|
tview.NewTableCell("[yellow::b]"+j.path).
|
2021-10-17 10:12:02 -06:00
|
|
|
SetAlign(tview.AlignLeft))
|
2021-10-14 10:32:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-14 02:06:24 -07:00
|
|
|
|
|
|
|
func GenerateArtistTree() (map[string]map[string]map[string]string, error) {
|
|
|
|
ArtistTree := make(map[string]map[string]map[string]string)
|
|
|
|
AllInfo, err := CONN.ListAllInfo("/")
|
|
|
|
if err == nil {
|
|
|
|
for _, i := range AllInfo {
|
|
|
|
if _, ArtistExists := ArtistTree[i["Artist"]]; !ArtistExists {
|
|
|
|
ArtistTree[i["Artist"]] = make(map[string]map[string]string)
|
|
|
|
}
|
|
|
|
if _, AlbumExists := ArtistTree[i["Artist"]][i["Album"]]; !AlbumExists {
|
|
|
|
ArtistTree[i["Artist"]][i["Album"]] = make(map[string]string)
|
|
|
|
}
|
|
|
|
if _, TitleExists := ArtistTree[i["Artist"]][i["Album"]][i["Title"]]; !TitleExists {
|
|
|
|
ArtistTree[i["Artist"]][i["Album"]][i["Title"]] = i["file"]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ArtistTree, nil
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("Could Not Generate Artist Tree")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func PrintArtistTree(a map[string]map[string]map[string]string) {
|
|
|
|
for k, v := range a {
|
|
|
|
fmt.Println(k, " : ")
|
|
|
|
for k1, v1 := range v {
|
|
|
|
fmt.Println("\t|---", k1, " : ")
|
|
|
|
for k2 := range v1 {
|
|
|
|
fmt.Println("\t\t|---", k2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-15 11:46:15 -07:00
|
|
|
|
2021-11-16 02:47:50 -07:00
|
|
|
/*
|
|
|
|
Adds All tracks from a specified album to a playlist
|
|
|
|
*/
|
2021-11-16 05:09:44 -07:00
|
|
|
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)
|
2021-11-15 11:46:15 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-16 05:09:44 -07:00
|
|
|
NOTIFICATION_SERVER.Send("Album Added : " + alb)
|
2021-11-15 11:46:15 -07:00
|
|
|
}
|
|
|
|
|
2021-11-16 02:47:50 -07:00
|
|
|
/*
|
|
|
|
Adds All tracks from a specified artist to a playlist
|
|
|
|
*/
|
2021-11-15 11:46:15 -07:00
|
|
|
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 {
|
2021-11-16 02:47:50 -07:00
|
|
|
err := CONN.Add(path)
|
|
|
|
if err != nil {
|
2021-11-16 05:09:44 -07:00
|
|
|
NOTIFICATION_SERVER.Send("Could Not Add Song : " + path)
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
2021-11-15 11:46:15 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-16 07:59:46 -07:00
|
|
|
NOTIFICATION_SERVER.Send("Artist Added : " + artist)
|
2021-11-15 11:46:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 02:47:50 -07:00
|
|
|
/*
|
|
|
|
Adds Specified Track to the Playlist
|
|
|
|
*/
|
2021-11-16 07:59:46 -07:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
err := CONN.Add(a[artist][alb][track])
|
|
|
|
if err != nil {
|
|
|
|
NOTIFICATION_SERVER.Send("Could Not Add Track : " + track)
|
|
|
|
}
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
|
|
|
NOTIFICATION_SERVER.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
|
|
|
|
to add tracks to the playlist */
|
|
|
|
func QueryArtistTreeForTracks(a map[string]map[string]map[string]string, track string) map[[3]string]string {
|
2021-11-15 11:46:15 -07:00
|
|
|
TrackMap := make(map[[3]string]string)
|
|
|
|
for artistName, albumMap := range a {
|
2021-11-16 07:30:04 -07:00
|
|
|
for albumName, trackList := range albumMap {
|
2021-11-15 11:46:15 -07:00
|
|
|
for trackName, path := range trackList {
|
|
|
|
if trackName == track {
|
2021-11-16 07:30:04 -07:00
|
|
|
TrackMap[[3]string{trackName, artistName, albumName}] = path
|
2021-11-15 11:46:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TrackMap
|
|
|
|
}
|
2021-11-16 02:47:50 -07:00
|
|
|
|
|
|
|
/* 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)
|
|
|
|
for artistName, albumMap := range a {
|
|
|
|
for albumName, trackList := range albumMap {
|
|
|
|
if albumName == album {
|
|
|
|
var pathSlice [][2]string
|
|
|
|
for trackName, path := range trackList {
|
|
|
|
pathSlice = append(pathSlice, [2]string{trackName, path})
|
|
|
|
}
|
2021-11-17 02:36:18 -07:00
|
|
|
AlbumMap[[2]string{albumName, artistName}] = pathSlice
|
2021-11-16 02:47:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AlbumMap
|
|
|
|
}
|
2021-11-16 05:09:44 -07:00
|
|
|
|
2021-11-16 07:59:46 -07:00
|
|
|
func AddToPlaylist(a interface{}, addAndPlay bool) {
|
2021-11-16 05:09:44 -07:00
|
|
|
switch a.(type) {
|
|
|
|
case [3]string:
|
|
|
|
{
|
|
|
|
b := a.([3]string)
|
2021-11-16 07:59:46 -07:00
|
|
|
AddTitle(ARTIST_TREE, b[1], b[2], b[0], addAndPlay)
|
2021-11-16 05:09:44 -07:00
|
|
|
}
|
|
|
|
case [2]string:
|
|
|
|
{
|
|
|
|
b := a.([2]string)
|
|
|
|
AddAlbum(ARTIST_TREE, b[0], b[1])
|
|
|
|
}
|
|
|
|
case string:
|
|
|
|
{
|
|
|
|
b := a.(string)
|
|
|
|
AddArtist(ARTIST_TREE, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|