#
Blossom
low level
#
Example
final downloadResult = await ndk.blossom.getBlob(
sha256:
"b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553",
serverUrls: ["https://cdn.hzrd149.com"],
);
print(
"file of type: ${downloadResult.mimeType}, size: ${downloadResult.data.length}",
);
#
When to use
For a simpler, more generic API, check out
If no servers are specified the default user server list (kind 10063) is used for upload and delete.
The auth events get automatically signed and are valid for:
const Duration BLOSSOM_AUTH_EXPIRATION = Duration(minutes: 5);
#
methods - Blossom
#
uploadBlob
upload a blob, if serverMediaOptimisation is set to true the /media endpoint is used.
EventSigner _getSigner(EventSigner? customSigner) {
if (customSigner != null) return customSigner;
if (_accounts.canSign) {
return _accounts.getLoggedAccount()!.signer;
}
// Create a temporary signer if no account is logged in
final keyPair = Bip340.generatePrivateKey();
return Bip340EventSigner(
privateKey: keyPair.privateKey,
publicKey: keyPair.publicKey,
);
#
getBlob
Download the blob and use fallback if the blob is not found or the server is offline.
serverUrls ??= await _userServerList
.getUserServerList(pubkeys: [signer.getPublicKey()]);
if (serverUrls == null) {
throw Exception("User has no server list");
}
final stream = _blossomImpl.uploadBlob(
dataStreamFactory: () => Stream.value(data),
#
checkBlob
if you have a video player that uses a url you can use check to get a valid url first. Example can be found in NDK demo app
completedUploads: const [],
phase: UploadPhase.hashing,
progressPhase: hashProgress.progress,
);
if (hashProgress.isComplete && hashProgress.hash != null) {
fileHash = hashProgress.hash;
}
}
if (fileHash == null) {
throw Exception('Failed to compute file hash');
#
getBlobStream
Similar to getBlob, it streams the data, which is helpful for video files.
/// Throws an [Exception] if no SHA256 hash is detected in the URL
Future<List<BlobUploadResult>> mirrorToServers({
required Uri blossomUrl,
required List<String> targetServerUrls,
EventSigner? customSigner,
}) async {
final signer = _getSigner(customSigner);
// Extract sha256 from the URL
final sha256Match = sha256Regex.firstMatch(blossomUrl.toString());
#
listBlobs
Future<BlobResponse> getBlob({
required String sha256,
bool useAuth = false,
List<String>? serverUrls,
String? pubkeyToFetchUserServerList,
EventSigner? customSigner,
}) async {
Nip01Event? myAuthorization;
Nip01Event? signedAuthorization;
if (useAuth) {
#
deleteBlob
);
}
/// Downloads a blob directly to a file path (without loading into memory)
/// For native platforms (Windows, macOS, Linux, Android, iOS): uses actual file system paths
/// For web: triggers browser download dialog to save the file
///
/// if [serverUrls] is null, the userServerList is fetched from nostr. \
#
directDownload
if (pubkeyToFetchUserServerList == null) {
throw Exception(
"pubkeyToFetchUserServerList is null and serverUrls is null");
}
#
report
}
if (serverUrls == null) {
throw Exception("User has no server list");
}
return _blossomImpl.downloadBlobToFile(
sha256: sha256,
outputPath: outputPath,
authorization: signedAuthorization,
serverUrls: serverUrls,
);
}
/// checks if the blob exists on the server without downloading, useful to check before streaming a video via url \
#
methods - BlossomUserServerList
To get and set the user server list e.g. on settings page, you can use BlossomUserServerList
#
getUserServerList
/// Get user server list \
/// returns list of server urls \
/// returns null if the user has no server list
Future<List<String>?> getUserServerList({
required List<String> pubkeys,
}) async {
#
publishUserServerList
/// Publish user server list \
/// order of [serverUrlsOrdered] is important, the first server is the most trusted server
Future<List<RelayBroadcastResponse>> publishUserServerList({
required List<String> serverUrlsOrdered,
}) async {