Skip to content

Commit

Permalink
add: express server
Browse files Browse the repository at this point in the history
  • Loading branch information
Prajjawalk committed Apr 5, 2024
1 parent 88d6113 commit c1891bd
Show file tree
Hide file tree
Showing 6 changed files with 447 additions and 140 deletions.
2 changes: 2 additions & 0 deletions packages/express/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env.*
tmp
78 changes: 78 additions & 0 deletions packages/express/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import express from 'express'
import pinataSDK from "@pinata/sdk";
import axios from "axios";
import { exec } from "child_process";
import fs from "fs";
import { Livepeer } from "livepeer";
import "dotenv/config"

const pinata = new pinataSDK({ pinataJWTKey: process.env.PINATA_JWT });
const app = express()
const port = 4000
app.use(express.json())

const livepeer = new Livepeer({
apiKey: process.env.LIVEPEER_API_KEY,
});

app.post('/', async (req, res) => {
console.log(req.body)
const body = req.body
const playbackId = body.playbackId;
const playbackInfo = await livepeer.playback.get(playbackId);
const videoUrl = playbackInfo.playbackInfo?.meta.source[0]?.url;

const mp4FilePath = `video-${playbackId}.mp4`;
const mp4FileStream = fs.createWriteStream(mp4FilePath);
const response = await axios.get(String(videoUrl), { responseType: "stream" });

response.data.pipe(mp4FileStream);

await new Promise((resolve, reject) => {
mp4FileStream.on("finish", resolve);
mp4FileStream.on("error", e => {
console.log(e);
reject(e);
});
});
console.log("mp4 file downloaded...");

// Convert MP4 to GIF using FFmpeg
const gifFilePath = `output-${playbackId}.gif`;
await new Promise((resolve, reject) => {
exec(
`ffmpeg -i ${mp4FilePath} -vf "fps=10,scale=320:-1:flags=lanczos" -c:v gif -loop 0 ${gifFilePath}`,
error => {
if (error) {
console.log(error);
reject(error);
return;
}
resolve();
},
);
});
console.log("gif generated...");

const readableStreamForFile = fs.createReadStream(gifFilePath);
const options = {
pinataMetadata: {
name: "gif",
},
};
const result = await pinata.pinFileToIPFS(readableStreamForFile, options);
console.log(result);
const { IpfsHash } = result;

const gifUrl = `https://ipfs.io/ipfs/${IpfsHash}`;
fs.unlinkSync(gifFilePath);
fs.unlinkSync(mp4FilePath);

res.send(JSON.stringify({
gifUrl: gifUrl
}))
})

app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
20 changes: 20 additions & 0 deletions packages/express/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "watch-clip-mint-express",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"type": "module",
"dependencies": {
"@pinata/sdk": "2.1.0",
"express": "4.19.2",
"livepeer": "^3.0.2"
},
"devDependencies": {
"dotenv": "^16.4.5"
},
"author": "",
"license": "ISC"
}
137 changes: 10 additions & 127 deletions packages/nextjs/app/slow-fetch/route.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,10 @@
import { NextRequest, NextResponse } from "next/server";
// import { DEFAULT_DEBUGGER_HUB_URL } from "../debug";
import { RandomNumberRequestStateValue } from "./types";
import pinataSDK from "@pinata/sdk";
import { kv } from "@vercel/kv";
import axios from "axios";
import { exec } from "child_process";
import { getFrameMessage } from "frames.js";
import fs from "fs";
import { Livepeer } from "livepeer";

// import { PinataFDK } from "pinata-fdk";

const MAXIMUM_KV_RESULT_LIFETIME_IN_SECONDS = 10 * 60; // 10 minutes
const pinata = new pinataSDK({ pinataJWTKey: process.env.PINATA_JWT });

// const fdk = new PinataFDK({
// pinata_jwt: String(process.env.PINATA_JWT),
// pinata_gateway: String(process.env.PINATA_GATEWAY),
// });

// async function pollUrlUntilResponse(url: string, expectedResponse: string, interval: number, maxAttempts: number) {
// let attempts = 0;
// // const axios = require("axios");
// while (attempts < maxAttempts) {
// try {
// const response = await axios.get(url, {
// headers: {
// Authorization: `Bearer ${process.env.LIVEPEER_API_KEY}`,
// },
// });
// if (response.data.status.phase == expectedResponse) {
// console.log("got the download url...");
// return response.data.downloadUrl;
// }
// } catch (error) {
// // Handle errors if necessary
// console.error("Error:", error);
// throw new Error("Error polling url");
// }
// await new Promise(resolve => setTimeout(resolve, interval));
// attempts++;
// }
// throw new Error(`Max attempts (${maxAttempts}) reached without receiving the expected response.`);
// }

export async function POST(req: NextRequest) {
const body = await req.json();
Expand All @@ -52,102 +14,23 @@ export async function POST(req: NextRequest) {
const uniqueId = `fid:${frameMessage.requesterFid}`;

try {
// const frame_id = `${frameMessage.requesterFid}`;
// const custom_id = "frameNFT";

console.log("sending analytics...");
console.log(body.postBody);
// const analyticsRes = await fdk.sendAnalytics(frame_id, body.postBody, custom_id);
// console.log(analyticsRes);

const playbackId = frameMessage.inputText;
if (!playbackId) {
return NextResponse.json({ message: "Playback ID is required" }, { status: 400 });
}

const livepeer = new Livepeer({
apiKey: process.env.LIVEPEER_API_KEY,
});

//clipping random livestream
// console.log("creating clip");
// const result = await livepeer.stream.createClip({
// /**
// * Playback ID of the stream or asset to clip
// */
// playbackId: playbackId,
// /**
// * Start time of the clip in milliseconds
// */
// startTime: Date.now() - 7000,
// /**
// * End time of the clip in milliseconds
// */
// endTime: Date.now() - 5000,
// });
// console.log(result.object?.asset);

// const url = `https://livepeer.studio/api/asset/${result.object?.asset.id}`;
// const expectedResponse = "ready";
// const pollingInterval = 5000; // 5 seconds (in milliseconds)
// const maxAttempts = 100;

// const downloadUrl = await pollUrlUntilResponse(url, expectedResponse, pollingInterval, maxAttempts);

// fetch the playback info on the server
const playbackInfo = await livepeer.playback.get(playbackId);
const videoUrl = playbackInfo.playbackInfo?.meta.source[0]?.url;
console.log(videoUrl);
// const videoUrl = downloadUrl;

// console.log("playback info ", playbackInfo.playbackInfo?.meta.source[0]);

// Download MP4 video file
const mp4FilePath = `/tmp/video-${playbackId}.mp4`;
const mp4FileStream = fs.createWriteStream(mp4FilePath);
const response = await axios.get(String(videoUrl), { responseType: "stream" });

response.data.pipe(mp4FileStream);

await new Promise((resolve, reject) => {
mp4FileStream.on("finish", resolve);
mp4FileStream.on("error", e => {
console.log(e);
reject(e);
});
});
console.log("mp4 file downloaded...");

// Convert MP4 to GIF using FFmpeg
const gifFilePath = `/tmp/output-${playbackId}.gif`;
fs.closeSync(fs.openSync(gifFilePath, "w"));
await new Promise<void>((resolve, reject) => {
exec(
`npx ffmpeg -i ${mp4FilePath} -vf "fps=10,scale=320:-1:flags=lanczos" -c:v gif -loop 0 ${gifFilePath} --loglevel=verbose`,
error => {
if (error) {
console.log(error);
reject(error);
return;
}
resolve();
},
);
});
console.log("gif generated...");

const readableStreamForFile = fs.createReadStream(gifFilePath);
const options = {
pinataMetadata: {
name: "gif",
const response = await fetch(String(process.env.NODE_LIVEPEER_SERVER), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
};
const res = await pinata.pinFileToIPFS(readableStreamForFile, options);
console.log(res);
const { IpfsHash } = res;

const gifUrl = `https://ipfs.io/ipfs/${IpfsHash}`;
fs.unlinkSync(gifFilePath);
fs.unlinkSync(mp4FilePath);
body: JSON.stringify({
playbackId: playbackId,
}),
});
const { gifUrl } = await response.json();
await kv.set<RandomNumberRequestStateValue>(
uniqueId,
{
Expand Down
1 change: 0 additions & 1 deletion packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"@farcaster/core": "^0.14.3",
"@ffmpeg-installer/darwin-arm64": "^4.1.5",
"@ffmpeg-installer/ffmpeg": "^1.1.0",
"@ffmpeg-installer/linux-x64": "^4.1.0",
"@heroicons/react": "~2.0.11",
"@livepeer/react": "^4.1.11",
"@noble/ed25519": "^2.0.0",
Expand Down
Loading

0 comments on commit c1891bd

Please sign in to comment.