| const axios = require('axios'); | |
| const dns = require('dns').promises; | |
| const PROXY_URL = 'https://proxy-sigma-roan.vercel.app/api/proxy'; | |
| dns.setServers(['1.1.1.1', '8.8.8.8', '8.8.4.4']); | |
| function generateUniqueId() { | |
| return Array.from({ length: 32 }, () => | |
| Math.floor(Math.random() * 16).toString(16) | |
| ).join(''); | |
| } | |
| function generatePassword() { | |
| const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | |
| let password = ''; | |
| for (let i = 0; i < 12; i++) { | |
| password += chars.charAt(Math.floor(Math.random() * chars.length)); | |
| } | |
| return password; | |
| } | |
| function randomDelay(min = 1000, max = 3000) { | |
| const delay = Math.floor(Math.random() * (max - min + 1)) + min; | |
| return new Promise(resolve => setTimeout(resolve, delay)); | |
| } | |
| function generateRandomIP() { | |
| return `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`; | |
| } | |
| async function proxyRequest(url, options = {}) { | |
| const targetPath = url.startsWith('http') ? url : url; | |
| const fakeIP = generateRandomIP(); | |
| const headers = { | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', | |
| 'Accept': 'application/json, text/plain, */*', | |
| 'X-Forwarded-For': fakeIP, | |
| 'X-Real-IP': fakeIP, | |
| 'X-Client-IP': fakeIP, | |
| ...(options.headers || {}) | |
| }; | |
| await randomDelay(500, 1500); | |
| const axiosConfig = { | |
| method: options.method || 'GET', | |
| headers: headers, | |
| timeout: 30000, | |
| params: { url: targetPath }, | |
| validateStatus: (status) => status >= 200 && status < 600 | |
| }; | |
| if (options.data && (options.method === 'POST' || options.method === 'PUT')) { | |
| axiosConfig.data = options.data; | |
| } | |
| let lastError = null; | |
| for (let attempt = 1; attempt <= 3; attempt++) { | |
| try { | |
| axiosConfig.url = PROXY_URL; | |
| const response = await axios(axiosConfig); | |
| console.log(`[Proxy] Status: ${response.status}, URL: ${targetPath}`); | |
| if (response.status === 500) { | |
| console.error('[Proxy] 500 Error Details:', JSON.stringify(response.data)); | |
| throw new Error(`Proxy server error: ${JSON.stringify(response.data)}`); | |
| } | |
| if (response.status === 403) { | |
| await randomDelay(3000, 5000); | |
| throw new Error('API Bylo returned 403 Forbidden'); | |
| } | |
| if (response.status === 429) { | |
| await randomDelay(5000, 10000); | |
| if (attempt < 3) continue; | |
| throw new Error('Rate limit exceeded'); | |
| } | |
| if (response.status >= 200 && response.status < 300) { | |
| if (!response.data) throw new Error('Empty response from proxy'); | |
| return response; | |
| } | |
| if (response.status >= 400) { | |
| const errorMsg = response.data?.msg || response.data?.message || 'Unknown error'; | |
| throw new Error(`API error (${response.status}): ${errorMsg}`); | |
| } | |
| if (attempt < 3) await randomDelay(2000, 4000); | |
| } catch (error) { | |
| console.error('[Proxy] Request failed:', { | |
| url: targetPath, | |
| status: error.response?.status, | |
| data: error.response?.data, | |
| message: error.message | |
| }); | |
| lastError = error; | |
| if (attempt < 3) { | |
| const waitTime = 3000 * attempt; | |
| await randomDelay(waitTime, waitTime + 2000); | |
| } | |
| } | |
| } | |
| throw new Error(`Proxy request failed after 3 attempts: ${lastError?.message || 'Unknown error'}`); | |
| } | |
| async function createTempEmail() { | |
| const { data } = await axios.post('https://api.internal.temp-mail.io/api/v3/email/new', { | |
| min_name_length: 10, | |
| max_name_length: 10 | |
| }, { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Application-Name': 'web', | |
| 'Application-Version': '4.0.0', | |
| 'X-CORS-Header': 'iaWg3pchvFx48fY' | |
| }, | |
| timeout: 15000 | |
| }); | |
| return data; | |
| } | |
| async function getHcaptchaToken() { | |
| const { data } = await axios.get( | |
| 'https://anabot.my.id/api/tools/bypass?url=https%3A%2F%2Fapi.hcaptcha.com&siteKey=6f70c0f2-3ef6-4972-9fb6-c0b4bade3af8&type=hcaptcha-invisible&apikey=freeApikey', | |
| { timeout: 15000 } | |
| ); | |
| if (!data.success) throw new Error('Failed to get hCaptcha token'); | |
| return data.data.result.token; | |
| } | |
| async function sendVerificationEmail(email) { | |
| await randomDelay(1000, 2000); | |
| const hcaptchaToken = await getHcaptchaToken(); | |
| const encodedEmail = encodeURIComponent(email); | |
| await randomDelay(500, 1000); | |
| const { data } = await proxyRequest( | |
| `/api/auth/send-captcha?email=${encodedEmail}&type=register`, | |
| { | |
| method: 'GET', | |
| headers: { | |
| 'Accept': 'application/json, text/plain, */*', | |
| 'hcaptcha-token': hcaptchaToken, | |
| 'uniqueId': generateUniqueId() | |
| } | |
| } | |
| ); | |
| if (data.code !== 200) { | |
| throw new Error(`Failed to send verification email: ${data.msg || 'Unknown error'}`); | |
| } | |
| await randomDelay(3000, 5000); | |
| return true; | |
| } | |
| async function getVerificationCode(email) { | |
| let attempts = 0; | |
| const maxAttempts = 30; | |
| while (attempts < maxAttempts) { | |
| try { | |
| await new Promise(resolve => setTimeout(resolve, 5000)); | |
| const { data } = await axios.get( | |
| `https://api.internal.temp-mail.io/api/v3/email/${email}/messages`, | |
| { | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Application-Name': 'web', | |
| 'Application-Version': '4.0.0', | |
| 'X-CORS-Header': 'iaWg3pchvFx48fY' | |
| }, | |
| timeout: 10000 | |
| } | |
| ); | |
| if (data.length > 0) { | |
| const bodyText = data[0].body_text; | |
| const codeMatch = bodyText.match(/Verification Code:\s*(\d{6})/); | |
| if (codeMatch) return codeMatch[1]; | |
| } | |
| attempts++; | |
| } catch (error) { | |
| attempts++; | |
| } | |
| } | |
| throw new Error('Verification code not received after 30 attempts'); | |
| } | |
| async function registerAccount(email, password, verificationCode) { | |
| const { data } = await proxyRequest('/api/auth/register', { | |
| method: 'POST', | |
| headers: { | |
| 'Accept': 'application/json, text/plain, */*', | |
| 'Content-Type': 'application/json', | |
| 'uniqueId': generateUniqueId() | |
| }, | |
| data: { | |
| email: email, | |
| password: password, | |
| confirmPassword: password, | |
| verificationCode: verificationCode, | |
| referDomain: '' | |
| } | |
| }); | |
| if (data.code !== 200) { | |
| throw new Error(`Registration failed: ${data.msg || 'Unknown error'}`); | |
| } | |
| return data.data.token; | |
| } | |
| async function createVideoFromImage(prompt, imageUrl, ratio, duration, authToken, email) { | |
| await randomDelay(2000, 3000); | |
| const payloadVariants = [ | |
| { | |
| prompt: prompt, | |
| channel: 'SORA2', | |
| pageId: 536, | |
| source: 'bylo.ai', | |
| watermarkFlag: false, | |
| privateFlag: false, | |
| isTemp: true, | |
| model: 'sora_video2', | |
| videoType: 'image-to-video', | |
| duration: duration.toString(), | |
| aspectRatio: ratio, | |
| imageUrls: [imageUrl], | |
| email: email | |
| }, | |
| { | |
| prompt: prompt, | |
| channel: 'SORA2', | |
| pageId: 536, | |
| source: 'bylo.ai', | |
| watermarkFlag: false, | |
| privateFlag: false, | |
| isTemp: true, | |
| model: 'sora_video2', | |
| videoType: 'image-to-video', | |
| duration: duration.toString(), | |
| aspectRatio: ratio, | |
| imageUrl: imageUrl, | |
| email: email | |
| }, | |
| { | |
| prompt: prompt, | |
| channel: 'SORA2', | |
| pageId: 536, | |
| source: 'bylo.ai', | |
| watermarkFlag: false, | |
| privateFlag: false, | |
| isTemp: true, | |
| model: 'sora_video2', | |
| videoType: 'image-to-video', | |
| duration: duration.toString(), | |
| aspectRatio: ratio, | |
| image: imageUrl, | |
| email: email | |
| } | |
| ]; | |
| let lastError = null; | |
| for (let i = 0; i < payloadVariants.length; i++) { | |
| try { | |
| console.log(`[DEBUG] Trying payload variant ${i + 1}:`, JSON.stringify(payloadVariants[i], null, 2)); | |
| const { data } = await proxyRequest('/aimodels/api/v1/ai/video/create', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'uniqueid': generateUniqueId(), | |
| 'verify': '', | |
| 'authorization': authToken | |
| }, | |
| data: payloadVariants[i] | |
| }); | |
| console.log('[DEBUG] Response:', JSON.stringify(data, null, 2)); | |
| if (data.code === 200) { | |
| return data.data; | |
| } | |
| lastError = new Error(`Failed with code ${data.code}: ${data.message || data.msg || 'Unknown error'}`); | |
| } catch (error) { | |
| console.error(`[DEBUG] Payload variant ${i + 1} failed:`, error.message); | |
| lastError = error; | |
| } | |
| } | |
| throw lastError || new Error('All payload variants failed'); | |
| } | |
| async function getTaskStatus(taskId, authToken) { | |
| const { data } = await proxyRequest( | |
| `/aimodels/api/v1/ai/${taskId}?channel=SORA2`, | |
| { | |
| method: 'GET', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'authorization': authToken | |
| } | |
| } | |
| ); | |
| if (!data || !data.data) { | |
| throw new Error('Invalid response from task status API'); | |
| } | |
| return data.data; | |
| } | |
| async function waitForVideoCompletion(taskId, authToken) { | |
| let attempts = 0; | |
| const maxAttempts = 120; | |
| while (attempts < maxAttempts) { | |
| await randomDelay(5000, 7000); | |
| const taskData = await getTaskStatus(taskId, authToken); | |
| console.log(`[Progress] Attempt ${attempts + 1}/${maxAttempts} - State: ${taskData.state}`); | |
| if (taskData.state === 1 && taskData.completeData) { | |
| const completeData = JSON.parse(taskData.completeData); | |
| return completeData.data.result_urls[0]; | |
| } | |
| if (taskData.failMsg) { | |
| throw new Error(`Video generation failed: ${taskData.failMsg}`); | |
| } | |
| attempts++; | |
| } | |
| throw new Error('Video generation timeout after 10 minutes'); | |
| } | |
| async function sora2ImageToVideo(prompt, imageUrl, ratio = 'portrait', duration = 10) { | |
| console.log('[1/6] Creating temporary email...'); | |
| const tempMail = await createTempEmail(); | |
| const email = tempMail.email; | |
| const password = generatePassword(); | |
| console.log(`[Email] ${email}`); | |
| console.log('[2/6] Sending verification email...'); | |
| await sendVerificationEmail(email); | |
| console.log('[3/6] Waiting for verification code...'); | |
| const verificationCode = await getVerificationCode(email); | |
| console.log(`[Code] ${verificationCode}`); | |
| console.log('[4/6] Registering account...'); | |
| const authToken = await registerAccount(email, password, verificationCode); | |
| console.log('[Auth] Token received'); | |
| console.log('[5/6] Creating video task...'); | |
| const taskId = await createVideoFromImage(prompt, imageUrl, ratio, duration, authToken, email); | |
| console.log(`[Task ID] ${taskId}`); | |
| console.log('[6/6] Waiting for video completion...'); | |
| const videoUrl = await waitForVideoCompletion(taskId, authToken); | |
| console.log(`[Video URL] ${videoUrl}`); | |
| return { | |
| success: true, | |
| email: email, | |
| password: password, | |
| videoUrl: videoUrl, | |
| taskId: taskId | |
| }; | |
| } | |
| const handler = async (req, res) => { | |
| const startTime = Date.now(); | |
| try { | |
| const { prompt, imageUrl, key, ratio = 'portrait' } = req.query; | |
| if (!prompt) { | |
| return res.status(400).json({ | |
| author: 'Herza', | |
| success: false, | |
| msg: 'Missing required parameter: prompt', | |
| usage: '/api/AI/sora2img2video?prompt=your_prompt&imageUrl=image_url&ratio=portrait&key=your_key' | |
| }); | |
| } | |
| if (!imageUrl) { | |
| return res.status(400).json({ | |
| author: 'Herza', | |
| success: false, | |
| msg: 'Missing required parameter: imageUrl' | |
| }); | |
| } | |
| if (!key) { | |
| return res.status(400).json({ | |
| author: 'Herza', | |
| success: false, | |
| msg: 'Missing required parameter: key' | |
| }); | |
| } | |
| if (!['portrait', 'landscape'].includes(ratio)) { | |
| return res.status(400).json({ | |
| author: 'Herza', | |
| success: false, | |
| msg: 'Invalid ratio. Use: portrait or landscape' | |
| }); | |
| } | |
| console.log(`\n${'='.repeat(60)}`); | |
| console.log('NEW IMAGE TO VIDEO REQUEST RECEIVED'); | |
| console.log(`Prompt: ${prompt}`); | |
| console.log(`Image URL: ${imageUrl}`); | |
| console.log(`Ratio: ${ratio}`); | |
| console.log(`${'='.repeat(60)}\n`); | |
| const result = await sora2ImageToVideo(prompt, imageUrl, ratio, 10); | |
| const processingTime = ((Date.now() - startTime) / 1000).toFixed(2); | |
| console.log(`\n${'='.repeat(60)}`); | |
| console.log('REQUEST COMPLETED'); | |
| console.log(`Duration: ${processingTime}s`); | |
| console.log(`${'='.repeat(60)}\n`); | |
| res.json({ | |
| author: 'Herza', | |
| success: true, | |
| data: { | |
| model: 'sora-video2', | |
| prompt: prompt, | |
| imageUrl: imageUrl, | |
| ratio: ratio, | |
| duration: '10s', | |
| videoUrl: result.videoUrl, | |
| taskId: result.taskId, | |
| account: { | |
| email: result.email, | |
| password: result.password | |
| }, | |
| processingTime: `${processingTime}s` | |
| } | |
| }); | |
| } catch (error) { | |
| console.error('\n❌ ERROR:', error.message); | |
| console.error('Stack:', error.stack); | |
| const processingTime = ((Date.now() - startTime) / 1000).toFixed(2); | |
| const errorMessage = error.response?.data?.error || | |
| error.response?.data?.message || | |
| error.message || | |
| 'Unknown error occurred'; | |
| res.status(error.response?.status || 500).json({ | |
| author: 'Herza', | |
| success: false, | |
| msg: errorMessage, | |
| processingTime: `${processingTime}s`, | |
| error: { | |
| code: error.code || 'UNKNOWN', | |
| statusCode: error.response?.status, | |
| details: error.response?.data || error.message | |
| } | |
| }); | |
| } | |
| } | |
| module.exports = { | |
| name: 'Sora2 Image to Video Generator', | |
| description: 'Generate videos from images using Sora2 AI model from Bylo.ai via Vercel Proxy', | |
| type: 'GET', | |
| routes: ['api/AI/sora2img2video'], | |
| tags: ['AI', 'Sora', 'OpenAI', 'Video', 'Image to Video'], | |
| parameters: ['prompt', 'imageUrl', 'ratio', 'key'], | |
| enabled: true, | |
| main: ['AI'], | |
| limit: 13, | |
| handler | |
| }; |