Favorites are now merged between local list and the remote service and stored in di-tui's config fle. If no local favorites are configured the behavior is unchanged; once the user interacts, the config becomes the source of truth for ordering and visibility. Merge rules: - Local entries appear first, sorted by the user's preference - Hidden local entries suppress matching remote entries - Remote favorites with no local entry are appended to the end, in order Reorder saves are debounced 200ms so rapid key presses produce a single config write. Toggling a favorite saves immediately.
193 lines
4.2 KiB
Go
193 lines
4.2 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/acaloiaro/di-tui/components"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// TODO This application is migrating to having all of its configuration read into this `Config` struct, rather than
|
|
// using individual `ReadType` functions from viper. Migrating all `Get*` methods to use `Config` instead.
|
|
type Config struct {
|
|
Favorites []components.FavoriteItem `yaml:"favorites" mapstructure:"favorites"`
|
|
Theme map[string]string
|
|
}
|
|
|
|
var C Config
|
|
|
|
func init() {
|
|
viper.SetConfigName("config")
|
|
viper.SetConfigType("yaml")
|
|
viper.AddConfigPath("$HOME/.config/di-tui")
|
|
viper.AddConfigPath("$HOME/.di-tui/")
|
|
viper.AddConfigPath(".")
|
|
|
|
viper.SetDefault("album_art", true)
|
|
viper.SetDefault("network.shortname", "di")
|
|
|
|
err := viper.ReadInConfig()
|
|
if err != nil {
|
|
saveConfig()
|
|
}
|
|
|
|
if err := viper.Unmarshal(&C); err != nil {
|
|
fmt.Fprintf(os.Stderr, "unable to load di-tui configuration file: %v", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
// AlbumArt returns true if album art should be fetched when a new song begins playing
|
|
func AlbumArt() bool {
|
|
return viper.GetBool("album_art")
|
|
}
|
|
|
|
// GetToken returns the di.fm API token if one is available
|
|
func GetToken() (token string) {
|
|
return viper.GetString("token")
|
|
}
|
|
|
|
// GetUserID returns the di.fm user ID
|
|
func GetUserID() (userID int) {
|
|
return viper.GetInt("user_id")
|
|
}
|
|
|
|
// GetAudioToken gets the audio token from disk
|
|
func GetAudioToken() string {
|
|
return viper.GetString("audioToken")
|
|
}
|
|
|
|
// SaveAudioToken saves the audio token to disk
|
|
func SaveAudioToken(audioToken string) {
|
|
viper.Set("audioToken", audioToken)
|
|
|
|
saveConfig()
|
|
}
|
|
|
|
// GetSessionKey gets the session key from disk
|
|
func GetSessionKey() string {
|
|
return viper.GetString("sessionKey")
|
|
}
|
|
|
|
// SaveSessionKey saves the session key to disk
|
|
func SaveSessionKey(sessionKey string) {
|
|
viper.Set("sessionKey", sessionKey)
|
|
|
|
saveConfig()
|
|
}
|
|
|
|
// SaveUserID saves the user's ID
|
|
func SaveUserID(userID int64) {
|
|
viper.Set("user_id", userID)
|
|
|
|
saveConfig()
|
|
}
|
|
|
|
// SaveListenToken saves the user's listen token
|
|
func SaveListenToken(token string) {
|
|
viper.Set("token", token)
|
|
|
|
saveConfig()
|
|
}
|
|
|
|
// SaveAPIKey saves the user's API key
|
|
func SaveAPIKey(key string) {
|
|
viper.Set("api_key", key)
|
|
|
|
saveConfig()
|
|
}
|
|
|
|
// SaveNetwork saves the user's default network
|
|
func SaveNetwork(network *components.Network) {
|
|
viper.Set("network", network)
|
|
|
|
saveConfig()
|
|
}
|
|
|
|
// GetLocalFavorites returns the user's locally configured favorites
|
|
func GetLocalFavorites() []components.FavoriteItem {
|
|
return C.Favorites
|
|
}
|
|
|
|
// SaveLocalFavorites persists the ordered favorites list to the config file
|
|
func SaveLocalFavorites(favorites []components.FavoriteItem) {
|
|
data := make([]map[string]any, len(favorites))
|
|
for i, f := range favorites {
|
|
entry := map[string]any{
|
|
"name": f.Name,
|
|
"channel_id": f.ChannelID,
|
|
}
|
|
if f.Hidden {
|
|
entry["hidden"] = true
|
|
}
|
|
data[i] = entry
|
|
}
|
|
viper.Set("favorites", data)
|
|
C.Favorites = favorites
|
|
saveConfig()
|
|
}
|
|
|
|
// HasTheme returns true if the di-tui config has a Theme set
|
|
func HasTheme() bool {
|
|
if C.Theme["primary_color"] != "" {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// GetThemePrimaryColor gets the theme's primary color
|
|
func GetThemePrimaryColor() string {
|
|
return C.Theme["primary_color"]
|
|
}
|
|
|
|
// GetThemePrimaryColor gets the theme's background color
|
|
func GetThemeBackgroundColor() string {
|
|
return C.Theme["background_color"]
|
|
}
|
|
|
|
// GetThemePrimaryTextColor gets the theme's primary text color
|
|
func GetThemePrimaryTextColor() string {
|
|
return C.Theme["primary_text_color"]
|
|
}
|
|
|
|
// GetThemePrimaryColor gets the theme's primary color
|
|
func GetThemeSecondaryTextColor() string {
|
|
return C.Theme["secondary_text_color"]
|
|
}
|
|
|
|
func saveConfig() {
|
|
viper.SetConfigFile(configFilePath())
|
|
viper.SetConfigType("yaml")
|
|
|
|
viper.Set("username", "")
|
|
viper.Set("password", "")
|
|
|
|
viper.WriteConfig()
|
|
|
|
}
|
|
|
|
func configFilePath() string {
|
|
var home string
|
|
if runtime.GOOS == "windows" {
|
|
home = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
|
if home == "" {
|
|
home = os.Getenv("USERPROFILE")
|
|
}
|
|
return home
|
|
}
|
|
|
|
home = os.Getenv("HOME")
|
|
dir := fmt.Sprintf("%s/.config/di-tui/", home)
|
|
|
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
err = os.MkdirAll(dir, 0755)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("%s/config.yml", dir)
|
|
}
|