-
Notifications
You must be signed in to change notification settings - Fork 297
feat: Add Blossom media server upload support #3438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Implements foundational Blossom protocol support (BUD-01, BUD-02) for uploading blobs to Blossom media servers. Key components: - BlossomTypes.swift: Server URL wrapper, blob descriptor, error types - BlossomAuth.swift: Kind 24242 authorization event creation (differs from NIP-98 by using ["t", action], ["x", sha256], ["expiration"]) - BlossomUploader.swift: PUT /upload with raw binary body Unlike NIP-96 uploaders (nostr.build), Blossom uses: - PUT method instead of POST - Raw binary body instead of multipart form-data - Kind 24242 auth instead of NIP-98 kind 27235 - SHA256 hash of file required for authorization Also adds NostrKind cases for blossom_auth (24242) and blossom_server_list (10063). Closes: damus-io#3218 (partial) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: alltheseas <[email protected]>
Implements BUD-03 user server list support for tracking user's preferred Blossom media servers. New files: - BlossomServerList.swift: Model for kind 10063 events - Parses ["server", url] tags from events - Converts to NostrEvent for publishing - Supports adding/removing servers immutably - BlossomServerListManager.swift: Manages server list state - Loads from NostrDB or manual settings - Publishes updates to relays - Follows UserRelayListManager pattern Settings additions: - latestBlossomServerListEventIdHex: Event ID for NostrDB lookup - manualBlossomServerUrl: Primary method for v1 - direct URL entry without requiring kind 10063 event publishing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: alltheseas <[email protected]>
Adds Settings UI for configuring Blossom media servers. New views: - MediaServerSettingsView: Main settings view for media upload servers - Default uploader picker (nostr.build, nostrcheck, Blossom) - Blossom server configuration section (visible when Blossom selected) - Current server display, change/remove server buttons - AddBlossomServerView: Sheet for entering/editing Blossom server URL - URL validation with error feedback - Paste from clipboard support - Public server examples for quick setup MediaUploader changes: - Added .blossom case to enum - Blossom uses kind 24242 auth (not NIP-98) - Server URL retrieved from settings at upload time Integration: - Router: Added MediaServerSettings route - ConfigView: Added "Media Servers" navigation link - AppearanceSettingsView: Shows server status/warning when Blossom selected 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: alltheseas <[email protected]>
Connects BlossomUploader to the existing media upload infrastructure so users can actually upload images and videos via Blossom. Key changes to AttachMediaUtility: - Added uploadViaBlossom() helper method that: - Gets server URL from UserSettingsStore.shared - Validates keypair availability - Loads media data and calls BlossomUploader - Maps BlossomUploadResult to ImageUploadResult - Modified create_upload_request() to branch early for Blossom - Checks if uploader is .blossom via type cast - Calls uploadViaBlossom() instead of NIP-96 flow Also adds Blossom core files (Types, Auth, Uploader) to the DamusNotificationService target to resolve build errors. Changelog-Added: Added Blossom media server upload support Closes: damus-io#3218 Signed-off-by: alltheseas <[email protected]>
|
@fishcakeday can you review ser |
|
@lovvtide I tested the auth blossom upload flow via iOS Damus to satellite blossom server successfully. Any feedback on this blossom upload PR for iOS Damus? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for uploading media to Blossom servers as an alternative to the existing nostr.build and nostrcheck uploaders. The implementation includes a complete Blossom client (BUD-01/BUD-02), settings UI for server configuration, and integration with the existing media upload flow. The initial version uses manually configured server URLs stored in settings, with kind 10063 server list event support (BUD-03) planned for a future release.
Key changes:
- Core Blossom client implementation with kind 24242 authorization, PUT-based uploads with raw binary bodies, and SHA256 hash-based authentication
- Settings UI for selecting Blossom as the default uploader and configuring server URLs
- Integration with existing AttachMediaUtility that branches to Blossom upload for the new uploader type
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
damus/Core/Blossom/BlossomTypes.swift |
Defines core types: BlossomServerURL wrapper with validation, BlossomBlobDescriptor response model, error types, and upload result enum |
damus/Core/Blossom/BlossomAuth.swift |
Implements kind 24242 authorization event creation with required tags (t, x, expiration) and base64 encoding for HTTP headers |
damus/Core/Blossom/BlossomUploader.swift |
Implements PUT /upload endpoint with raw binary body, SHA256 computation, and blob descriptor response parsing |
damus/Core/Blossom/BlossomServerList.swift |
Models kind 10063 server list events with parsing from NostrEvent/NdbNote and conversion to publishable events |
damus/Core/Blossom/BlossomServerListManager.swift |
Manager class for fetching, storing, and publishing server lists (follows UserRelayListManager pattern but not yet instantiated) |
damus/Features/Settings/Views/MediaServerSettingsView.swift |
Main settings view for selecting default uploader and configuring Blossom server URL |
damus/Features/Settings/Views/AddBlossomServerView.swift |
Sheet for adding/editing Blossom server URLs with validation, clipboard paste, and example servers |
damus/Features/Settings/Views/ConfigView.swift |
Adds Media Servers navigation link to settings |
damus/Features/Settings/Views/AppearanceSettingsView.swift |
Updates uploader picker to show Blossom server status and configuration warnings |
damus/Shared/Media/Images/AttachMediaUtility.swift |
Adds uploadViaBlossom function and early branching logic to route Blossom uploads separately from NIP-96 uploads |
damus/Shared/Media/Models/MediaUploader.swift |
Adds .blossom case with appropriate property values (empty nameParam, no NIP-98 requirement, empty postAPI) |
damus/Shared/Utilities/Router.swift |
Adds MediaServerSettings route for navigation |
damus/Features/Settings/Models/UserSettingsStore.swift |
Adds Blossom-specific settings: latestBlossomServerListEventIdHex and manualBlossomServerUrl |
damus/Core/Nostr/NostrKind.swift |
Adds blossom_auth (24242) and blossom_server_list (10063) event kinds |
damus/Features/Timeline/Models/HomeModel.swift |
Adds cases for blossom_auth and blossom_server_list in event processing switch |
damus/Features/Events/Models/LoadableNostrEventView.swift |
Adds Blossom kinds to unsupported event types list |
damus.xcodeproj/project.pbxproj |
Adds new Blossom source files to build targets |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Addressing the comments, and noting that claude takes exception with copilots diagnosis, and proposed solutions 🙂 |
Update comment to accurately reflect that kind 10063 server list support is planned for future release, and v1 uses manual server URL in settings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Thread URLSessionTaskDelegate through Blossom upload path to enable upload progress tracking, matching the existing NIP-96 upload behavior. Changes: - Add progressDelegate parameter to BlossomUploader.upload() - Pass delegate to URLSession.shared.data(for:delegate:) - Update AttachMediaUtility to forward progress delegate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add comprehensive unit tests for Blossom authentication and upload functionality (32 tests total). BlossomAuthTests (11 tests): - Kind 24242 event creation and signing - Required tags (t, x, expiration) - Base64 encoding and header format - Custom expiration support BlossomUploaderTests (21 tests): - BlossomServerURL validation and endpoints - BlossomBlobDescriptor JSON parsing - Error descriptions - Upload result handling - Hashable/Equatable/Codable conformance 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
@jb55 comments are addressed |
fishcakeday
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took a look, but did not do in depth analyses. Looking good so far.
|
Thanks @fishcakeday, investigating. Your feedback reminded me to test out video support. |
- Add streaming SHA256 computation to avoid loading entire file into memory - Add file-based upload using URLSession.upload(fromFile:) for large files - Fix processVideo() missing return statement that caused video uploads to fail - Fix MediaPicker to copy videos immediately before temp file is deleted - Auto-select streaming upload for files >1MB, in-memory for smaller files - Add unit tests for streaming SHA256 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
Video support works on my local build: https://damus.io/nevent1qqsz9x638y7d8gquk8kv22zr54hntm8af5kd38qg0ca2z4e0q4m5szsvn6cq9
|
nostr.download (Route96) is a Blossom-compatible media server that implements BUD-01 through BUD-09. Added to the suggested servers list for easier user onboarding. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Implements blob mirroring per BUD-04 specification for redundancy: BlossomUploader.swift: - Add mirror() function implementing PUT /mirror endpoint - Add mirrorToServersInBackground() for fire-and-forget mirroring - Server downloads blob from source URL (more efficient than re-upload) UserSettingsStore.swift: - Add blossomMirrorEnabled toggle setting - Add blossomMirrorServers array for configured backup servers - JSON encoding for array storage in UserDefaults AttachMediaUtility.swift: - Integrate mirror triggering after successful primary upload - Extract triggerBackgroundMirroring() helper with guard clauses - Mirroring runs in background, doesn't block upload response Flow: Upload to primary → Return URL → Background mirror to backups 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
MediaServerSettingsView.swift: - Add "Backup Mirrors" section with enable toggle - List configured mirror servers with swipe-to-delete - Add "Publish Server List" section for BUD-03 compliance AddBlossomMirrorServerView: - Sheet for adding mirror server URLs - Suggested servers list (primal, nostr.download, oxtr, satellite) - Validation: prevents duplicates and adding primary as mirror - Early returns with guard clauses for clean control flow Kind 10063 publication: - publishServerList() creates event with ordered server tags - Primary server first, then mirrors in configured order - Broadcasts via postbox to all connected relays - Caches event ID locally for retrieval This enables other clients to discover user's blob servers when media is unavailable from the original URL. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
- HTTPS-only: BlossomServerURL now rejects HTTP URLs for security - Fix tests to expect HTTP rejection (testServerURLRejectsHttp) - Fix testUploadWithInvalidServerURL to use HTTPS - Update UI error messages to say "https" only (not "http or https") - Add @mainactor to setManualServer() for concurrency safety - Add /media endpoint property for BUD-05 media optimization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
|
@fishcakeday latest commits should address your feedback. added blossom mirroring @BenGWeeks
|


Summary
Add Blossom media server upload support, allowing users to upload images and videos to their preferred Blossom server instead of nostr.build.
Screenshots
Key features:
Key differences from NIP-96 uploaders:
["u", url],["method", method]["t", "upload"],["x", sha256]Checklist
Standard PR Checklist
Closes:orFixes:tags in the commit messages wherever applicable, or made sure those are not needed. See Submitting patchesTest report
Device: iPhone 17 (Xcode Simulator)
iOS: iOS 26
Damus: Branch
add-blossom-upload(commit 70b7ece)Setup:
Steps:
https://blossom.primal.netandhttps://cdn.satellite.earth)Results:
Other notes
New files:
damus/Core/Blossom/BlossomTypes.swift- Server URL wrapper, blob descriptor, error typesdamus/Core/Blossom/BlossomAuth.swift- Kind 24242 authorization event creationdamus/Core/Blossom/BlossomUploader.swift- PUT /upload with raw binary bodydamus/Core/Blossom/BlossomServerList.swift- Kind 10063 server list modeldamus/Core/Blossom/BlossomServerListManager.swift- Server list state managementdamus/Features/Settings/Views/MediaServerSettingsView.swift- Main settings viewdamus/Features/Settings/Views/AddBlossomServerView.swift- Add/edit server sheetModified files:
damus/Shared/Media/Images/AttachMediaUtility.swift- Added Blossom upload branchdamus/Shared/Media/Models/MediaUploader.swift- Added .blossom casedamus/Core/Nostr/NostrKind.swift- Added blossom_auth (24242), blossom_server_list (10063)damus/Features/Settings/Views/ConfigView.swift- Added Media Servers navigationdamus/Shared/Utilities/Router.swift- Added MediaServerSettings routeCloses #3218