Why Nostr? What is Njump?
2024-09-16 09:37:09
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;
}

// Main function to execute the script
async function main() {
// Retrieve the secret key from an environment variable
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.nostr.band' ];
// 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 = './uploaded_files.json';

// Path to the text file that stores uploaded URLs
const urlFilePath = './uploaded_urls.txt';
// Function to read uploaded files from JSON
async function readUploadedFiles(): 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>) {
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) {

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);

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) {

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);

}

}

// Example usage

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

if (folderPath) {

try {

const uploadedFiles = await readUploadedFiles();

const randomFilePath = await getRandomValidFileFromFolder(folderPath, uploadedFiles);

if (randomFilePath) {

await signAndUploadMedia(randomFilePath, uploadedFiles, urlFilePath);

} else {

await publishRandomUrlEvent(urlFilePath);

}

} 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 handling.
Author Public Key
npub15522kwl0kaf04t44xcvj6py5rhp9hzz936y5qlu48xacnuua4auqpc9emz