shithub: hell

ref: cc7e785c8e24ddf31409fdefaf3eb26b7b90bbbf
dir: /main.go/

View raw version
package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"

	"github.com/chzyer/readline"
	"github.com/mattn/go-mastodon"
)

func main() {
	account, err := loadConfig()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		return
	}

	client := initClient(account)

	rl, _ := readline.New("> ")

	//Horrible io pipe hack
	//Replaces system stdout with the readline one
	r, w, _ := os.Pipe()
	os.Stdout = w

	go func() {
		io.Copy(rl.Stdout(), r)
	}()

	homeMap := make(map[string]*mastodon.Status)
	debugMap := make(map[string]interface{})
	postref := "a"
	var recentpost *mastodon.Status

	currentUser, err := client.GetAccountCurrentUser(context.Background())

	if err != nil {
		fmt.Println("Couldn't get our own profile: %v\n", err)
		return
	}

	go StreamHomeTimeline(client, rl, homeMap)

	for {
		line, err := rl.Readline()

		if err != nil {
			fmt.Println("Error:", err)
			return
		}
		command, arguments := processInput(line)

		//if we didn't get a slash command then the user is just posting
		if command == "" && arguments != "" {
			recentpost, err = postStatus(fmt.Sprintf(line), account, *client, "public")
			if err != nil {
				fmt.Println(err)
			}
			continue
		}

		index, content, _ := strings.Cut(arguments, " ")
		postItem, postOK := homeMap[index]
		debugItem, debugOK := debugMap[index]

		//Contextual commands that need to handle their own requirements
		switch command {
		case "rm":
			if !postOK && recentpost != nil {
				err = client.DeleteStatus(context.Background(), recentpost.ID)
				if err != nil {
					fmt.Println(err)
				}
				recentpost = nil
				continue
			}
			if !postOK {
				fmt.Println("No recent status to delete or post index not valid")
				continue
			}
			err = client.DeleteStatus(context.Background(), postItem.ID)
			if err != nil {
				fmt.Println(err)
			}
			continue
		}

		if arguments == "" {
			fmt.Printf("%v requires an argument\n", command)
			continue
		}

		//Commands that don't take an index
		switch command {
		case "dm":
			recentpost, err = postStatus(arguments, account, *client, "direct")
			if err != nil {
				fmt.Println(err)
			}
			continue
			if !postOK && !debugOK {
				fmt.Printf("\"%v\" not a valid index\n", index)
				continue
			}
		}

		//Commands that accept debug indexes
		switch command {
		case "examine":
			if postOK {
				PrintObjectProperties(postItem, debugMap)
				continue
			}
			PrintObjectProperties(debugItem, debugMap)
			continue
		}

		//if a user passes a debug index to a status command
		if !postOK {
			fmt.Printf("\"%v\" not a valid post index\n", index)
			continue
		}
		//Commands require status indexes
		switch command {
		case "like":
			_, err := client.Favourite(context.Background(), postItem.ID)
			if err != nil {
				printMastodonErr(err)
			} else {
				fmt.Printf(formatFavorite(postItem, arguments) + "\n")
			}
		case "mark":
			_, err := client.Bookmark(context.Background(), postItem.ID)
			if err != nil {
				printMastodonErr(err)
			} else {
				fmt.Printf(formatBookmark(postItem, arguments) + "\n")
			}
		case "unmark":
			_, err := client.Unbookmark(context.Background(), postItem.ID)
			if err != nil {
				printMastodonErr(err)
			} else {
				fmt.Printf(formatUnbookmark(postItem, arguments) + "\n")
			}
		case "open":
			url := fmt.Sprintf("%v/statuses/%v", client.Config.Server, postItem.ID)
			cmd := exec.Command("open", url, "-a", "Eldritch Café")
			cmd.Run()
		case "preview":
			err := previewPostImages(postItem, "qlmanage -p")
			if err != nil {
				fmt.Printf("Image preview failed: %v\n", err)
			}
		case "download":
			savePostImages(postItem, "/Users/penny/Downloads/")
		case "reply":
			if currentUser.ID == postItem.Account.ID {
				recentpost, err = postReply(content, account, *client, postItem.Visibility, postItem.ID)
				if err != nil {
					fmt.Println(err)
				}
				continue
			}
			recentpost, err = postReply("@"+getUserString(postItem)+" "+content, account, *client, postItem.Visibility, postItem.ID)
			if err != nil {
				fmt.Println(err)
			}
			continue
		case "rt":
			rtStatus, err := client.Reblog(context.Background(), postItem.ID)
			if err != nil {
				fmt.Println(err)
				continue
			}
			recentpost = rtStatus
			saveWorkRef(homeMap, rtStatus, postref)
			printPost("?"+postref, rtStatus)
			postref = IncrementString(postref)
		case "parent":
			if postItem.InReplyToID == nil {
				fmt.Printf("%v doesn't have a parent\n", index)
				continue
			}
			parentStatus, _ := client.GetStatus(context.Background(), mastodon.ID(postItem.InReplyToID.(string)))
			saveWorkRef(homeMap, parentStatus, postref)
			printPost("?"+postref, parentStatus)
			postref = IncrementString(postref)
		case "children":
			context, err := client.GetStatusContext(context.Background(), postItem.ID)
			if err != nil {
				fmt.Println(err)
				continue
			}
			if len(context.Descendants) == 0 {
				fmt.Printf("\"%v\" has no children")
			}
			for post := range context.Descendants {
				saveWorkRef(homeMap, context.Descendants[post], postref)
				printPost("?"+postref, context.Descendants[post])
				postref = IncrementString(postref)
			}
		case "thread":
			context, err := client.GetStatusContext(context.Background(), postItem.ID)
			if err != nil {
				fmt.Println(err)
				continue
			}

			for post := range context.Ancestors {
				saveWorkRef(homeMap, context.Ancestors[post], postref)
				printPost("?"+postref, context.Ancestors[post])
				postref = IncrementString(postref)
			}

			printPost(index, postItem)

			for post := range context.Descendants {
				saveWorkRef(homeMap, context.Descendants[post], postref)
				printPost("?"+postref, context.Descendants[post])
				postref = IncrementString(postref)
			}

		default:
			fmt.Printf("Unimplemented command \"%v\"?\"\n", command)
		}
	}
}