R2 S3-API code
I feel like I must be doing something wrong if I have to do this
const key = parsedUrl.pathname.split('/').slice(2).join('/');
const key = parsedUrl.pathname.split('/').slice(2).join('/');
3 Replies
import { NextRequest, NextResponse } from 'next/server';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { randomUUID } from 'crypto';
if (!process.env.S3_ENDPOINT) {
throw new Error('S3_ENDPOINT is not defined');
}
if (!process.env.S3_ACCESS_KEY_ID) {
throw new Error('S3_ACCESS_KEY_ID is not defined');
}
if (!process.env.S3_SECRET_ACCESS_KEY) {
throw new Error('CLOUDFLARE_SECRET_ACCESS_KEY is not defined');
}
const S3 = new S3Client({
region: 'auto',
endpoint: process.env.S3_ENDPOINT,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
});
// JSON body: { "filename": "my-file.txt" }
export async function POST(request: NextRequest) {
const data = await request.json();
const filename = data.filename;
const url = await generateSignedUrl(filename);
return NextResponse.json({ url });
}
async function generateSignedUrl(filename: string) {
// Create randomized UUID for filename
const uuid = randomUUID();
// Attach file extension to UUID
const extension = filename.split('.').pop();
const key = `${uuid}.${extension}`;
const command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key,
});
const url = await getSignedUrl(S3, command, {
expiresIn: 60 * 60 * 24 * 7, // 7 days
});
return url;
}
import { NextRequest, NextResponse } from 'next/server';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { randomUUID } from 'crypto';
if (!process.env.S3_ENDPOINT) {
throw new Error('S3_ENDPOINT is not defined');
}
if (!process.env.S3_ACCESS_KEY_ID) {
throw new Error('S3_ACCESS_KEY_ID is not defined');
}
if (!process.env.S3_SECRET_ACCESS_KEY) {
throw new Error('CLOUDFLARE_SECRET_ACCESS_KEY is not defined');
}
const S3 = new S3Client({
region: 'auto',
endpoint: process.env.S3_ENDPOINT,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
});
// JSON body: { "filename": "my-file.txt" }
export async function POST(request: NextRequest) {
const data = await request.json();
const filename = data.filename;
const url = await generateSignedUrl(filename);
return NextResponse.json({ url });
}
async function generateSignedUrl(filename: string) {
// Create randomized UUID for filename
const uuid = randomUUID();
// Attach file extension to UUID
const extension = filename.split('.').pop();
const key = `${uuid}.${extension}`;
const command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key,
});
const url = await getSignedUrl(S3, command, {
expiresIn: 60 * 60 * 24 * 7, // 7 days
});
return url;
}
import { NextRequest, NextResponse } from 'next/server';
import { S3Client, HeadObjectCommand } from '@aws-sdk/client-s3';
import { PrismaClient } from '@prisma/client';
import { getSessionUser } from '@/lib/session';
if (!process.env.S3_ENDPOINT) {
throw new Error('S3_ENDPOINT is not defined');
}
if (!process.env.S3_ACCESS_KEY_ID) {
throw new Error('S3_ACCESS_KEY_ID is not defined');
}
if (!process.env.S3_SECRET_ACCESS_KEY) {
throw new Error('CLOUDFLARE_SECRET_ACCESS_KEY is not defined');
}
const S3 = new S3Client({
region: 'auto',
endpoint: process.env.S3_ENDPOINT,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
});
const prisma = new PrismaClient();
export async function POST(request: NextRequest) {
const sessionUser = await getSessionUser();
if (!sessionUser) {
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
}
const user = await prisma.user.findUnique({
where: {
email: sessionUser.email,
},
});
if (!user) {
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
}
// Validation
const { url } = await request.json();
if (!url) {
return NextResponse.json({ error: 'url is required' });
}
// Determine the type of URL
const parsedUrl = new URL(url);
const camcorderS3Hostname = process.env.S3_HOSTNAME;
const youtubeHostnames = ['www.youtube.com', 'youtu.be'];
if (parsedUrl.hostname === camcorderS3Hostname) {
// This is a Camcorder S3 URL
// No need to download the file, since it's already on S3
let name;
let mimeType;
let size;
const key = parsedUrl.pathname.split('/').slice(2).join('/');
try {
const headObjectCommand = new HeadObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key,
});
const headObjectResponse = await S3.send(headObjectCommand);
name = headObjectResponse.Metadata?.name;
mimeType = headObjectResponse.ContentType;
size = headObjectResponse.ContentLength;
} catch (error) {
console.error(error);
return NextResponse.json({ error: 'unknown url' });
}
const asset = await prisma.asset.create({
data: {
name: name || parsedUrl.pathname,
url: parsedUrl.hostname + parsedUrl.pathname,
mimeType: mimeType || 'video/mp4',
size: size || 0,
user: {
connect: {
id: user.id,
},
},
},
});
console.log(asset);
} else if (youtubeHostnames.includes(parsedUrl.hostname)) {
// This is a Youtube URL
// Need to trigger a Youtube download and then upload to S3
} else if (parsedUrl.pathname.endsWith('.mp4')) {
// This is an MP4 URL
// Need to download the file and then upload to S3
} else {
// This is an unknown URL
// Return an error
return NextResponse.json({ error: 'unknown url' });
}
// Save the associated video file's S3 URL to the database as a video record
// Process the video file through the transcription pipeline
// Save the transcription to the database as a transcription record
return NextResponse.json({ url });
}
import { NextRequest, NextResponse } from 'next/server';
import { S3Client, HeadObjectCommand } from '@aws-sdk/client-s3';
import { PrismaClient } from '@prisma/client';
import { getSessionUser } from '@/lib/session';
if (!process.env.S3_ENDPOINT) {
throw new Error('S3_ENDPOINT is not defined');
}
if (!process.env.S3_ACCESS_KEY_ID) {
throw new Error('S3_ACCESS_KEY_ID is not defined');
}
if (!process.env.S3_SECRET_ACCESS_KEY) {
throw new Error('CLOUDFLARE_SECRET_ACCESS_KEY is not defined');
}
const S3 = new S3Client({
region: 'auto',
endpoint: process.env.S3_ENDPOINT,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
});
const prisma = new PrismaClient();
export async function POST(request: NextRequest) {
const sessionUser = await getSessionUser();
if (!sessionUser) {
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
}
const user = await prisma.user.findUnique({
where: {
email: sessionUser.email,
},
});
if (!user) {
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
}
// Validation
const { url } = await request.json();
if (!url) {
return NextResponse.json({ error: 'url is required' });
}
// Determine the type of URL
const parsedUrl = new URL(url);
const camcorderS3Hostname = process.env.S3_HOSTNAME;
const youtubeHostnames = ['www.youtube.com', 'youtu.be'];
if (parsedUrl.hostname === camcorderS3Hostname) {
// This is a Camcorder S3 URL
// No need to download the file, since it's already on S3
let name;
let mimeType;
let size;
const key = parsedUrl.pathname.split('/').slice(2).join('/');
try {
const headObjectCommand = new HeadObjectCommand({
Bucket: process.env.S3_BUCKET_NAME,
Key: key,
});
const headObjectResponse = await S3.send(headObjectCommand);
name = headObjectResponse.Metadata?.name;
mimeType = headObjectResponse.ContentType;
size = headObjectResponse.ContentLength;
} catch (error) {
console.error(error);
return NextResponse.json({ error: 'unknown url' });
}
const asset = await prisma.asset.create({
data: {
name: name || parsedUrl.pathname,
url: parsedUrl.hostname + parsedUrl.pathname,
mimeType: mimeType || 'video/mp4',
size: size || 0,
user: {
connect: {
id: user.id,
},
},
},
});
console.log(asset);
} else if (youtubeHostnames.includes(parsedUrl.hostname)) {
// This is a Youtube URL
// Need to trigger a Youtube download and then upload to S3
} else if (parsedUrl.pathname.endsWith('.mp4')) {
// This is an MP4 URL
// Need to download the file and then upload to S3
} else {
// This is an unknown URL
// Return an error
return NextResponse.json({ error: 'unknown url' });
}
// Save the associated video file's S3 URL to the database as a video record
// Process the video file through the transcription pipeline
// Save the transcription to the database as a transcription record
return NextResponse.json({ url });
}
Sounds like the S3 client youre using is trying to use path style and is putting the bucket name on the path?
I'm using the AWS S3 sdk
I wonder if there's a way I can tell it not to do that