Every like gives me a bigger pumpkin head

Should be compressing and doing resume on app password

+84 -28
base_images/base_big_head.jpg

This is a binary file and will not be displayed.

+84 -28
main.go
··· 1 1 package main 2 2 3 3 import ( 4 + "bytes" 4 5 "context" 5 6 "fmt" 6 - "io" 7 - 8 7 "image" 9 8 "image/draw" 10 9 "image/jpeg" 11 10 "image/png" 11 + "io" 12 12 "log" 13 13 "os" 14 14 "os/signal" ··· 18 18 comatproto "github.com/bluesky-social/indigo/api/atproto" 19 19 appbsky "github.com/bluesky-social/indigo/api/bsky" 20 20 "github.com/bluesky-social/indigo/atproto/atclient" 21 + "github.com/bluesky-social/indigo/atproto/syntax" 21 22 lexutil "github.com/bluesky-social/indigo/lex/util" 22 - ) 23 - 24 - import ( 25 23 "github.com/coder/websocket" 26 - xdraw "golang.org/x/image/draw" 27 - 28 24 "github.com/joho/godotenv" 25 + xdraw "golang.org/x/image/draw" 29 26 ) 30 27 31 28 type PumpkinHead struct { ··· 72 69 bodyImg: bodyImg, 73 70 headImg: headImg, 74 71 callCount: 0, 75 - scaleStep: 0.00, // How much my big head grows each call 72 + scaleStep: 0.01, // How much my big head grows each call 76 73 }, nil 77 74 } 78 75 ··· 113 110 return output, nil 114 111 } 115 112 113 + // CompressImage compresses the image to JPEG format with the given quality (1-100) 114 + func CompressImage(img image.Image, quality int) (*bytes.Buffer, error) { 115 + buf := new(bytes.Buffer) 116 + err := jpeg.Encode(buf, img, &jpeg.Options{Quality: quality}) 117 + if err != nil { 118 + return nil, fmt.Errorf("failed to compress image: %w", err) 119 + } 120 + return buf, nil 121 + } 122 + 116 123 func saveToFiles(pumpkin *PumpkinHead, outputDir string, newPic image.Image) { 117 124 118 125 // Create output directory if it doesn't exist ··· 120 127 writeErrorAndExit(err) 121 128 } 122 129 123 - // Save to file 124 - filename := filepath.Join(outputDir, fmt.Sprintf("bighead_%03d.png", pumpkin.callCount)) 130 + filename := filepath.Join(outputDir, fmt.Sprintf("bighead_%03d.jpg", pumpkin.callCount)) 125 131 outFile, err := os.Create(filename) 126 132 if err != nil { 127 133 writeErrorAndExit(err) 128 134 } 129 - 130 135 defer outFile.Close() 131 136 132 - if err := png.Encode(outFile, newPic); err != nil { 137 + compressed, err := CompressImage(newPic, 80) 138 + if err != nil { 133 139 writeErrorAndExit(err) 134 140 } 141 + 142 + if _, err := outFile.Write(compressed.Bytes()); err != nil { 143 + writeErrorAndExit(err) 144 + } 145 + } 146 + 147 + type AuthSession struct { 148 + DID syntax.DID `json:"did"` 149 + Password string `json:"password"` 150 + AccessToken string `json:"access_token"` 151 + RefreshToken string `json:"session_token"` 152 + PDS string `json:"pds"` 135 153 } 136 154 137 155 type AtProtoStuff struct { 138 - //DID syntax.DID 139 - //accessToken string 140 - //refreshToken string 141 - Client *atclient.APIClient 156 + authSession AuthSession 157 + Client *atclient.APIClient 142 158 } 143 159 144 160 func Login(ctx context.Context, host, did, password string) (*AtProtoStuff, error) { 161 + 145 162 client, err := atclient.LoginWithPasswordHost(ctx, host, did, password, "", nil) 163 + 146 164 if err != nil { 147 165 return nil, err 148 166 } 167 + 168 + passAuth, ok := client.Auth.(*atclient.PasswordAuth) 169 + if !ok { 170 + return nil, fmt.Errorf("expected password auth") 171 + } 172 + 173 + sess := AuthSession{ 174 + DID: passAuth.Session.AccountDID, 175 + PDS: passAuth.Session.Host, 176 + Password: password, 177 + AccessToken: passAuth.Session.AccessToken, 178 + RefreshToken: passAuth.Session.RefreshToken, 179 + } 180 + 149 181 //client.Client. 150 - return &AtProtoStuff{Client: client}, nil 182 + return &AtProtoStuff{ 183 + authSession: sess, 184 + Client: client, 185 + }, nil 186 + } 187 + 188 + func (a *AtProtoStuff) authRefreshCallback(ctx context.Context, data atclient.PasswordSessionData) { 189 + fmt.Println("auth refresh callback") 190 + 191 + a.authSession.DID = data.AccountDID 192 + a.authSession.AccessToken = data.AccessToken 193 + a.authSession.RefreshToken = data.RefreshToken 194 + a.authSession.PDS = data.Host 151 195 } 152 196 153 197 func (a *AtProtoStuff) updatePumpkinHead(ctx context.Context, image io.Reader) (err error) { 154 198 199 + client := atclient.ResumePasswordSession(atclient.PasswordSessionData{ 200 + AccessToken: a.authSession.AccessToken, 201 + RefreshToken: a.authSession.RefreshToken, 202 + AccountDID: a.authSession.DID, 203 + Host: a.authSession.PDS, 204 + }, a.authRefreshCallback) 205 + 155 206 profileNsid := "app.bsky.actor.profile" 156 207 selfKey := "self" 157 208 158 209 currentProfileResp, err := comatproto.RepoGetRecord( 159 210 ctx, 160 - a.Client, 211 + client, 161 212 "", 162 213 profileNsid, 163 - a.Client.AccountDID.String(), 214 + client.AccountDID.String(), 164 215 selfKey) 165 216 166 217 if err != nil { ··· 218 269 if err != nil { 219 270 writeErrorAndExit(err) 220 271 } 221 - saveToFiles(pumpkin, "bighead", newHeadWhoDis) 272 + 273 + compressed, err := CompressImage(newHeadWhoDis, 80) 274 + if err != nil { 275 + log.Printf("Failed to compress image: %v", err) 276 + continue 277 + } 222 278 223 - //Incase i need to read the acutal record later 224 - //switch msgType { 225 - //case websocket.MessageText: 226 - // fmt.Printf("Received: %s\n", string(data)) 227 - //case websocket.MessageBinary: 228 - // fmt.Printf("Received binary: %d bytes\n", len(data)) 229 - //} 279 + if err := atProtoStuff.updatePumpkinHead(ctx, compressed); err != nil { 280 + log.Printf("Failed to update Bluesky profile: %v", err) 281 + } 230 282 } 231 283 } 232 284 ··· 252 304 writeErrorAndExit(err) 253 305 } 254 306 255 - ogPumpkinHead, err := os.Open("./base_images/base_big_head.png") 307 + //Resets back to a baseline pumpkinhead 308 + ogPumpkinHead, err := os.Open("./base_images/base_big_head.jpg") 309 + if err != nil { 310 + writeErrorAndExit(err) 311 + } 256 312 257 313 err = atProtoStuff.updatePumpkinHead(ctx, ogPumpkinHead) 258 314 if err != nil {