1
0
Fork 0

Basic image and video upload

This commit is contained in:
Sjors Provoost 2024-08-31 21:25:48 +02:00
parent d24980e1e6
commit 4e1c42f3a7
Signed by: sjors
GPG key ID: 57FF9BDBCC301009
4 changed files with 118 additions and 3 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.env

View file

@ -21,6 +21,8 @@ Run the script:
deno run --allow-read --allow-net main.ts
```
Optionally add `--env --allow-env` to use a `.env` file.
First it will prompt for the path of your archive.
E.g. `/Users/you/Downloads/instagram-you-2024-01-01-abcdef`

View file

@ -4,6 +4,9 @@
"specifiers": {
"jsr:@nostrify/nostrify@^0.30.1": "jsr:@nostrify/nostrify@0.30.1",
"jsr:@nostrify/types@^0.30.0": "jsr:@nostrify/types@0.30.0",
"jsr:@std/assert@^0.224.0": "jsr:@std/assert@0.224.0",
"jsr:@std/crypto@^0.224.0": "jsr:@std/crypto@0.224.0",
"jsr:@std/encoding@^0.224.0": "jsr:@std/encoding@0.224.3",
"jsr:@std/encoding@^0.224.1": "jsr:@std/encoding@0.224.3",
"npm:@noble/hashes@^1.4.0": "npm:@noble/hashes@1.4.0",
"npm:@scure/bip32@^1.4.0": "npm:@scure/bip32@1.4.0",
@ -19,6 +22,7 @@
"integrity": "fcc923707e87a9fbecc82dbb18756d1d3d134cd0763f4b1254c4bce709e811eb",
"dependencies": [
"jsr:@nostrify/types@^0.30.0",
"jsr:@std/crypto@^0.224.0",
"jsr:@std/encoding@^0.224.1",
"npm:@scure/bip32@^1.4.0",
"npm:@scure/bip39@^1.3.0",
@ -31,6 +35,16 @@
"@nostrify/types@0.30.0": {
"integrity": "1f38fa849cff930bd709edbf94ef9ac02f46afb8b851f86c8736517b354616da"
},
"@std/assert@0.224.0": {
"integrity": "8643233ec7aec38a940a8264a6e3eed9bfa44e7a71cc6b3c8874213ff401967f"
},
"@std/crypto@0.224.0": {
"integrity": "154ef3ff08ef535562ef1a718718c5b2c5fc3808f0f9100daad69e829bfcdf2d",
"dependencies": [
"jsr:@std/assert@^0.224.0",
"jsr:@std/encoding@^0.224.0"
]
},
"@std/encoding@0.224.3": {
"integrity": "5e861b6d81be5359fad4155e591acf17c0207b595112d1840998bb9f476dbdaf"
}

104
main.ts
View file

@ -6,17 +6,24 @@ import {
NRelay1
} from '@nostrify/nostrify';
import { BlossomUploader } from '@nostrify/nostrify/uploaders';
import * as nip19 from 'nostr-tools/nip19'
console.log("\nUse at your own risk!\n");
console.log("Considering trying it out with a throwaway nsec.");
console.log("All data will be public. Anything you upload is hard to delete.\n");
const path = prompt("Enter Instagram backup (absolute) path (unzip first): ");
const path = Deno.env.get("INSTAGRAM_BACKUP_PATH") || prompt("Enter Instagram backup (absolute) path (unzip first): ");
const posts = JSON.parse(await Deno.readTextFile(path + "/content/posts_1.json"));
console.log("Number of posts:", posts.length);
// TODO: sanity check all posts
for (const i in posts) {
const post = posts[i]
}
console.log("You can try one picture at a time, duplicates are skipped the next run.");
const n = Number(prompt("How many do you want to upload?", posts.length));
@ -26,7 +33,7 @@ if (n == 0) { Deno.exit(0); }
assert(n > 0);
assert(n <= posts.length);
const nsec_str = prompt("\nPlease enter your nsec:");
const nsec_str = Deno.env.get("NSEC") || prompt("\nPlease enter your nsec:");
// Sanity check format
NSchema.bech32('nsec').parse(nsec_str);
@ -42,7 +49,7 @@ console.log("\nYour npub: ", npub);
console.log("In hex format: ", pubkey_hex);
// TODO: get relays from profile and/or allow multiple
const relay_str = prompt("Pick a relay:");
const relay_str = Deno.env.get("RELAY") || prompt("Pick a relay:");
const relay = new NRelay1(relay_str);
console.log("\nAs a sanity check, here's your last message (if any):");
@ -53,3 +60,94 @@ for await (const msg of relay.req([{ kinds: [1], limit: 1, authors: [pubkey_hex]
}
await relay.close()
// TODO: suggest public (free or paid) Blossom servers, allow multiple
const blossom_url = Deno.env.get("BLOSSOM") || prompt("Enter Blossom server URL:", "https://blossom.primal.net/");
const uploader = new BlossomUploader({
servers: [String(blossom_url)],
signer: signer,
});
alert("About to upload all images. Not posting to Nostr yet.");
let completed = 0;
let events = [];
for (const i in posts) {
const post = posts[i]
console.log(post);
// Not all posts have a creation timestamp. If it's absent we'll use
// the first media timestamp.
let created_at = post.creation_timestamp;
// Message is the post title followed by each image on a new line.
// If an image has a title, that's added too.
let message = "";
// Some posts don't have a "title" field, others have an empty string.
if (post.title != undefined && post.title != "") {
message = post.title + "\n";
}
let first = true;
for (const j in post.media) {
const media = post.media[j];
if (first) {
first = false;
} else {
message += "\n";
}
if (created_at == undefined) {
created_at = media.creation_timestamp;
}
if (media.title != undefined && media.title != "") {
message += media.title + "\n";
}
const data = await Deno.readFile(path + "/" + media.uri);
let blob;
let extension;
// Check file extension
if (media.uri.slice(-5) == ".webp") {
blob = new Blob([data], {type: 'image/webp'});
extension = ".webp"
} else if (!media.uri.includes(".")) {
// Assume it's an mp4 movie
blob = new Blob([data], {type: 'video/mp4'});
extension = ".mp4"
} else {
// Unexpected, abort
console.error("Unexpected file type for: ", media.uri);
console.log(post);
Deno.exit(1);
}
const tags = await uploader.upload(blob);
if (extension == ".mp4") {
console.log(tags);
}
// add URL to message (plus extension)
message += tags[0][1] + extension
// TODO: get city?
}
// Generate Nostr event
const event = await signer.signEvent({ kind: 1, content: message, tags: [], created_at: created_at});
console.log(event);
events.push(event);
completed++;
if (completed == n) break;
}
alert("About to post to Nostr.");
for (const event in events) {
await relay.event(event);
}
console.log("Done!");