shithub: hell

ref: cd81887caa011b15968a6c8a926171a8119c516c
dir: /main.go/

View raw version
package main

import (
	"context"
	"fmt"
	
	"strconv"
	"strings"

	mastodon "codeberg.org/penny64/hellclient-go-mastodon"
	"github.com/k3a/html2text"
)

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

	rl := hc.rl
	client := *hc.client
	enablePipeHack(rl)

	homeMap := hc.homeMap
	lastindex := ""
	recentpost := &hc.recentpost
	var lastaccount *mastodon.Account


	go StreamHomeTimeline(&client, homeMap, hc)

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

			command, arguments, found := processInput(line, []string{})

			//empty line
			if command == "" && arguments == "" && err == nil {
				hc.togglepause()
				return
			}

			if command == "" && arguments == "" && err != nil {
				return
			}

			//if we didn't get a slash command then the user is just posting
			if command == "" && arguments != "" {
				hc.dispatchStatus(line, "public")
				return
			}

			result, err := hc.cmdload.run(line)
			if err != nil {
				fmt.Print(err)
			}
			fmt.Printf(result)
			return

			if !found {
				fmt.Printf("Command not found: \"%s\"\n", command)
				return
			}

			hc.lock()
			defer hc.unlock()

			index, content, _ := strings.Cut(arguments, " ")
			
			



			postItem, postOK := homeMap[index]

			//Wether we got a post index or not
			foundindex := false
			//If there's no index selected load the last post we operated on
			if postOK {
				foundindex = true
				lastindex = index
				lastaccount = nil
			} else {
				postItem, postOK = homeMap[lastindex]
			}
			
			var reblogger *mastodon.Status
			//Okay now see if the post we end up with is a reblog
			if postOK {
				if postItem.Reblog != nil {
					reblogger = postItem
					postItem = postItem.Reblog
					
				}
			}
			cmdctx, _ := hc.cmdload.processLine(line)
			hc.PrintObjectProperties(cmdctx.account)
			hc.PrintObjectProperties(cmdctx.status)
			hc.PrintObjectProperties(cmdctx.reblogger)
			fmt.Println(cmdctx.raw_argument)
			fmt.Println(cmdctx.command)
			fmt.Println(cmdctx.content)
			fmt.Println(cmdctx.index)

			accByNameOrRef := func() (account *mastodon.Account)  {
				if lastaccount != nil {
					account = lastaccount
					return
				}
				if lastindex != "" {
					account = &postItem.Account
					return
				}
				account = hc.resolveAccount(arguments)
				lastindex = ""
				postItem = nil
				lastaccount = account
				return
			}
			formatter := &StatusFormatter{prefs: hc.preferences, status: postItem, postContext: hc.ctxref, localindex: index}
			templater := newStatusTemplateRenderer(formatter)

			//Commands require status indexes
			switch command {
			case "mark":
				if !postOK {
					fmt.Printf("mark requires a status to operate on\n")
					return
				}
				markfunc := func() { _, err = client.Bookmark(context.Background(), postItem.ID) }
				hc.dispatchAnon(markfunc).Wait()
				if err != nil {
					printMastodonErr(err)
				} else {
					line, _ := templater.render("Bookmarked: $index $username $content $media_descriptions\n")
					fmt.Print(line)
				}
				return
			case "unmark":
				if !postOK {
					fmt.Printf("unmark requires a status to operate on\n")
					return
				}
				var postCopy *mastodon.Status
				unmarkfunc := func() {
					postCopy, err = client.GetStatus(context.Background(), postItem.ID)
				}
				hc.dispatchAnon(unmarkfunc).Wait()
				if err != nil {
					fmt.Printf("Error removing bookmark: %s\n", err)
					return
				}
				if !postCopy.Bookmarked.(bool) {
					fmt.Printf("Post not bookmarked.\n")
					return
				}
				hc.dispatchAnon(func() { _, err = client.Unbookmark(context.Background(), postItem.ID) }).Wait()
				if err != nil {
					printMastodonErr(err)
				} else {
					line, _ := templater.render("Unbookmarked: $index $username $content $media_descriptions\n")
					fmt.Print(line)
				}
				return
			case "open":
				if !postOK {
					fmt.Printf("open requires a status to operate on\n")
					return
				}

				url := fmt.Sprintf("%v/statuses/%v", client.Config.Server, postItem.ID)
				openItemInOS(hc.preferences.Browser, url)
				return
			case "url":
				_, indexstr, _ := strings.Cut(arguments, " ")
				urlindex, err := strconv.Atoi(indexstr)
				if err != nil {
					urlindex = 1
				}
				if urlindex > len(hc.homeref.urlmap[index]) {
					fmt.Printf("Bad url index\n")
					return
				}
				openItemInOS(hc.preferences.Browser, hc.homeref.urlmap[index][urlindex-1])
				return
			case "play":
				_, indexstr, _ := strings.Cut(arguments, " ")
				urlindex, err := strconv.Atoi(indexstr)
				if err != nil {
					urlindex = 1
				}
				if urlindex > len(hc.homeref.urlmap[index]) {
					fmt.Printf("Bad url index\n")
					return
				}
				openItemInOS(hc.preferences.MediaPlayer, hc.homeref.urlmap[index][urlindex-1])
				return
			case "view":
				err := hc.previewPostImages(postItem, hc.preferences.ImageViewer)
				if err != nil {
					fmt.Printf("Image preview failed: %v\n", err)
				}
				return
			case "import":
				err := hc.previewPostImages(postItem, hc.preferences.MediaImport)
				if err != nil {
					fmt.Printf("Image preview failed: %v\n", err)
				}
				return
			case "download":
				savePostImages(postItem, hc.preferences.Save_Location)
				return
			case "hrt":
				// We want to filter RTs from the RTer
				if reblogger != nil {
					postItem = reblogger
				}
				account := accByNameOrRef()
				if account == nil {
					fmt.Printf("Account lookup failed.\n")
					return
				}
				relationships, err := hc.client.GetAccountRelationships(context.Background(), []string{string(account.ID)})
				if err != nil {
					fmt.Printf("Error loading relationship.\n")
					return
				}
				relationship := relationships[0]
				if !relationship.Following {
					fmt.Printf("can't filter rts from user you don't follow!\n")
					return
				}
				if relationship.ShowingReblogs {
					_, err := hc.client.AccountFollowDetailed(context.Background(), account.ID, true, relationship.Notifying)
					if err != nil {
						fmt.Printf("Error updating settings\n")
						return
					}
					fmt.Printf("No longer showing RTs from <%s>\n", account.Acct)
					return
				}
				//Turn them back on if they were off!
				_, err = hc.client.AccountFollowDetailed(context.Background(), account.ID, false, relationship.Notifying)
				if err != nil {
					fmt.Printf("Error updating settings\n")
					return
				}
				fmt.Printf("Now showing RTs from <%s>\n", account.Acct)
				return
			case "rt":
				rtfunc := func() {
					rtStatus, err := client.Reblog(context.Background(), postItem.ID)
					if err != nil {
						fmt.Println(err)
						return
					}
					*recentpost = rtStatus
					hc.printAndIncrement(hc.ctxref, rtStatus)
					return
				}
				hc.dispatchAnon(rtfunc).Wait()
				return
			case "parent":
				parentfunc := func() {
					if postItem.InReplyToID == nil {
						fmt.Printf("%v doesn't have a parent\n", index)
						return
					}
					parentStatus, _ := client.GetStatus(context.Background(), mastodon.ID(postItem.InReplyToID.(string)))
					hc.printAndIncrement(hc.ctxref, parentStatus)
					return
				}
				hc.dispatchAnon(parentfunc).Wait()
				return
			case "children":
				childfunc := func() {
					context, err := client.GetStatusContext(context.Background(), postItem.ID)
					if err != nil {
						fmt.Println(err)
						return
					}
					if len(context.Descendants) == 0 {
						fmt.Printf("\"%s\" has no children\n", index)
					}
					for post := range context.Descendants {
						hc.printAndIncrement(hc.ctxref, context.Descendants[post])
					}
					return
				}
				hc.dispatchAnon(childfunc).Wait()
				return
			case "edit":
				if content == "" || content == " " {
					if (postItem == nil) || postItem.Account.ID != hc.currentuser.ID {
						fmt.Printf("cannot edit other's statuses!\n")
						return
					}
					fixedHTML, err := prepareForEdit(postItem)
					if err != nil {
						fmt.Printf("Error loading post HTML: %s\n", err)
						return
					}
					rl.SetDefault(fmt.Sprintf("/edit %v %v", index, html2text.HTML2TextWithOptions(fixedHTML, html2text.WithUnixLineBreaks())))
					return
				}
				var MediaIDs []mastodon.ID
				for _, media := range postItem.MediaAttachments {
					MediaIDs = append(MediaIDs, media.ID)
				}
				toot := &mastodon.Toot{
					Status:      content,
					MediaIDs:    MediaIDs,
					Sensitive:   postItem.Sensitive,
					SpoilerText: postItem.SpoilerText,
					Visibility:  postItem.Visibility,
					Language:    postItem.Language,
				}
				if postItem.InReplyToID != nil {
					id := mastodon.ID(postItem.InReplyToID.(string))
					toot.InReplyToID = id
				}
				editfunc := func() {
					_, err = client.UpdateStatus(context.Background(), toot, postItem.ID)
					if err != nil {
						fmt.Println(err)
						return
					}
				}
				hc.dispatchAnon(editfunc).Wait()
				return
			case "thread":
				hc.pause(true)
				hc.page = &Page{disablereverse: true}
				getter := &ThreadStatusGetter{target: postItem, client: hc.client}
				hc.page.loader = &StatusPages{hc: hc, getter: getter}
				fmt.Print(hc.page.String())
				return
			case "pinned":
				var account *mastodon.Account
				if foundindex || index == "" {
					account = &postItem.Account
				} else {
					account = hc.resolveAccount(index)
					if account == nil {
						return
					}
				}

				hc.pause(true)
				hc.page = &Page{}
				hc.page.itembuffer = new([]PageItem)
				getter := &PinnedStatusGetter{client: hc.client, ID: account.ID}
				hc.page.loader = &StatusPages{hc: hc, getter: getter}
				fmt.Print(hc.page.String())
				return
			case "account":
				account := accByNameOrRef()
				if account == nil {
					fmt.Printf("Account lookup failed.\n")
					return
				}
				hc.pause(true)
				hc.page = &Page{}
				hc.page.itembuffer = new([]PageItem)
				getter := &AccountStatusGetter{client: hc.client, ID: account.ID}
				hc.page.loader = &StatusPages{hc: hc, getter: getter}
				fmt.Print(hc.page.String())
				return
			case "unfollow":
				account := accByNameOrRef()
				if account == nil {
					fmt.Printf("Account lookup failed.")
					return
				}
				var relationship *mastodon.Relationship
				unfollowfunc := func(job *GenericJob) { relationship, err = hc.client.AccountUnfollow(context.Background(), account.ID) }
				unfollowjob := hc.dispatchFunc(unfollowfunc)
				unfollowjob.Wait()
				if err != nil {
					fmt.Printf("Error unfollowing account: %s\n", err)
					return
				}
				if !relationship.Following {
					fmt.Printf("Successfully unfollowed %s\n", index)
					return
				}
				fmt.Printf("Unknown failure, account is still followed\n")
				return

			case "follow":				
				account := accByNameOrRef()
				if account == nil {
					fmt.Printf("Account lookup failed.\n")
					return
				}
				var relationship *mastodon.Relationship
				followfunc := func(job *GenericJob) { relationship, err = hc.client.AccountFollow(context.Background(), account.ID) }
				followjob := hc.dispatchFunc(followfunc)
				followjob.Wait()
				if err != nil {
					fmt.Printf("Error requesting follow: %s\n", err)
					return
				}
				if relationship.Following {
					fmt.Printf("Successfully followed %s\n", account.Acct)
					return
				}
				if relationship.Requested {
					fmt.Printf("Follow request sent to %s\n", account.Acct)
					return
				}
			case "fpost":
				_, err := hc.filterStatus(postItem)
				if err != nil {
					fmt.Printf("Error filtering post: %v\n", err)
					return
				}
				url := fmt.Sprintf("%v/statuses/%v", client.Config.Server, postItem.ID)
				fmt.Printf("Filtered %v\n", url)
				return
			case "ufpost":
				_, err := hc.unfilterStatus(postItem)
				if err != nil {
					fmt.Printf("Error unfiltering post: %v\n", err)
					return
				}
				line, _ := templater.render("Unfiltered: %s> $standard_or_subject\n")
				fmt.Print(line)
				return
			case "block":
				var account *mastodon.Account
				if foundindex || index == "" {
					account = &postItem.Account
				} else {
					account = hc.resolveAccount(index)
					if account == nil {
						fmt.Printf("Account or index not found.\n")
						return
					}
				}
				blockfunc := func() {
					_, err := client.AccountBlock(context.Background(), account.ID)
					if err != nil {
						fmt.Printf("Error blocking account: %s.\n")
						return
					}
					fmt.Printf("Account blocked: %s\n", account.Acct)
				}
				hc.dispatchAnon(blockfunc).Wait()
				return
			case "unblock":
				var account *mastodon.Account
				if foundindex || index == "" {
					account = &postItem.Account
				} else {
					account = hc.resolveAccount(index)
					if account == nil {
						fmt.Printf("Account or index not found.\n")
						return
					}
				}
				unblockfunc := func() {
					_, err := client.AccountBlock(context.Background(), account.ID)
					if err != nil {
						fmt.Printf("Error blocking account: %s.\n")
						return
					}
					fmt.Printf("Account unblocked: %s\n", account.Acct)
				}
				hc.dispatchAnon(unblockfunc).Wait()
				return
			}

			//Posts that need an index and an argument
			if content == "" {
				fmt.Printf("\"%v\" requires an argument\n", command)
				return
			}
		}()
	}
}