diff --git a/App.go b/app.go similarity index 100% rename from App.go rename to app.go diff --git a/cache/cache.go b/cache/cache.go index 80eba89..4f10ee2 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -3,70 +3,32 @@ package cache import ( "errors" "fmt" - "io/ioutil" "os" "strings" + + "github.com/aditya-K2/goMP/utils" ) var ( - USER_CACHE_DIR, err = os.UserCacheDir() - CACHE_LIST map[[2]string]string = make(map[[2]string]string) - CACHE_DIR string = USER_CACHE_DIR - DEFAULT_IMG string + CACHE_DIR string + DEFAULT_IMG string ) func SetCacheDir(path string) { - CACHE_DIR = path + CACHE_DIR = utils.CheckDirectoryFmt(path) } -func SetDefaultPath(path string) { - DEFAULT_IMG = path -} - -func LoadCache(path string) error { - cacheFileContent, err := ioutil.ReadFile(path) - if err != nil { - return errors.New("Could Not Read From Cache File") - } - lineSlice := strings.Split(string(cacheFileContent), "\n") - for _, line := range lineSlice { - if len(line) != 0 { - param := strings.Split(line, "\t") - if len(param) == 3 { - CACHE_LIST[[2]string{param[0], param[1]}] = param[2] - } - } - } - return nil -} - -func GetFromCache(artist, album string) (string, error) { - if val, ok := CACHE_LIST[[2]string{artist, album}]; ok { - return val, nil +func Exists(artist, album string) bool { + if _, err := os.Stat(GenerateName(artist, album)); errors.Is(err, os.ErrNotExist) { + return false } else { - return "", errors.New("Element Not In Cache") - } -} - -func PointToDefault(artist, album string) { - CACHE_LIST[[2]string{artist, album}] = DEFAULT_IMG -} - -func AddToCache(artist, album string) string { - fileName := CACHE_DIR + GenerateName(artist, album) - CACHE_LIST[[2]string{artist, album}] = fileName - return fileName -} - -func WriteCache(path string) { - b, err := os.Create(path) - if err == nil { - for k, v := range CACHE_LIST { - b.Write([]byte(fmt.Sprintf("%s\t%s\t%s\n", k[0], k[1], v))) - } + return true } } func GenerateName(artist, album string) string { - return strings.Replace(strings.Replace(fmt.Sprintf("%s-%s.jpg", artist, album), " ", "_", -1), "/", "_", -1) + if (artist == "" && album == "") || (artist == " " && album == " ") { + return CACHE_DIR + "UnknownArtist-UnknownAlbum.jpg" + } + return CACHE_DIR + strings.Replace(strings.Replace(fmt.Sprintf("%s-%s.jpg", artist, album), " ", "_", -1), "/", "_", -1) } diff --git a/client.go b/client.go index 48ca4b9..00243cd 100644 --- a/client.go +++ b/client.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/aditya-K2/goMP/utils" "github.com/aditya-K2/tview" ) @@ -12,16 +13,6 @@ var ( WHITE_AND_BOLD string = "[#ffffff::b]" ) -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 -} - func togglePlayBack() error { status, err := CONN.Status() if status["state"] == "play" && err == nil { @@ -39,10 +30,10 @@ func UpdatePlaylist(inputTable *tview.Table) { for i, j := range _playlistAttr { _, _, w, _ := inputTable.GetInnerRect() if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" { - inputTable.SetCell(i, 0, tview.NewTableCell(getFormattedString(j["file"], w/3))) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3))) } else { - 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, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+j["Title"], w/3))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+j["Artist"], w/3))) inputTable.SetCell(i, 2, tview.NewTableCell("[yellow]"+j["Album"])) } } @@ -106,14 +97,14 @@ func UpdateSearchView(inputTable *tview.Table, c []interface{}) { switch content.(type) { case [3]string: { - 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))) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([3]string)[0], width/3))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([3]string)[1], width/3))) + inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString("[yellow]"+content.([3]string)[2], width/3))) } case [2]string: { - 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))) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([2]string)[0], width/3))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([2]string)[1], width/3))) } case string: { @@ -128,16 +119,6 @@ func UpdateSearchView(inputTable *tview.Table, c []interface{}) { } } -func join(stringSlice []string) string { - var _s string = stringSlice[0] - for i := 1; i < len(stringSlice); i++ { - if _s != "" { - _s += ("/" + stringSlice[i]) - } - } - return _s -} - func Update(f []FileNode, inputTable *tview.Table) { inputTable.Clear() for i, j := range f { @@ -146,11 +127,11 @@ func Update(f []FileNode, inputTable *tview.Table) { if err == nil && _songAttributes[0]["Title"] != "" { _, _, w, _ := inputTable.GetInnerRect() inputTable.SetCell(i, 0, - tview.NewTableCell("[green]"+getFormattedString(_songAttributes[0]["Title"], w/3)). + tview.NewTableCell("[green]"+utils.GetFormattedString(_songAttributes[0]["Title"], w/3)). SetAlign(tview.AlignLeft)) inputTable.SetCell(i, 1, - tview.NewTableCell("[magenta]"+getFormattedString(_songAttributes[0]["Artist"], w/3)). + tview.NewTableCell("[magenta]"+utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)). SetAlign(tview.AlignLeft)) inputTable.SetCell(i, 2, diff --git a/config/config.go b/config/config.go index c98ee95..c5dc1c0 100644 --- a/config/config.go +++ b/config/config.go @@ -6,20 +6,22 @@ import ( "os" "strings" + "github.com/aditya-K2/goMP/utils" "github.com/spf13/viper" ) var ( - HOME_DIR, _ = os.UserHomeDir() - defaults = map[string]interface{}{ + HOME_DIR, _ = os.UserHomeDir() + USER_CACHE_DIR, _ = os.UserCacheDir() + defaults = map[string]interface{}{ "ADDITIONAL_PADDING_X": 12, "ADDITIONAL_PADDING_Y": 16, "IMAGE_WIDTH_EXTRA_X": -1.5, "IMAGE_WIDTH_EXTRA_Y": -3.75, - "MUSIC_DIRECTORY": getMusicDirectory() + "/", + "MUSIC_DIRECTORY": utils.CheckDirectoryFmt(getMusicDirectory()), "PORT": "6600", "DEFAULT_IMAGE_PATH": "default.jpg", - "COVER_IMAGE_PATH": "cover.jpg", + "CACHE_DIR": utils.CheckDirectoryFmt(USER_CACHE_DIR), } ) diff --git a/main.go b/main.go index 0b82f93..dcd8aa4 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,8 @@ import ( "strconv" "time" + "github.com/aditya-K2/goMP/utils" + "github.com/aditya-K2/fuzzy" "github.com/aditya-K2/goMP/cache" "github.com/aditya-K2/goMP/config" @@ -34,8 +36,6 @@ func main() { } defer CONN.Close() cache.SetCacheDir(viper.GetString("CACHE_DIR")) - cache.SetDefaultPath(viper.GetString("DEFAULT_IMAGE_PATH")) - cache.LoadCache(viper.GetString("CACHE_FILE")) r := newRenderer() c, _ := CONN.CurrentSong() if len(c) != 0 { @@ -57,7 +57,7 @@ func main() { Repeat, _ = strconv.ParseBool(_v["repeat"]) ARTIST_TREE, err = GenerateArtistTree() - ARTIST_TREE_CONTENT := ConvertToArray() + ARTIST_TREE_CONTENT := utils.ConvertToArray(ARTIST_TREE) NOTIFICATION_SERVER = NewNotificationServer() NOTIFICATION_SERVER.Start() @@ -208,7 +208,7 @@ func main() { if i == 10 { break } - suggestions = append(suggestions, getFormattedString(match.Str, w-2)) + suggestions = append(suggestions, utils.GetFormattedString(match.Str, w-2)) } return suggestions } else { @@ -256,5 +256,4 @@ func main() { if err := UI.App.Run(); err != nil { panic(err) } - cache.WriteCache(viper.GetString("CACHE_FILE")) } diff --git a/notification.go b/notification.go index 15fa3e1..3013627 100644 --- a/notification.go +++ b/notification.go @@ -3,6 +3,8 @@ package main import ( "time" + "github.com/aditya-K2/goMP/utils" + "github.com/aditya-K2/tview" "github.com/gdamore/tcell/v2" ) @@ -23,7 +25,7 @@ func NewNotification(s string) *Notification { /* Draw Function for the Notification Primitive */ func (self *Notification) Draw(screen tcell.Screen) { - termDetails := getWidth() + termDetails := utils.GetWidth() var ( COL int = int(termDetails.Col) diff --git a/progressBar.go b/progressBar.go index 69f5575..46b0e0e 100644 --- a/progressBar.go +++ b/progressBar.go @@ -4,6 +4,8 @@ import ( "fmt" "strconv" + "github.com/aditya-K2/goMP/utils" + "github.com/aditya-K2/tview" "github.com/gdamore/tcell/v2" ) @@ -69,14 +71,14 @@ 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 ]", formatString(_status["state"]), formatString(_status["random"]), formatString(_status["repeat"]), _status["volume"])).SetTitleAlign(tview.AlignRight) - s.t.GetCell(2, 0).Text = getText(float64(_width), percentage, strTime(el)+"/"+strTime(du)+"("+strconv.FormatFloat(percentage, 'f', 2, 32)+"%"+")") + 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]", formatString(_status["state"]), formatString(_status["random"]), 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 ]", formatString(_status["state"]), formatString(_status["random"]), formatString(_status["repeat"]), _status["volume"])).SetTitleAlign(tview.AlignRight) - s.t.GetCell(2, 0).Text = getText(float64(_width), 0, " ---:---") + 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, " ---:---") } } diff --git a/render.go b/render.go index b7797ee..6008b05 100644 --- a/render.go +++ b/render.go @@ -1,7 +1,12 @@ 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" ) @@ -41,11 +46,11 @@ func (self *Renderer) Send(path string) { */ func openImage(path string, c chan string) { - fw, fh := getFontWidth() + fw, fh := utils.GetFontWidth() var im *ueberzug.Image if path != "stop" { extractedImage := getImagePath(path) - img2, _ := getImg(extractedImage) + 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 @@ -75,12 +80,12 @@ func getImagePath(path string) string { a, err := CONN.ListInfo(path) var extractedImage string if err == nil && len(a) != 0 { - if val, err := cache.GetFromCache(a[0]["artist"], a[0]["album"]); err == nil { - extractedImage = val + if cache.Exists(a[0]["artist"], a[0]["album"]) { + extractedImage = cache.GenerateName(a[0]["artist"], a[0]["album"]) } else { - imagePath := cache.AddToCache(a[0]["artist"], a[0]["album"]) - absPath := viper.GetString("MUSIC_DIRECTORY") + path - extractedImage = extractImageFromFile(absPath, imagePath) + 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 { @@ -88,7 +93,6 @@ func getImagePath(path string) string { extractedImage = downloadedImage } else { NOTIFICATION_SERVER.Send("Falling Back to Default Image.") - cache.PointToDefault(a[0]["artist"], a[0]["album"]) } } else { NOTIFICATION_SERVER.Send("Extracted Image Successfully") @@ -97,3 +101,22 @@ func getImagePath(path string) string { } 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 +} diff --git a/sample_config.yml b/sample_config.yml index a2d0677..98858ab 100644 --- a/sample_config.yml +++ b/sample_config.yml @@ -76,7 +76,7 @@ togglePlayBack : [ "p", "SPACE", "]" ] # using the quotes is neccessary. # 3. Fallback to the default image. # # -CACHE_DIR : "/path/to/the/cache/Directory" # for e.g "~/.config/goMP/cache/" Please Note that adding a / at the end is neccessary. +CACHE_DIR : "/path/to/the/cache/Directory" # for e.g "~/.config/goMP/cache/" # You will have to manually create this directory. CACHE_FILE : "/path/to/the/cache/file" # Cache file stores the path to all the images ( think of it like a database. ) # Soon will be deprecated. diff --git a/imageUtils.go b/utils/imageUtils.go similarity index 72% rename from imageUtils.go rename to utils/imageUtils.go index 86f0fd6..ce3dfee 100644 --- a/imageUtils.go +++ b/utils/imageUtils.go @@ -1,14 +1,12 @@ -package main +package utils import ( - "image" "os" "strings" "github.com/bogem/id3v2" "github.com/mewkiz/flac" "github.com/mewkiz/flac/meta" - "github.com/nfnt/resize" "github.com/spf13/viper" ) @@ -64,41 +62,23 @@ func GetFlacImage(songPath, imagePath string) string { return "" } -func extractImageFromFile(uri string, imagePath string) string { +func ExtractImageFromFile(uri string, imagePath string) string { + _i := imagePath if strings.HasSuffix(uri, ".mp3") { imagePath := GetMp3Image(uri, imagePath) if imagePath == "" { + Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i) return viper.GetString("DEFAULT_IMAGE_PATH") - } else { - return imagePath } } else if strings.HasSuffix(uri, ".flac") { imagePath := GetFlacImage(uri, imagePath) if imagePath == "" { + Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i) return viper.GetString("DEFAULT_IMAGE_PATH") - } else { - return imagePath } } else { + Copy(viper.GetString("DEFAULT_IMAGE_PATH"), _i) return viper.GetString("DEFAULT_IMAGE_PATH") } -} - -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 := 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 + return imagePath } diff --git a/utils.go b/utils/utils.go similarity index 50% rename from utils.go rename to utils/utils.go index 6f18fc1..ee88706 100644 --- a/utils.go +++ b/utils/utils.go @@ -1,6 +1,7 @@ -package main +package utils import ( + "io/ioutil" "strconv" "strings" "syscall" @@ -14,7 +15,7 @@ type winsize struct { Ypixel uint16 } -func getWidth() *winsize { +func GetWidth() *winsize { ws := &winsize{} retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(syscall.Stdin), @@ -27,14 +28,14 @@ func getWidth() *winsize { return ws } -func getFontWidth() (float32, float32) { - g := getWidth() +func GetFontWidth() (float32, float32) { + g := GetWidth() fw := (float32(g.Xpixel) / float32(g.Col)) fh := (float32(g.Ypixel) / float32(g.Row)) return fw, fh } -func strTime(e float64) string { +func StrTime(e float64) string { a := int(e) var min, seconds string if a/60 < 10 { @@ -52,24 +53,24 @@ func strTime(e float64) string { return min + ":" + seconds } -func insertAt(inputString, stringTobeInserted string, index int) string { +func InsertAt(inputString, stringTobeInserted string, index int) string { s := inputString[:index] + stringTobeInserted + inputString[index:] return s } -func getText(width, percentage float64, eta string) string { +func GetText(width, percentage float64, eta string) string { q := "[#000000:#ffffff: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)) + a = InsertAt(a, eta, int(width/2)-10) + a = InsertAt(a, "[-:-:-]", int(width*percentage/100)) q += a return q } -func ConvertToArray() []string { +func ConvertToArray(ArtistTree map[string]map[string]map[string]string) []string { var p []string - for k2, v := range ARTIST_TREE { + for k2, v := range ArtistTree { p = append(p, k2) for k1, v1 := range v { p = append(p, k1) @@ -81,7 +82,7 @@ func ConvertToArray() []string { return p } -func formatString(a interface{}) string { +func FormatString(a interface{}) string { if a == "play" { return "Playing" } else if a == "1" { @@ -94,3 +95,44 @@ func formatString(a interface{}) string { return "Paused" } } + +func Copy(sourceImage, destinationImage string) error { + source, err := ioutil.ReadFile(sourceImage) + if err != nil { + return err + } else { + err = ioutil.WriteFile(destinationImage, source, 0644) + if err != nil { + return err + } + return nil + } +} + +func Join(stringSlice []string) string { + var _s string = stringSlice[0] + for i := 1; i < len(stringSlice); i++ { + if _s != "" { + _s += ("/" + stringSlice[i]) + } + } + return _s +} + +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 +} + +func CheckDirectoryFmt(path string) string { + if strings.HasSuffix(path, "/") { + return path + } else { + return path + "/" + } +}