An engagement based washing machine that spins you round and round!
6
fork

Configure Feed

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

Fix image size limit and prevent infinite retry on errors

Brooke 82ff4525 fd703788

+20 -17
+15
cmd/brooke-spin/main.go
··· 104 104 currentState *state.State, 105 105 ) error { 106 106 // Fetch notifications 107 + log.Printf("Checking for notifications (already processed: %d)", len(currentState.ProcessedNotifications)) 107 108 notifications, newCursor, err := blueskyClient.ListNotifications(currentState.LastNotificationCursor, 50) 108 109 if err != nil { 109 110 return fmt.Errorf("failed to fetch notifications: %w", err) 110 111 } 112 + log.Printf("API returned %d total notifications", len(notifications)) 111 113 112 114 // Filter for unprocessed notifications that match configured types 113 115 var relevantNotifications []client.Notification 116 + var skippedCount int 114 117 for _, notif := range notifications { 115 118 // Skip if already processed 116 119 if currentState.ProcessedNotifications[notif.URI] { 120 + skippedCount++ 117 121 continue 118 122 } 119 123 // Check if notification type matches configured filters 120 124 if cfg.ShouldProcessNotification(notif.Reason) { 121 125 relevantNotifications = append(relevantNotifications, notif) 122 126 } 127 + } 128 + 129 + if skippedCount > 0 { 130 + log.Printf("Skipped %d already-processed notifications", skippedCount) 123 131 } 124 132 125 133 if len(relevantNotifications) == 0 { ··· 176 184 profile.Avatar = blobRef 177 185 log.Println("Updating profile...") 178 186 if err := blueskyClient.UpdateProfile(profile); err != nil { 187 + // Mark as processed even on failure to avoid infinite retry loops 188 + log.Printf("Failed to update profile: %v", err) 189 + currentState.ProcessedNotifications[notif.URI] = true 190 + // Save state to prevent retrying this notification 191 + if saveErr := stateManager.Save(currentState); saveErr != nil { 192 + log.Printf("Warning: failed to save state after error: %v", saveErr) 193 + } 179 194 return fmt.Errorf("failed to update profile: %w", err) 180 195 } 181 196
+5 -17
internal/image/processor.go
··· 103 103 } 104 104 } 105 105 106 - // Encode the image back to bytes 106 + // Always encode as JPEG with compression to keep file size under Bluesky's limit (976.56KB) 107 + // PNG with transparency can be too large 107 108 var buf bytes.Buffer 108 - switch format { 109 - case "jpeg", "jpg": 110 - if err := jpeg.Encode(&buf, masked, &jpeg.Options{Quality: 95}); err != nil { 111 - return nil, "", fmt.Errorf("failed to encode jpeg: %w", err) 112 - } 113 - case "png": 114 - if err := png.Encode(&buf, masked); err != nil { 115 - return nil, "", fmt.Errorf("failed to encode png: %w", err) 116 - } 117 - default: 118 - // Default to JPEG if format is unknown 119 - if err := jpeg.Encode(&buf, masked, &jpeg.Options{Quality: 95}); err != nil { 120 - return nil, "", fmt.Errorf("failed to encode jpeg: %w", err) 121 - } 122 - format = "jpeg" 109 + if err := jpeg.Encode(&buf, masked, &jpeg.Options{Quality: 85}); err != nil { 110 + return nil, "", fmt.Errorf("failed to encode jpeg: %w", err) 123 111 } 124 112 125 - return buf.Bytes(), format, nil 113 + return buf.Bytes(), "jpeg", nil 126 114 } 127 115 128 116 // GetMimeType returns the MIME type for an image format