Basic image and video upload
This commit is contained in:
parent
d24980e1e6
commit
4e1c42f3a7
4 changed files with 118 additions and 3 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.env
|
|
@ -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`
|
||||
|
|
14
deno.lock
14
deno.lock
|
@ -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
104
main.ts
|
@ -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!");
|
||||
|
|
Loading…
Reference in a new issue