Interactively go through your bluesky follow graph and decide to keep or remove follow records
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Query the terminal sixel area instead of using hardcoded font_size

yemou 9bf5c240 5a9d4e3a

+61 -13
+3 -3
flake.lock
··· 2 2 "nodes": { 3 3 "nixpkgs": { 4 4 "locked": { 5 - "lastModified": 1772963539, 6 - "narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=", 5 + "lastModified": 1773122722, 6 + "narHash": "sha256-FIqHByVqxCprNjor1NqF80F2QQoiiyqanNNefdlvOg4=", 7 7 "owner": "NixOS", 8 8 "repo": "nixpkgs", 9 - "rev": "9dcb002ca1690658be4a04645215baea8b95f31d", 9 + "rev": "62dc67aa6a52b4364dd75994ec00b51fbf474e50", 10 10 "type": "github" 11 11 }, 12 12 "original": {
+58 -10
main.go
··· 16 16 "net/http" 17 17 "net/url" 18 18 "os" 19 + "strconv" 20 + "strings" 19 21 20 22 "github.com/bluesky-social/indigo/api/atproto" 21 23 "github.com/bluesky-social/indigo/api/bsky" ··· 31 33 32 34 //go:embed static/callback.html 33 35 var callbackHTML []byte 34 - 35 - const font_size = 16 36 36 37 37 func callbackListener(ctx context.Context, result chan url.Values) (int, error) { 38 38 listener, err := net.Listen("tcp", ":0") ··· 98 98 } 99 99 100 100 func main() { 101 + if term.IsTerminal(int(os.Stdin.Fd())) == false { 102 + log.Fatal("Expected to be running inside of a terminal emulator") 103 + } 104 + 101 105 handle := flag.String("h", "", "Account handle to use") 102 106 // collection := flag.String("c", "likes", "Collection to sift ('likes' or 'follows')") 103 107 flag.Parse() ··· 196 200 imageHeight := avatarImg.Bounds().Max.Y 197 201 imageRatio := imageWidth / imageHeight 198 202 199 - terminalWidth, terminalHeight, err := term.GetSize(0) 203 + oldState, err := term.MakeRaw(int(os.Stdin.Fd())) 200 204 if err != nil { 201 205 log.Fatal(err) 202 206 } 203 207 204 - if terminalWidth > terminalHeight { 205 - terminalWidth = terminalHeight * imageRatio 208 + // The first escape sequence queries the sixel area while the second queries the cursor's relative 209 + // position. The second sequence's output isn't used, it is just there since all terminals support it so we 210 + // know we won't block forever while reading. 211 + fmt.Printf("\x1b[?2;1;0S\x1b[6n") 212 + 213 + hasSixelArea := false 214 + queryResult := "" 215 + b := make([]byte, 1) 216 + 217 + for { 218 + // This is the end of the cursor location query 219 + if b[0] == 'R' { 220 + break 221 + } 222 + 223 + os.Stdin.Read(b) 224 + 225 + if !hasSixelArea { 226 + queryResult += string(b) 227 + } 228 + 229 + if len(queryResult) != 0 && queryResult[len(queryResult)-1] == 'S' { 230 + hasSixelArea = true 231 + } 232 + } 233 + 234 + term.Restore(int(os.Stdin.Fd()), oldState) 235 + 236 + if !hasSixelArea { 237 + log.Fatal("Failed to get sixel area") 238 + } 239 + 240 + sixelArea := strings.Split(queryResult, ";") 241 + 242 + terminalSixelWidth, err := strconv.Atoi(sixelArea[2]) 243 + if err != nil { 244 + log.Fatal(err) 245 + } 246 + 247 + terminalSixelHeight, err := strconv.Atoi(sixelArea[3][0 : len(sixelArea[3])-1]) 248 + if err != nil { 249 + log.Fatal(err) 250 + } 251 + 252 + if terminalSixelWidth > terminalSixelHeight { 253 + terminalSixelWidth = terminalSixelHeight * imageRatio 206 254 } else { 207 - terminalHeight = terminalWidth / imageRatio 255 + terminalSixelHeight = terminalSixelWidth / imageRatio 208 256 } 209 257 210 - // TODO: Make the FONT_SIZE configureable via cli flag or figure 211 - // out a way to get the cell height from the terminal 212 - maxImageWidth := (terminalWidth / 2) * font_size 213 - maxImageHeight := (terminalHeight / 2) * font_size 258 + // TODO: Instead of just doing half of the terminal size, we probably want a minimum size that we want to 259 + // display 260 + maxImageWidth := (terminalSixelWidth / 2) 261 + maxImageHeight := (terminalSixelHeight / 2) 214 262 215 263 maxImageRatio := maxImageWidth / maxImageHeight 216 264