UNPKG

cloudku-uploader

Version:

Blazing-fast, zero-dependency uploader for CloudKu. Supports auto-conversion, chunked uploads, and TypeScript. Easily upload images, videos, audio, and documents via Node.js.

163 lines (137 loc) 5.61 kB
const Base = [ 'https://cloudkuimages.guru', 'https://cloudkuimages-guru.us.itpanel.app' ]; const Headers = { 'x-content-type-options': 'nosniff', 'x-frame-options': 'DENY', 'x-xss-protection': '0', 'referrer-policy': 'strict-origin-when-cross-origin,origin', 'x-provided-by': 'StackCDN', 'Referer': 'https://cloudkuimages.guru', 'Origin': 'https://cloudkuimages.guru', 'User-Agent': 'cloudku-uploader/4.2.1', 'Accept': '*/*' }; const generateBoundary = () => '----formdata-' + Math.random().toString(36).substr(2, 9); export const parseExpireTime = (timeStr) => { if (!timeStr) return null; const match = timeStr.match(/^(\d+)([smhdMy])$/); if (!match) return timeStr; const [, amount, unit] = match; const now = new Date(); const value = parseInt(amount); const calculations = { 's': () => new Date(now.getTime() + value * 1000), 'm': () => new Date(now.getTime() + value * 60 * 1000), 'h': () => new Date(now.getTime() + value * 60 * 60 * 1000), 'd': () => new Date(now.getTime() + value * 24 * 60 * 60 * 1000), 'M': () => { const date = new Date(now); date.setMonth(date.getMonth() + value); return date; }, 'y': () => { const date = new Date(now); date.setFullYear(date.getFullYear() + value); return date; } }; return calculations[unit]?.()?.toISOString().split('T')[0] || timeStr; }; const buildMultipartData = (fileBuffer, fileName, expireDate) => { const boundary = generateBoundary(); const encoder = new TextEncoder(); let formData = `--${boundary}\r\n`; formData += `Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n`; formData += `Content-Type: application/octet-stream\r\n\r\n`; const headerBytes = encoder.encode(formData); const fileBytes = new Uint8Array(fileBuffer); let expireBytes = new Uint8Array(0); if (expireDate) { const expireForm = `\r\n--${boundary}\r\n` + `Content-Disposition: form-data; name="expire_date"\r\n\r\n${expireDate}`; expireBytes = encoder.encode(expireForm); } const footerBytes = encoder.encode(`\r\n--${boundary}--\r\n`); const totalSize = headerBytes.length + fileBytes.length + expireBytes.length + footerBytes.length; const multipartData = new Uint8Array(totalSize); let pos = 0; multipartData.set(headerBytes, pos); pos += headerBytes.length; multipartData.set(fileBytes, pos); pos += fileBytes.length; multipartData.set(expireBytes, pos); pos += expireBytes.length; multipartData.set(footerBytes, pos); return { data: multipartData, boundary }; }; export const uploadFile = async (fileBuffer, fileName = 'image.jpg', expireDate = null) => { const endpoint = expireDate ? '/temp.php' : '/upload.php'; const { data, boundary } = buildMultipartData(fileBuffer, fileName, expireDate); const headers = { ...Headers, 'Content-Type': `multipart/form-data; boundary=${boundary}` }; for (let i = 0; i < Base.length; i++) { try { const response = await fetch(Base[i] + endpoint, { method: 'POST', headers, body: data }); const result = await response.json(); result.information = 'https://cloudkuimages.guru/ch'; return result; } catch (error) { if (i === Base.length - 1) { return { status: 'error', message: `Upload gagal: ${error.message}`, information: 'https://cloudkuimages.guru/ch' }; } } } }; export const uploadSmart = async (fileBuffer, fileName = 'image.jpg', expireTime = null) => { const expireDate = parseExpireTime(expireTime); return uploadFile(fileBuffer, fileName, expireDate); }; export const uploadTemp = (fileBuffer, fileName, expireTime) => uploadSmart(fileBuffer, fileName, expireTime); export const uploadPermanent = (fileBuffer, fileName) => uploadFile(fileBuffer, fileName); export const uploadBatch = async (files) => { const results = await Promise.allSettled( files.map(({ buffer, name, expire }) => uploadSmart(buffer, name, expire) ) ); return results.map((result, index) => ({ index, status: result.status, data: result.status === 'fulfilled' ? result.value : null, error: result.status === 'rejected' ? result.reason : null })); }; export const upload30s = (buffer, name) => uploadTemp(buffer, name, '30s'); export const upload15m = (buffer, name) => uploadTemp(buffer, name, '15m'); export const upload6h = (buffer, name) => uploadTemp(buffer, name, '6h'); export const upload7d = (buffer, name) => uploadTemp(buffer, name, '7d'); export const upload3M = (buffer, name) => uploadTemp(buffer, name, '3M'); export const upload1y = (buffer, name) => uploadTemp(buffer, name, '1y'); export default { uploadFile, uploadSmart, uploadTemp, uploadPermanent, uploadBatch, parseExpireTime, upload30s, upload15m, upload6h, upload7d, upload3M, upload1y };