shithub: hell

ref: a0fcdc0c539634670f2fa71d72831c22f2ec10a4
dir: /config.go/

View raw version
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)
}