diff --git a/functions/upload.js b/functions/upload.js index ffb44b5..8ebb887 100644 --- a/functions/upload.js +++ b/functions/upload.js @@ -1,151 +1,83 @@ -// functions/upload.js -// Handles cover image uploads via imgur.gg API - -const API_BASE = 'https://temp.imgur.gg/api/upload'; +const BASE = "https://temp.imgur.gg"; export async function onRequest(context) { - const { request } = context; + const { request } = context; - // Handle CORS preflight - if (request.method === 'OPTIONS') { - return new Response(null, { - status: 204, - headers: { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'POST', - 'Access-Control-Allow-Headers': 'Content-Type', - }, - }); - } - - if (request.method !== 'POST') { - return new Response(JSON.stringify({ error: 'Method not allowed' }), { - status: 405, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - }); - } - - try { - // Parse the multipart form data - const formData = await request.formData(); - const file = formData.get('file'); - - if (!file) { - return new Response(JSON.stringify({ error: 'No file provided' }), { - status: 400, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - }); - } - - // Validate file type - if (!file.type.startsWith('image/')) { - return new Response(JSON.stringify({ error: 'File must be an image' }), { - status: 400, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - }); - } - - // Validate file size (max 10MB) - const maxSize = 10 * 1024 * 1024; // 10MB - if (file.size > maxSize) { - return new Response(JSON.stringify({ error: 'File size exceeds 10MB limit' }), { - status: 400, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - }); - } - - // Get file bytes - const fileBytes = await file.arrayBuffer(); - - // Step 1: Request upload metadata - const metadataPayload = { - files: [ - { - fileName: file.name, - fileType: file.type, - fileSize: file.size, - }, - ], - }; - - const metadataResponse = await fetch(API_BASE, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(metadataPayload), - }); - - if (!metadataResponse.ok) { - throw new Error(`Metadata request failed: ${metadataResponse.status}`); - } - - const metadata = await metadataResponse.json(); - - if (!metadata.success || !metadata.files || !metadata.files[0]) { - throw new Error('Failed to get upload URL from imgur.gg'); - } - - const fileInfo = metadata.files[0]; - const uploadUrl = fileInfo.uploadUrl; - - // Step 2: Upload the file - const uploadResponse = await fetch(uploadUrl, { - method: 'PUT', - body: fileBytes, - headers: { - 'Content-Type': file.type, - }, - }); - - if (!uploadResponse.ok) { - throw new Error(`File upload failed: ${uploadResponse.status}`); - } - - // Step 3: Return the public URL - const publicUrl = `https://i.imgur.gg/${fileInfo.fileId}-${fileInfo.fileName}`; - - return new Response( - JSON.stringify({ - success: true, - url: publicUrl, - fileId: fileInfo.fileId, - fileName: fileInfo.fileName, - }), - { - status: 200, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - } - ); - } catch (error) { - console.error('Upload error:', error); - return new Response( - JSON.stringify({ - error: 'Upload failed', - message: error.message, - }), - { - status: 500, - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - }, - } - ); + if (request.method !== "POST") { + return new Response("Method not allowed", { status: 405 }); + } + + const formData = await request.formData(); + const file = formData.get("file"); + + if (!file) { + return new Response("No file", { status: 400 }); + } + + const buffer = await file.arrayBuffer(); + // 1. GET site to grab cookie + const getRes = await fetch(BASE, { + method: "GET", + }); + + const setCookie = getRes.headers.get("set-cookie") || ""; + const cookie = setCookie.split(";")[0]; // _s=xxxxx + + // 2. Request metadata WITH cookie + + const metadataRes = await fetch(`${BASE}/api/upload`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Cookie: cookie, + Origin: BASE, + Referer: BASE + "/", + }, + body: JSON.stringify({ + files: [ + { + fileName: file.name, + fileType: file.type, + fileSize: file.size, + }, + ], + }), + }); + + if (!metadataRes.ok) { + const text = await metadataRes.text(); + return new Response("Metadata failed: " + text, { status: 500 }); + } + + const metadata = await metadataRes.json(); + const uploadInfo = metadata.files[0]; + + // 3. Upload to signed URL + + const uploadRes = await fetch(uploadInfo.uploadUrl, { + method: "PUT", + headers: { + "Content-Type": file.type, + }, + body: buffer, + }); + + if (!uploadRes.ok) { + return new Response("Upload failed", { status: 500 }); + } + + // 4. Return public URL + + const publicUrl = + `https://i.imgur.gg/${uploadInfo.fileId}-${uploadInfo.fileName}`; + + return new Response( + JSON.stringify({ + success: true, + url: publicUrl, + }), + { + headers: { "Content-Type": "application/json" }, } + ); }