feat: add params
This commit is contained in:
parent
39239f0d2f
commit
e41f176126
@ -1,9 +1,10 @@
|
||||
FROM node:20-alpine
|
||||
FROM node:21
|
||||
|
||||
RUN apt-get update -y && apt-get install -y ffmpeg
|
||||
|
||||
WORKDIR /app
|
||||
COPY . /app/
|
||||
|
||||
RUN yarn install
|
||||
RUN yarn build
|
||||
RUN npm install
|
||||
RUN npm run build
|
||||
|
||||
ENTRYPOINT [ "node", "build/index.js" ]
|
||||
|
8
development.mjs
Normal file
8
development.mjs
Normal file
@ -0,0 +1,8 @@
|
||||
import shell from "shelljs";
|
||||
import "dotenv/config.js";
|
||||
|
||||
shell.exec("./node_modules/.bin/tsc");
|
||||
shell.exec("./node_modules/.bin/tsc --watch", { silent: true, async: true });
|
||||
shell.exec("./node_modules/.bin/nodemon --watch build -d 1 build/index.js", {
|
||||
async: true,
|
||||
});
|
@ -12,6 +12,8 @@ const LNBITS_ADMIN_KEY = process.env.LNBITS_ADMIN_KEY;
|
||||
const NOSTR_RELAYS = process.env.NOSTR_RELAYS?.split(",") ?? [];
|
||||
if (NOSTR_RELAYS.length === 0) throw new Error("Missing NOSTR_RELAYS");
|
||||
|
||||
export { NOSTR_PRIVATE_KEY, LNBITS_URL, LNBITS_ADMIN_KEY, NOSTR_RELAYS };
|
||||
const BLOSSOM_UPLOAD_SERVER = process.env.BLOSSOM_UPLOAD_SERVER || "https://media-server.slidestr.net";
|
||||
|
||||
export { NOSTR_PRIVATE_KEY, LNBITS_URL, LNBITS_ADMIN_KEY, NOSTR_RELAYS, BLOSSOM_UPLOAD_SERVER };
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { getFileSizeSync } from "./filesystem.js";
|
||||
import { createReadStream } from "fs";
|
||||
import axios from "axios";
|
||||
import debug from "debug";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
const logger = debug("dvm:blossom");
|
||||
|
||||
@ -17,7 +18,6 @@ type BlobDescriptor = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
|
||||
const signer: Signer = async (event: EventTemplate) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
@ -29,21 +29,26 @@ const signer: Signer = async (event: EventTemplate) => {
|
||||
});
|
||||
};
|
||||
|
||||
export async function uploadFile(filePath: string, server: string): Promise<BlobDescriptor> {
|
||||
try {
|
||||
const oneHour = () => dayjs().unix() + 60 * 60;
|
||||
export async function createDvmBlossemAuthToken() {
|
||||
const tenMinutes = () => dayjs().unix() + 10 * 60;
|
||||
const authEvent = await signer({
|
||||
created_at: dayjs().unix(),
|
||||
kind: 24242,
|
||||
content: "Upload thumbail",
|
||||
tags: [
|
||||
["t", "upload"],
|
||||
// ["name", ], unknown
|
||||
["size", String(getFileSizeSync(filePath))],
|
||||
["expiration", String(oneHour)],
|
||||
["name", randomUUID() ], // make sure the auth events are unique
|
||||
["expiration", String(tenMinutes)],
|
||||
],
|
||||
});
|
||||
|
||||
return btoa(JSON.stringify(authEvent));
|
||||
}
|
||||
|
||||
export async function uploadFile(filePath: string, server: string, authToken?: string): Promise<BlobDescriptor> {
|
||||
try {
|
||||
const blossomAuthToken = authToken || await createDvmBlossemAuthToken();
|
||||
|
||||
// Create a read stream for the thumbnail file
|
||||
const thumbnailStream = createReadStream(filePath);
|
||||
|
||||
@ -51,7 +56,7 @@ export async function uploadFile(filePath: string, server: string): Promise<Blob
|
||||
const blob = await axios.put<BlobDescriptor>(`${server}/upload`, thumbnailStream, {
|
||||
headers: {
|
||||
"Content-Type": "image/jpeg", // Adjust content type as needed <--- TODO adjust for png
|
||||
authorization: "Nostr " + btoa(JSON.stringify(authEvent)),
|
||||
"Authorization": "Nostr " + blossomAuthToken,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -24,8 +24,8 @@ export function getInputParams(e: Event, k: string) {
|
||||
return e.tags.filter((t) => t[0] === "param" && t[1] === k).map((t) => t[2]);
|
||||
}
|
||||
|
||||
export function getInputParam(e: Event, k: string) {
|
||||
const value = getInputParams(e, k)[0];
|
||||
export function getInputParam(e: Event, k: string, defaultValue?: string) {
|
||||
const value = getInputParams(e, k)[0] || defaultValue;
|
||||
if (value === undefined) throw new Error(`Missing ${k} param`);
|
||||
return value;
|
||||
}
|
||||
|
50
src/index.ts
50
src/index.ts
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
import dayjs from "dayjs";
|
||||
import { NostrEvent, Subscription, Filter, finalizeEvent } from "nostr-tools";
|
||||
import { NOSTR_PRIVATE_KEY, NOSTR_RELAYS } from "./env.js";
|
||||
import { getInput, getInputTag, getOutputType, getRelays } from "./helpers/dvm.js";
|
||||
import { NostrEvent, Subscription, Filter, finalizeEvent, nip04 } from "nostr-tools";
|
||||
import { BLOSSOM_UPLOAD_SERVER, NOSTR_PRIVATE_KEY, NOSTR_RELAYS } from "./env.js";
|
||||
import { getInput, getInputParam, getInputParams, getInputTag, getOutputType, getRelays } from "./helpers/dvm.js";
|
||||
import { unique } from "./helpers/array.js";
|
||||
import { pool } from "./pool.js";
|
||||
import { logger } from "./debug.js";
|
||||
@ -14,19 +14,51 @@ import { rmSync } from "fs";
|
||||
type JobContext = {
|
||||
request: NostrEvent;
|
||||
url: string;
|
||||
thumbnailCount: number;
|
||||
imageFormat: "jpg" | "png";
|
||||
uploadServer: string;
|
||||
};
|
||||
|
||||
async function shouldAcceptJob(request: NostrEvent): Promise<JobContext> {
|
||||
//const decryptedContent = await nip04.decrypt(NOSTR_PRIVATE_KEY, request.pubkey, request.content);
|
||||
//encryptedTags = JSON.parse(decryptedContent);
|
||||
|
||||
const input = getInput(request);
|
||||
const output = getOutputType(request);
|
||||
// const lang = getInputParam(request, "language");
|
||||
|
||||
const authTokens = unique(getInputParams(request, "authToken"));
|
||||
const thumbnailCount = parseInt(getInputParam(request, "thumbnailCount", "3"), 10);
|
||||
const imageFormat = getInputParam(request, "imageFormat", "jpg");
|
||||
const uploadServer = getInputParam(request, "uploadServer", BLOSSOM_UPLOAD_SERVER);
|
||||
|
||||
// if (output !== "text/plain") throw new Error(`Unsupported output type ${output}`);
|
||||
|
||||
if (thumbnailCount < 1 || thumbnailCount > 10) {
|
||||
throw new Error(`Thumbnail count has to be between 1 and 10`);
|
||||
}
|
||||
|
||||
// uniq auth token either 0 or len>=thumbnailCount
|
||||
if (authTokens.length > 0 && authTokens.length <= thumbnailCount) {
|
||||
throw new Error(`Not enough auth tokens ${authTokens.length} for ${thumbnailCount} thumbnail uploads.`);
|
||||
}
|
||||
|
||||
// TODO check that auth tokens are not expired
|
||||
|
||||
// TODO add sanity checks for URL
|
||||
if (
|
||||
!uploadServer.match(
|
||||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/,
|
||||
)
|
||||
) {
|
||||
throw new Error(`Upload server is not a valid url.`);
|
||||
}
|
||||
|
||||
if (imageFormat != "jpg" && imageFormat != "png") {
|
||||
throw new Error(`Unsupported image format ${imageFormat}`);
|
||||
}
|
||||
|
||||
if (input.type === "url") {
|
||||
return { url: input.value, request };
|
||||
return { url: input.value, request, thumbnailCount, imageFormat, uploadServer };
|
||||
} else throw new Error(`Unknown input type ${input.type}`);
|
||||
}
|
||||
|
||||
@ -60,19 +92,19 @@ async function doWork(context: JobContext) {
|
||||
const startTime = dayjs().unix();
|
||||
|
||||
logger(`creating thumb for URL ${context.url}`);
|
||||
const server = "https://media-server.slidestr.net"; // TODO add env variable for this
|
||||
|
||||
const resultTags = await retreiveMetaData(context.url);
|
||||
|
||||
const thumbnailContent = await extractThumbnails(context.url, 3, 'jpg'); // TODO add DVM param for these
|
||||
const thumbnailContent = await extractThumbnails(context.url, context.thumbnailCount, context.imageFormat);
|
||||
|
||||
for (const tp of thumbnailContent.thumbnailPaths) {
|
||||
const blob = await uploadFile(tp, server);
|
||||
logger(`Uplaoaded thumbnail file: ${blob.url}`);
|
||||
const blob = await uploadFile(tp, context.uploadServer); // todo use user specfic auth Tokens
|
||||
logger(`Uploaaded thumbnail file: ${blob.url}`);
|
||||
resultTags.push(["thumb", blob.url]);
|
||||
resultTags.push(["x", blob.sha256]);
|
||||
}
|
||||
|
||||
//nip04.encrypt(NOSTR_PRIVATE_KEY, p, JSON.stringify())
|
||||
const result = finalizeEvent(
|
||||
{
|
||||
kind: DVM_VIDEO_THUMB_RESULT_KIND,
|
||||
|
Loading…
Reference in New Issue
Block a user