Why Nostr? What is Njump?
2024-09-17 08:13:28
in reply to

🐈‍⬛ on Nostr: ``` import { NSecSigner, NRelay1, NSchema as n } from '@nostrify/nostrify'; import { ...

```
import { NSecSigner, NRelay1, NSchema as n } from '@nostrify/nostrify';
import { BlossomUploader } from '@nostrify/nostrify/uploaders';
import * as nip19 from 'nostr-tools/nip19';

// Helper function to convert a hex string to Uint8Array
function hexToUint8Array(hex: string): Uint8Array {
if (hex.length % 2 !== 0) {
throw new Error("Hex string must have an even length");
}
const array = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
array[i / 2] = parseInt(hex.substr(i, 2), 16);
}
return array;
}

// Function to read uploaded files from JSON
async function readUploadedFiles(uploadedFilesPath: string): Promise<Set<string>> {
try {
const data = await Deno.readTextFile(uploadedFilesPath);
return new Set(JSON.parse(data));
} catch {
return new Set();
}
}

// Function to write uploaded files to JSON
async function writeUploadedFiles(uploadedFiles: Set<string>, uploadedFilesPath: string) {
await Deno.writeTextFile(uploadedFilesPath, JSON.stringify(Array.from(uploadedFiles)));
}

// Function to append a URL to a text file
async function appendUrlToFile(fileUrl: string, urlFilePath: string) {
try {
await Deno.writeTextFile(urlFilePath, fileUrl + '\n', { append: true });
console.log(`Appended URL to file: ${fileUrl}`);
} catch (error) {
console.error('Error appending URL to file:', error);
}
}

// Function to sign, parse, and upload a media file
async function signAndUploadMedia(
filePath: string,
uploadedFiles: Set<string>,
urlFilePath: string,
signer: NSecSigner,
relays: { relay: NRelay1; url: string }[]
) {
try {
// Check if the file has already been uploaded
if (uploadedFiles.has(filePath)) {
console.log(`File ${filePath} has already been uploaded. Skipping.`);
return;
}

// Get the public key from the signer
const pubkey = await signer.getPublicKey();

// Initialize the uploader
const uploader = new BlossomUploader({
servers: [
'https://cdn.satellite.earth';,
'https://nstore.nostrver.se';,
'https://blossom.puhcho.me';,
'https://blossom.primal.net';,
'https://cdn.nostrcheck.me';
],
signer: signer,
});

// Read the file
const fileBuffer = await Deno.readFile(filePath);
const file = new File([fileBuffer], filePath.split('/').pop()!);

// Upload the file and get the tags
const tags = await uploader.upload(file);

// Find the URL in the tags
let fileUrl = 'Unknown URL';
for (const tag of tags) {
if (tag[0] === "url" && tag[1]) {
fileUrl = tag[1];
break;
}
}

// Append the URL to the text file
await appendUrlToFile(fileUrl, urlFilePath);

// Create event data
const eventData = {
kind: 1,
content: `${fileUrl}`,
tags: tags,
created_at: Math.floor(Date.now() / 1000),
};

// Sign the event to get id and sig
const signedEvent = await signer.signEvent(eventData);
const completeEventData = {
...eventData,
id: signedEvent.id,
pubkey: pubkey,
sig: signedEvent.sig,
};

// Parse and validate the complete event data using NSchema
const event = n.event().parse(completeEventData);
console.log('Parsed and validated event:', event);

// Send the event to each relay
for (const { relay, url } of relays) {
try {
console.log(`Sending event to relay ${url}`);
await relay.event(event);
console.log(`Event sent successfully to ${url}`);
} catch (error) {
console.error(`Error sending event to relay ${url}:`, error);
} finally {
try {
await relay.close();
console.log(`Relay ${url} closed`);
} catch (closeError) {
console.error(`Error closing relay ${url}:`, closeError);
}
}
}

// Add the file to the uploaded files set and update the JSON file
uploadedFiles.add(filePath);
await writeUploadedFiles(uploadedFiles, './uploaded_files.json');

console.log("Done!");
} catch (error) {
console.error('Error signing and uploading media:', error);
}
}

// Function to select a random valid file from a folder
async function getRandomValidFileFromFolder(folderPath: string, uploadedFiles: Set<string>): Promise<string | null> {
const validExtensions = ['jpg', 'mp4', 'webp', 'gif'];
const files: string[] = [];

for await (const dirEntry of Deno.readDir(folderPath)) {
if (dirEntry.isFile) {
const extension = dirEntry.name.split('.').pop()?.toLowerCase();
if (extension && validExtensions.includes(extension)) {
files.push(dirEntry.name);
}
}
}

// Filter out files that have already been uploaded
const unuploadedFiles = files.filter(file => !uploadedFiles.has(`${folderPath}/${file}`));

if (unuploadedFiles.length === 0) {
console.log('All files have been uploaded. Selecting a random URL to publish.');
return null;
}

const randomIndex = Math.floor(Math.random() * unuploadedFiles.length);
return `${folderPath}/${unuploadedFiles[randomIndex]}`;
}

// Function to publish a Nostr event with a random URL
async function publishRandomUrlEvent(urlFilePath: string, signer: NSecSigner, relays: { relay: NRelay1; url: string }[]) {
try {
const urls = (await Deno.readTextFile(urlFilePath)).trim().split('\n');

if (urls.length === 0) {
console.error('No URLs found in the URL file.');
return;
}

const randomUrl = urls[Math.floor(Math.random() * urls.length)];

// Create event data
const eventData = {
kind: 1,
content: `${randomUrl}`,
tags: [],
created_at: Math.floor(Date.now() / 1000),
};

// Sign the event to get id and sig
const signedEvent = await signer.signEvent(eventData);
const completeEventData = {
...eventData,
id: signedEvent.id,
pubkey: await signer.getPublicKey(),
sig: signedEvent.sig,
};

// Parse and validate the complete event data using NSchema
const event = n.event().parse(completeEventData);
console.log('Parsed and validated event:', event);

for (const { relay, url } of relays) {
try {
console.log(`Sending event to relay ${url}`);
await relay.event(event);
console.log(`Event sent successfully to ${url}`);
} catch (error) {
console.error(`Error sending event to relay ${url}:`, error);
} finally {
try {
await relay.close();
console.log(`Relay ${url} closed`);
} catch (closeError) {
console.error(`Error closing relay ${url}:`, closeError);
}
}
}

console.log("Published random URL event successfully!");

} catch (error) {

console.error('Error publishing random URL event:', error);

}

}

// Main function to execute the script
async function main() {

const hexSecretKey = Deno.env.get('SECRET_KEY_HEX');
if (!hexSecretKey) {

console.error('Environment variable "SECRET_KEY_HEX" is not set.');
Deno.exit(1);

return;

}

const secretKey: Uint8Array = hexToUint8Array(hexSecretKey);

// Initialize the signer with your secret key

const signer = new NSecSigner(secretKey);

// Define the relay URLs

const relayUrls = [

'wss://nostr.mom',
'wss://nos.lol',
'wss://relay.primal.net',
'wss://e.nos.lol',
'wss://relay.damus.io',
'wss://nostr.lu.ke',
'wss://nostr.oxtr.dev',
'wss://relay.nostrcheck.me',
'wss://nostr.data.haus',
'wss://ditto.puhcho.me/relay',
'wss://offchain.pub',
'wss://strfry.iris.to'

];

// Create an array of NRelay1 instances with their URLs

const relays = relayUrls.map(url => ({ relay: new NRelay1(url), url }));

// Path to the JSON file that stores uploaded files

const uploadedFilesPath = './home/user/test_bloom/uploaded_files.json';

// Path to the text file that stores uploaded URLs

const urlFilePath = './home/user/test_bloom/uploaded_urls.txt';

// Example usage

const folderPath = Deno.env.get('MEDIA_FOLDER_PATH');

if (folderPath) {

try {

const uploadedFiles = await readUploadedFiles(uploadedFilesPath);

const randomFilePath = await getRandomValidFileFromFolder(folderPath, uploadedFiles);

if (randomFilePath) {

await signAndUploadMedia(randomFilePath, uploadedFiles, urlFilePath, signer, relays);

} else {

await publishRandomUrlEvent(urlFilePath, signer, relays);

}

} catch (error) {

console.error('Error during execution:', error);

} finally {

Deno.exit();

}

} else {

console.error('Environment variable "MEDIA_FOLDER_PATH" is not set.');

Deno.exit(1);

}

}

// Execute main function

main();

```

Better as it was uploading to just one blossom.
Author Public Key
npub15522kwl0kaf04t44xcvj6py5rhp9hzz936y5qlu48xacnuua4auqpc9emz