ref: a0fcdc0c539634670f2fa71d72831c22f2ec10a4
dir: /config.go/
package main
import (
"bytes"
"fmt"
"os"
"strings"
"time"
"flag"
"slices"
"github.com/pelletier/go-toml/v2"
)
const configFileName = ".hell.conf"
type Hellprefs struct {
Apidelay float32 `toml:"apidelay" comment:"Time in seconds between API requests, accepts floats"`
Save_Location string `toml:"save_location" comment:"Save location for /download"`
Browser string `toml:"browser" comment:"System browser command."`
ImageViewer string `toml:"image_viewer" comment:"System image viewer command."`
MediaImport string `toml:"media_importer" comment:"Alternative media command used with /import"`
FilePicker string `toml:"file_picker" comment:"Graphical file picker (or otherwise)"`
MediaTag string `toml:"media_tag" comment:"text displayed to indicate a media attachment"`
MediaPlayer string `toml:"media_player" comment:"Application to pass media URLs to with /play"`
}
type account_array struct {
AccountConfigs []*mastodon_account `toml:"account"`
}
type mastodon_account struct {
MASTODON_CLIENT_ID string `toml:"MASTODON_CLIENT_ID"`
MASTODON_CLIENT_SECRET string `toml:"MASTODON_CLIENT_SECRET"`
MASTODON_ACCESS_TOKEN string `toml:"MASTODON_ACCESS_TOKEN"`
URL string `toml:"URL"`
Preferences Hellprefs `toml:"preferences"`
Profile string `toml:"profile"`
}
func (prefs *Hellprefs) ApiDelayTime() time.Duration {
delayms := prefs.Apidelay * 1000
i := int64(delayms)
return time.Duration(i) * time.Millisecond
}
func fixPrefs(prefs *Hellprefs) (*Hellprefs, bool) {
var fixed bool
defaultprefs := initPrefs()
if prefs == nil {
return &defaultprefs, true
}
if prefs.Apidelay == 0 {
prefs.Apidelay = defaultprefs.Apidelay
fixed = true
}
if prefs.Save_Location == "" {
prefs.Save_Location = defaultprefs.Save_Location
fixed = true
}
if prefs.Browser == "" {
prefs.Browser = defaultprefs.Browser
fixed = true
}
if prefs.ImageViewer == "" {
prefs.ImageViewer = defaultprefs.ImageViewer
fixed = true
}
if prefs.MediaImport == "" {
prefs.MediaImport = defaultprefs.MediaImport
fixed = true
}
if prefs.FilePicker == "" {
prefs.FilePicker = defaultprefs.FilePicker
fixed = true
}
if prefs.MediaTag == "" {
prefs.MediaTag = defaultprefs.MediaTag
fixed = true
}
if prefs.MediaPlayer == "" {
prefs.MediaPlayer = defaultprefs.MediaPlayer
fixed = true
}
return prefs, fixed
}
func initPrefs() Hellprefs {
prefs := &Hellprefs{
Apidelay: 2,
Save_Location: "~/Downloads",
Browser: "xdg-open '%s'",
ImageViewer: "xdg-open '%s'",
MediaImport: "xdg-open '%s'",
FilePicker: "zenity --file-selection",
MediaTag: "🖼️",
MediaPlayer: "mpv '%s'",
}
return *prefs
}
func createConfigToml(config *account_array, profile string) (b bytes.Buffer, account *mastodon_account, err error) {
account = &mastodon_account{}
client, url := ConfigureClient()
account.URL = url
account.MASTODON_CLIENT_ID = client.Config.ClientID
account.MASTODON_CLIENT_SECRET = client.Config.ClientSecret
account.MASTODON_ACCESS_TOKEN = client.Config.AccessToken
if profile != "" {
account.Profile = profile
} else {
account.Profile = "main"
}
account.Preferences = initPrefs()
config.AccountConfigs = append(config.AccountConfigs, account)
encoder := toml.NewEncoder(&b)
encoder.SetIndentTables(true)
err = encoder.Encode(config)
return
}
func loadConfig() (*mastodon_account, string, error) {
config := &account_array{}
configdir, err := os.UserConfigDir()
var configpath string
if err == nil {
configpath = configdir + "/" + configFileName
} else {
//If go can't find us a home dir just use the current dir
//Probably not a normal multiuser system
configpath = configFileName
}
var profile = flag.String("p", "", "[-p profile]")
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "%s ", flag.CommandLine.Name())
flag.VisitAll(func(f *flag.Flag) {
fmt.Fprintf(flag.CommandLine.Output(), "%s", f.Usage)
})
fmt.Fprintln(flag.CommandLine.Output(), "")
}
flag.Parse()
// Check if the config file exists
if _, err = os.Stat(configpath); os.IsNotExist(err) {
// no config, create account
b, account, err := createConfigToml(config, *profile)
if err != nil {
return nil, "", fmt.Errorf("Error generating account config: %s", err)
}
err = os.WriteFile(configpath, b.Bytes(), 0644)
if err != nil {
return nil, "", fmt.Errorf("error writing config file: %w", err)
}
return account, "", nil
}
// File exists, load it
data, err := os.ReadFile(configpath)
if err != nil {
return nil, "", fmt.Errorf("error reading config file: %w", err)
}
err = toml.Unmarshal(data, config)
if err != nil {
return nil, "", fmt.Errorf("error unmarshalling config: %w", err)
}
if len(config.AccountConfigs) < 1 {
return nil, "", fmt.Errorf("empty config")
}
var new_profile bool
var account_config *mastodon_account
if *profile != "" {
found := slices.ContainsFunc(config.AccountConfigs, func(p *mastodon_account) bool {
account_config = p
return p.Profile == *profile
})
if !found {
new_profile = true
_, account_config, err = createConfigToml(config, *profile)
}
} else {
account_config = config.AccountConfigs[0]
}
prefval := account_config.Preferences
prefs := &prefval
prefs, fixed := fixPrefs(prefs)
account_config.Preferences = *prefs
if fixed || new_profile {
var b bytes.Buffer
encoder := toml.NewEncoder(&b)
encoder.SetIndentTables(true)
err = encoder.Encode(config)
if err != nil {
return nil, "", fmt.Errorf("error marshalling config: %w", err)
}
err = os.WriteFile(configpath, b.Bytes(), 0644)
if err != nil {
return nil, "", fmt.Errorf("error writing config file: %w", err)
}
}
prefs.Save_Location = expandDir(prefs.Save_Location)
account_config.Preferences = *prefs
return account_config, configpath, nil
}
func expandDir(dir string) string {
homedir, err := os.UserHomeDir()
if err == nil {
dir = strings.ReplaceAll(dir, "~", homedir)
} else {
//We're not gonna bail but what is wrong with this install?
fmt.Printf("WARNING: no home directory found. Using current directory.\n")
dir = strings.ReplaceAll(dir, "~", ".")
}
return os.ExpandEnv(dir)
}