Spaces:
Sleeping
Sleeping
Upload 56 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- plugins/aimodel.js +91 -0
- plugins/aio.js +39 -0
- plugins/apple.js +213 -0
- plugins/cloudflare-bypass.js +79 -0
- plugins/copilot-think.js +110 -0
- plugins/copilot.js +110 -0
- plugins/deepseek.js +52 -0
- plugins/douyin.js +70 -0
- plugins/faceswap.js +99 -0
- plugins/fbdl.js +110 -0
- plugins/flixer.js +158 -0
- plugins/flux.js +138 -0
- plugins/google.js +40 -0
- plugins/gpt-5.js +110 -0
- plugins/herxa +0 -0
- plugins/ig.js +39 -0
- plugins/igstalk.js +111 -0
- plugins/img2pixel.js +163 -0
- plugins/likee.js +88 -0
- plugins/lyrics.js +40 -0
- plugins/mcstalk.js +39 -0
- plugins/mediafire.js +48 -0
- plugins/nnbana.js +91 -0
- plugins/openai.js +39 -0
- plugins/perplexity.js +39 -0
- plugins/pinlens.js +210 -0
- plugins/pinterest.js +40 -0
- plugins/qr-generator.js +60 -0
- plugins/random-generator.js +201 -0
- plugins/removebg.js +85 -0
- plugins/sc.js +39 -0
- plugins/sora2-img2vid.js +499 -0
- plugins/sora2.js +472 -0
- plugins/sora2nowm.js +130 -0
- plugins/spotifydl.js +39 -0
- plugins/spotifysearch.js +39 -0
- plugins/subdo.js +192 -0
- plugins/suno.js +263 -0
- plugins/suno4.js +469 -0
- plugins/sunov2.js +207 -0
- plugins/sunov3.js +254 -0
- plugins/terabox.js +52 -0
- plugins/text2img.js +60 -0
- plugins/text2video.js +296 -0
- plugins/threads.js +93 -0
- plugins/tiktok.js +39 -0
- plugins/ttstalk.js +131 -0
- plugins/twitter.js +103 -0
- plugins/twitters.js +147 -0
- plugins/upscale.js +189 -0
plugins/aimodel.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const { v4: uuidv4 } = require('uuid');
|
| 3 |
+
|
| 4 |
+
const models = {
|
| 5 |
+
'gpt-4o-mini': '25865',
|
| 6 |
+
'gpt-5-nano': '25871',
|
| 7 |
+
'gemini': '25874',
|
| 8 |
+
'deepseek': '25873',
|
| 9 |
+
'claude': '25875',
|
| 10 |
+
'grok': '25872',
|
| 11 |
+
'meta-ai': '25870',
|
| 12 |
+
'qwen': '25869'
|
| 13 |
+
};
|
| 14 |
+
|
| 15 |
+
async function aichat(question, model) {
|
| 16 |
+
let { data: html } = await axios.get(`https://px.nekolabs.my.id/${encodeURIComponent('https://chatgptfree.ai/')}`);
|
| 17 |
+
|
| 18 |
+
let nonce = html.data.content.match(/"nonce"\s*:\s*"([^&]+)"/);
|
| 19 |
+
if (!nonce) throw new Error('Nonce not found.');
|
| 20 |
+
|
| 21 |
+
let { data } = await axios.post(`https://px.nekolabs.my.id/${encodeURIComponent('https://chatgptfree.ai/wp-admin/admin-ajax.php')}`, new URLSearchParams({
|
| 22 |
+
action: 'aipkit_frontend_chat_message',
|
| 23 |
+
_ajax_nonce: nonce[1],
|
| 24 |
+
bot_id: models[model],
|
| 25 |
+
session_id: uuidv4(),
|
| 26 |
+
conversation_uuid: uuidv4(),
|
| 27 |
+
post_id: '6',
|
| 28 |
+
message: question
|
| 29 |
+
}).toString(), {
|
| 30 |
+
headers: {
|
| 31 |
+
'Content-Type': 'application/x-www-form-urlencoded',
|
| 32 |
+
'Origin': 'https://chatgptfree.ai',
|
| 33 |
+
'Referer': 'https://chatgptfree.ai/',
|
| 34 |
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36'
|
| 35 |
+
}
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
return data.data.content.data.reply;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
const handler = async (req, res) => {
|
| 42 |
+
try {
|
| 43 |
+
const { text, model } = req.query;
|
| 44 |
+
|
| 45 |
+
if (!text) {
|
| 46 |
+
return res.status(400).json({
|
| 47 |
+
author: 'Herza',
|
| 48 |
+
success: false,
|
| 49 |
+
msg: 'Missing required parameter: text'
|
| 50 |
+
});
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
if (!model || !models[model]) {
|
| 54 |
+
return res.status(400).json({
|
| 55 |
+
author: 'Herza',
|
| 56 |
+
success: false,
|
| 57 |
+
msg: 'Invalid or missing model parameter',
|
| 58 |
+
available_models: Object.keys(models)
|
| 59 |
+
});
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
const result = await aichat(text, model);
|
| 63 |
+
|
| 64 |
+
res.json({
|
| 65 |
+
author: 'Herza',
|
| 66 |
+
success: true,
|
| 67 |
+
model: model,
|
| 68 |
+
msg: result.trim()
|
| 69 |
+
});
|
| 70 |
+
|
| 71 |
+
} catch (error) {
|
| 72 |
+
console.error('Error fetching from AI:', error);
|
| 73 |
+
res.status(500).json({
|
| 74 |
+
author: 'Herza',
|
| 75 |
+
success: false,
|
| 76 |
+
msg: error.message || 'Terjadi kesalahan saat menghubungi AI.'
|
| 77 |
+
});
|
| 78 |
+
}
|
| 79 |
+
};
|
| 80 |
+
|
| 81 |
+
module.exports = {
|
| 82 |
+
name: 'Model AI Chat',
|
| 83 |
+
description: 'Generate responses using multiple AI models, availabe models is Claude, gpt-4o-mini, gpt-5-nano, gemini, deepseek, grok, meta-ai, qwen',
|
| 84 |
+
type: 'GET',
|
| 85 |
+
routes: ['api/AI/chat'],
|
| 86 |
+
tags: ['ai', 'gpt', 'gemini', 'claude', 'deepseek'],
|
| 87 |
+
parameters: ['text', 'model', 'key'],
|
| 88 |
+
enabled: true,
|
| 89 |
+
main: ['AI'],
|
| 90 |
+
handler
|
| 91 |
+
};
|
plugins/aio.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { aio } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { url } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!url) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: url'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await aio(url);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
msg: result.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'All In One DL',
|
| 31 |
+
description: 'Download All Video Without WM',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/download/aio'],
|
| 34 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 35 |
+
parameters: ['url', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['Downloader'],
|
| 38 |
+
handler
|
| 39 |
+
}
|
plugins/apple.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
const cookieString = "_ga=GA1.1.206983766.1756790346; PHPSESSID=jomn6brkleb5969a3opposidru; quality=m4a; dcount=2; _ga_382FSD5=GS2.1.s1756858170$o3$g1$t1756858172$j58$l0$h0";
|
| 4 |
+
|
| 5 |
+
const axiosInstance = axios.create({
|
| 6 |
+
headers: {
|
| 7 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
| 8 |
+
'Cookie': cookieString
|
| 9 |
+
}
|
| 10 |
+
});
|
| 11 |
+
|
| 12 |
+
function encodeDownloadUrl(url) {
|
| 13 |
+
if (!url) return url;
|
| 14 |
+
return url.replace(/ /g, '%20');
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
function detectUrlType(url) {
|
| 18 |
+
if (url.includes('/song/')) {
|
| 19 |
+
return 'song';
|
| 20 |
+
} else if (url.includes('/album/') && url.includes('?i=')) {
|
| 21 |
+
return 'song';
|
| 22 |
+
} else if (url.includes('/album/') && !url.includes('?i=')) {
|
| 23 |
+
return 'album';
|
| 24 |
+
} else {
|
| 25 |
+
return 'song';
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
async function apple(url) {
|
| 30 |
+
try {
|
| 31 |
+
const urlType = detectUrlType(url);
|
| 32 |
+
|
| 33 |
+
if (urlType === 'album') {
|
| 34 |
+
return await downloadAlbum(url);
|
| 35 |
+
} else {
|
| 36 |
+
return await downloadSong(url);
|
| 37 |
+
}
|
| 38 |
+
} catch (error) {
|
| 39 |
+
return {
|
| 40 |
+
author: "Herza",
|
| 41 |
+
status: 500,
|
| 42 |
+
source: "error",
|
| 43 |
+
data: {
|
| 44 |
+
error: error.message,
|
| 45 |
+
message: 'Download gagal dari aaplmusicdownloader'
|
| 46 |
+
}
|
| 47 |
+
};
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
async function downloadSong(url) {
|
| 52 |
+
await axiosInstance.get('https://aaplmusicdownloader.com/ifCaptcha.php');
|
| 53 |
+
|
| 54 |
+
const endpoint = url.includes('/song/')
|
| 55 |
+
? 'https://aaplmusicdownloader.com/api/song_url.php'
|
| 56 |
+
: 'https://aaplmusicdownloader.com/api/applesearch.php';
|
| 57 |
+
|
| 58 |
+
const searchResponse = await axiosInstance.get(`${endpoint}?url=${encodeURIComponent(url)}`, {
|
| 59 |
+
headers: {
|
| 60 |
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
| 61 |
+
'X-Requested-With': 'XMLHttpRequest',
|
| 62 |
+
'Referer': 'https://aaplmusicdownloader.com/'
|
| 63 |
+
}
|
| 64 |
+
});
|
| 65 |
+
|
| 66 |
+
const searchData = searchResponse.data;
|
| 67 |
+
|
| 68 |
+
await axiosInstance.get('https://aaplmusicdownloader.com/song.php', {
|
| 69 |
+
headers: {
|
| 70 |
+
'Referer': 'https://aaplmusicdownloader.com/'
|
| 71 |
+
}
|
| 72 |
+
});
|
| 73 |
+
|
| 74 |
+
await axiosInstance.get('https://aaplmusicdownloader.com/ifCaptcha.php', {
|
| 75 |
+
headers: {
|
| 76 |
+
'Referer': 'https://aaplmusicdownloader.com/song.php'
|
| 77 |
+
}
|
| 78 |
+
});
|
| 79 |
+
|
| 80 |
+
const formData = `song_name=${encodeURIComponent(searchData.name)}&artist_name=${encodeURIComponent(searchData.artist)}&url=${encodeURIComponent(url)}&token=none&zip_download=false&quality=m4a`;
|
| 81 |
+
|
| 82 |
+
const downloadResponse = await axiosInstance.post('https://aaplmusicdownloader.com/api/composer/swd.php', formData, {
|
| 83 |
+
headers: {
|
| 84 |
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
| 85 |
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
| 86 |
+
'X-Requested-With': 'XMLHttpRequest',
|
| 87 |
+
'Referer': 'https://aaplmusicdownloader.com/song.php'
|
| 88 |
+
}
|
| 89 |
+
});
|
| 90 |
+
|
| 91 |
+
const downloadData = downloadResponse.data;
|
| 92 |
+
const downloadLink = downloadData.dlink || downloadData.wmcode;
|
| 93 |
+
|
| 94 |
+
return {
|
| 95 |
+
author: "Herza",
|
| 96 |
+
status: 200,
|
| 97 |
+
source: "aaplmusicdownloader",
|
| 98 |
+
type: "song",
|
| 99 |
+
data: {
|
| 100 |
+
name: searchData.name,
|
| 101 |
+
albumname: searchData.albumname,
|
| 102 |
+
artist: searchData.artist,
|
| 103 |
+
thumb: searchData.thumb,
|
| 104 |
+
duration: searchData.duration,
|
| 105 |
+
downloadLink: encodeDownloadUrl(downloadLink),
|
| 106 |
+
status: downloadData.status
|
| 107 |
+
}
|
| 108 |
+
};
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
async function downloadAlbum(url) {
|
| 112 |
+
await axiosInstance.get('https://aaplmusicdownloader.com/ifCaptcha.php');
|
| 113 |
+
|
| 114 |
+
const playlistResponse = await axiosInstance.get(`https://aaplmusicdownloader.com/api/pl.php?url=${encodeURIComponent(url)}`, {
|
| 115 |
+
headers: {
|
| 116 |
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
| 117 |
+
'X-Requested-With': 'XMLHttpRequest',
|
| 118 |
+
'Referer': 'https://aaplmusicdownloader.com/'
|
| 119 |
+
}
|
| 120 |
+
});
|
| 121 |
+
|
| 122 |
+
const albumData = playlistResponse.data.album_details;
|
| 123 |
+
const firstSong = albumData[0];
|
| 124 |
+
|
| 125 |
+
await axiosInstance.get('https://aaplmusicdownloader.com/album.php', {
|
| 126 |
+
headers: {
|
| 127 |
+
'Referer': 'https://aaplmusicdownloader.com/'
|
| 128 |
+
}
|
| 129 |
+
});
|
| 130 |
+
|
| 131 |
+
await axiosInstance.get('https://aaplmusicdownloader.com/ifCaptcha.php', {
|
| 132 |
+
headers: {
|
| 133 |
+
'Referer': 'https://aaplmusicdownloader.com/album.php'
|
| 134 |
+
}
|
| 135 |
+
});
|
| 136 |
+
|
| 137 |
+
const formData = `song_name=${encodeURIComponent(firstSong.name)}&artist_name=${encodeURIComponent(firstSong.artist.replace(/&/g, '&'))}&url=${encodeURIComponent(firstSong.link)}&token=na&zip_download=false&quality=m4a`;
|
| 138 |
+
|
| 139 |
+
const downloadResponse = await axiosInstance.post('https://aaplmusicdownloader.com/api/composer/swd.php', formData, {
|
| 140 |
+
headers: {
|
| 141 |
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
| 142 |
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
| 143 |
+
'X-Requested-With': 'XMLHttpRequest',
|
| 144 |
+
'Referer': 'https://aaplmusicdownloader.com/album.php'
|
| 145 |
+
}
|
| 146 |
+
});
|
| 147 |
+
|
| 148 |
+
const downloadData = downloadResponse.data;
|
| 149 |
+
const downloadLink = downloadData.dlink || downloadData.wmcode;
|
| 150 |
+
|
| 151 |
+
return {
|
| 152 |
+
author: "Herza",
|
| 153 |
+
status: 200,
|
| 154 |
+
source: "aaplmusicdownloader",
|
| 155 |
+
type: "album",
|
| 156 |
+
data: {
|
| 157 |
+
name: firstSong.name,
|
| 158 |
+
albumname: firstSong.album,
|
| 159 |
+
artist: firstSong.artist.replace(/&/g, '&'),
|
| 160 |
+
thumb: firstSong.thumb,
|
| 161 |
+
duration: firstSong.duration,
|
| 162 |
+
downloadLink: encodeDownloadUrl(downloadLink),
|
| 163 |
+
status: downloadData.status
|
| 164 |
+
}
|
| 165 |
+
};
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
const handler = async (req, res) => {
|
| 169 |
+
try {
|
| 170 |
+
const { url } = req.query;
|
| 171 |
+
|
| 172 |
+
if (!url) {
|
| 173 |
+
return res.status(400).json({
|
| 174 |
+
success: false,
|
| 175 |
+
error: 'Missing required parameter: url'
|
| 176 |
+
});
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
const result = await apple(url);
|
| 180 |
+
|
| 181 |
+
if (result.status === 500) {
|
| 182 |
+
return res.status(500).json({
|
| 183 |
+
success: false,
|
| 184 |
+
error: result.data.error,
|
| 185 |
+
message: result.data.message
|
| 186 |
+
});
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
res.json({
|
| 190 |
+
author: "Herza",
|
| 191 |
+
success: true,
|
| 192 |
+
msg: result.data
|
| 193 |
+
});
|
| 194 |
+
|
| 195 |
+
} catch (error) {
|
| 196 |
+
res.status(500).json({
|
| 197 |
+
success: false,
|
| 198 |
+
error: error.message
|
| 199 |
+
});
|
| 200 |
+
}
|
| 201 |
+
};
|
| 202 |
+
|
| 203 |
+
module.exports = {
|
| 204 |
+
name: 'Apple Music DL',
|
| 205 |
+
description: 'Download Apple Music Song or Album',
|
| 206 |
+
type: 'GET',
|
| 207 |
+
routes: ['api/download/applemusic'],
|
| 208 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 209 |
+
parameters: ['url', 'key'],
|
| 210 |
+
enabled: true,
|
| 211 |
+
main: ['Downloader'],
|
| 212 |
+
handler
|
| 213 |
+
}
|
plugins/cloudflare-bypass.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { site_url, site_key, key } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!site_url || !site_key || !key) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
author: 'Herza',
|
| 10 |
+
success: false,
|
| 11 |
+
error: 'Missing required parameters: site_url, site_key, or key'
|
| 12 |
+
});
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
const solverUrl = `https://herzaj-turnstile-solver.hf.space/turnstile?url=${encodeURIComponent(site_url)}&sitekey=${encodeURIComponent(site_key)}`;
|
| 16 |
+
|
| 17 |
+
const firstResponse = await axios.get(solverUrl, {
|
| 18 |
+
timeout: 30000
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
const taskId = firstResponse.data?.task_id;
|
| 22 |
+
if (!taskId) {
|
| 23 |
+
return res.status(400).json({
|
| 24 |
+
author: 'Herza',
|
| 25 |
+
success: false,
|
| 26 |
+
error: 'Failed to obtain task_id from solver service'
|
| 27 |
+
});
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
await new Promise(resolve => setTimeout(resolve, 8000));
|
| 31 |
+
|
| 32 |
+
const resultUrl = `https://herzaj-turnstile-solver.hf.space/result?id=${encodeURIComponent(taskId)}`;
|
| 33 |
+
|
| 34 |
+
const secondResponse = await axios.get(resultUrl, {
|
| 35 |
+
timeout: 30000
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
const { elapsed_time, value } = secondResponse.data;
|
| 39 |
+
|
| 40 |
+
if (!value) {
|
| 41 |
+
return res.status(400).json({
|
| 42 |
+
author: 'Herza',
|
| 43 |
+
success: false,
|
| 44 |
+
error: 'Failed to retrieve token value from solver service'
|
| 45 |
+
});
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
return res.json({
|
| 49 |
+
author: 'Herza',
|
| 50 |
+
success: true,
|
| 51 |
+
data: {
|
| 52 |
+
elapsed_time,
|
| 53 |
+
value,
|
| 54 |
+
site_url,
|
| 55 |
+
site_key
|
| 56 |
+
}
|
| 57 |
+
});
|
| 58 |
+
|
| 59 |
+
} catch (error) {
|
| 60 |
+
return res.status(500).json({
|
| 61 |
+
author: 'Herza',
|
| 62 |
+
success: false,
|
| 63 |
+
error: error.message
|
| 64 |
+
});
|
| 65 |
+
}
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
module.exports = {
|
| 69 |
+
name: 'Cloudflare Turnstile Bypass',
|
| 70 |
+
description: 'Generate Cloudflare Turnstile tokens with custom site URL and site key',
|
| 71 |
+
type: 'GET',
|
| 72 |
+
routes: ['api/tools/bypasscf'],
|
| 73 |
+
tags: ['utility', 'turnstile', 'solver'],
|
| 74 |
+
parameters: ['site_url', 'site_key', 'key'],
|
| 75 |
+
enabled: true,
|
| 76 |
+
main: ['tools'],
|
| 77 |
+
limit: 8,
|
| 78 |
+
handler
|
| 79 |
+
};
|
plugins/copilot-think.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const WebSocket = require('ws')
|
| 2 |
+
const axios = require('axios')
|
| 3 |
+
|
| 4 |
+
class CopilotThink {
|
| 5 |
+
constructor() {
|
| 6 |
+
this.conversationId = null
|
| 7 |
+
this.headers = {
|
| 8 |
+
origin: 'https://copilot.microsoft.com',
|
| 9 |
+
'user-agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36'
|
| 10 |
+
}
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
async createConversation() {
|
| 14 |
+
let { data } = await axios.post('https://copilot.microsoft.com/c/api/conversations', null, { headers: this.headers })
|
| 15 |
+
this.conversationId = data.id
|
| 16 |
+
return this.conversationId
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
async chat(message) {
|
| 20 |
+
if (!this.conversationId) await this.createConversation()
|
| 21 |
+
return new Promise((resolve, reject) => {
|
| 22 |
+
const ws = new WebSocket(`wss://copilot.microsoft.com/c/api/chat?api-version=2&features=-,ncedge,edgepagecontext&setflight=-,ncedge,edgepagecontext&ncedge=1`, { headers: this.headers })
|
| 23 |
+
const response = { text: '', citations: [] }
|
| 24 |
+
ws.on('open', () => {
|
| 25 |
+
ws.send(JSON.stringify({
|
| 26 |
+
event: 'setOptions',
|
| 27 |
+
supportedFeatures: ['partial-generated-images'],
|
| 28 |
+
supportedCards: ['weather', 'local', 'image', 'sports', 'video', 'ads', 'safetyHelpline', 'quiz', 'finance', 'recipe'],
|
| 29 |
+
ads: { supportedTypes: ['text', 'product', 'multimedia', 'tourActivity', 'propertyPromotion'] }
|
| 30 |
+
}))
|
| 31 |
+
ws.send(JSON.stringify({
|
| 32 |
+
event: 'send',
|
| 33 |
+
mode: 'reasoning',
|
| 34 |
+
conversationId: this.conversationId,
|
| 35 |
+
content: [{ type: 'text', text: message }],
|
| 36 |
+
context: {}
|
| 37 |
+
}))
|
| 38 |
+
})
|
| 39 |
+
ws.on('message', (chunk) => {
|
| 40 |
+
try {
|
| 41 |
+
const parsed = JSON.parse(chunk.toString())
|
| 42 |
+
switch (parsed.event) {
|
| 43 |
+
case 'appendText':
|
| 44 |
+
response.text += parsed.text || ''
|
| 45 |
+
break
|
| 46 |
+
case 'citation':
|
| 47 |
+
response.citations.push({ title: parsed.title, icon: parsed.iconUrl, url: parsed.url })
|
| 48 |
+
break
|
| 49 |
+
case 'done':
|
| 50 |
+
resolve(response)
|
| 51 |
+
ws.close()
|
| 52 |
+
break
|
| 53 |
+
case 'error':
|
| 54 |
+
reject(new Error(parsed.message))
|
| 55 |
+
ws.close()
|
| 56 |
+
break
|
| 57 |
+
}
|
| 58 |
+
} catch (error) {
|
| 59 |
+
reject(error.message)
|
| 60 |
+
}
|
| 61 |
+
})
|
| 62 |
+
ws.on('error', reject)
|
| 63 |
+
})
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
const handler = async (req, res) => {
|
| 68 |
+
try {
|
| 69 |
+
const { text } = req.query
|
| 70 |
+
|
| 71 |
+
if (!text) {
|
| 72 |
+
return res.status(400).json({
|
| 73 |
+
author: 'Herza',
|
| 74 |
+
success: false,
|
| 75 |
+
msg: 'Missing required parameter: text'
|
| 76 |
+
})
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
const copilot = new CopilotThink()
|
| 80 |
+
const result = await copilot.chat(text)
|
| 81 |
+
|
| 82 |
+
res.json({
|
| 83 |
+
author: 'Herza',
|
| 84 |
+
success: true,
|
| 85 |
+
model: 'copilot-think',
|
| 86 |
+
msg: result.text.trim(),
|
| 87 |
+
citations: result.citations
|
| 88 |
+
})
|
| 89 |
+
|
| 90 |
+
} catch (error) {
|
| 91 |
+
console.error('Error fetching from Copilot Think:', error)
|
| 92 |
+
res.status(500).json({
|
| 93 |
+
author: 'Herza',
|
| 94 |
+
success: false,
|
| 95 |
+
msg: 'Terjadi kesalahan saat menghubungi AI.'
|
| 96 |
+
})
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
module.exports = {
|
| 101 |
+
name: 'Copilot Think AI',
|
| 102 |
+
description: 'Generate responses using Microsoft Copilot with Reasoning/Think Deeper',
|
| 103 |
+
type: 'GET',
|
| 104 |
+
routes: ['api/AI/copilot-think'],
|
| 105 |
+
tags: ['ai', 'copilot', 'reasoning', 'think-deeper'],
|
| 106 |
+
parameters: ['text'],
|
| 107 |
+
enabled: true,
|
| 108 |
+
main: ['AI'],
|
| 109 |
+
handler
|
| 110 |
+
}
|
plugins/copilot.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const WebSocket = require('ws')
|
| 2 |
+
const axios = require('axios')
|
| 3 |
+
|
| 4 |
+
class Copilot {
|
| 5 |
+
constructor() {
|
| 6 |
+
this.conversationId = null
|
| 7 |
+
this.headers = {
|
| 8 |
+
origin: 'https://copilot.microsoft.com',
|
| 9 |
+
'user-agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36'
|
| 10 |
+
}
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
async createConversation() {
|
| 14 |
+
let { data } = await axios.post('https://copilot.microsoft.com/c/api/conversations', null, { headers: this.headers })
|
| 15 |
+
this.conversationId = data.id
|
| 16 |
+
return this.conversationId
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
async chat(message) {
|
| 20 |
+
if (!this.conversationId) await this.createConversation()
|
| 21 |
+
return new Promise((resolve, reject) => {
|
| 22 |
+
const ws = new WebSocket(`wss://copilot.microsoft.com/c/api/chat?api-version=2&features=-,ncedge,edgepagecontext&setflight=-,ncedge,edgepagecontext&ncedge=1`, { headers: this.headers })
|
| 23 |
+
const response = { text: '', citations: [] }
|
| 24 |
+
ws.on('open', () => {
|
| 25 |
+
ws.send(JSON.stringify({
|
| 26 |
+
event: 'setOptions',
|
| 27 |
+
supportedFeatures: ['partial-generated-images'],
|
| 28 |
+
supportedCards: ['weather', 'local', 'image', 'sports', 'video', 'ads', 'safetyHelpline', 'quiz', 'finance', 'recipe'],
|
| 29 |
+
ads: { supportedTypes: ['text', 'product', 'multimedia', 'tourActivity', 'propertyPromotion'] }
|
| 30 |
+
}))
|
| 31 |
+
ws.send(JSON.stringify({
|
| 32 |
+
event: 'send',
|
| 33 |
+
mode: 'chat',
|
| 34 |
+
conversationId: this.conversationId,
|
| 35 |
+
content: [{ type: 'text', text: message }],
|
| 36 |
+
context: {}
|
| 37 |
+
}))
|
| 38 |
+
})
|
| 39 |
+
ws.on('message', (chunk) => {
|
| 40 |
+
try {
|
| 41 |
+
const parsed = JSON.parse(chunk.toString())
|
| 42 |
+
switch (parsed.event) {
|
| 43 |
+
case 'appendText':
|
| 44 |
+
response.text += parsed.text || ''
|
| 45 |
+
break
|
| 46 |
+
case 'citation':
|
| 47 |
+
response.citations.push({ title: parsed.title, icon: parsed.iconUrl, url: parsed.url })
|
| 48 |
+
break
|
| 49 |
+
case 'done':
|
| 50 |
+
resolve(response)
|
| 51 |
+
ws.close()
|
| 52 |
+
break
|
| 53 |
+
case 'error':
|
| 54 |
+
reject(new Error(parsed.message))
|
| 55 |
+
ws.close()
|
| 56 |
+
break
|
| 57 |
+
}
|
| 58 |
+
} catch (error) {
|
| 59 |
+
reject(error.message)
|
| 60 |
+
}
|
| 61 |
+
})
|
| 62 |
+
ws.on('error', reject)
|
| 63 |
+
})
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
const handler = async (req, res) => {
|
| 68 |
+
try {
|
| 69 |
+
const { text } = req.query
|
| 70 |
+
|
| 71 |
+
if (!text) {
|
| 72 |
+
return res.status(400).json({
|
| 73 |
+
author: 'Herza',
|
| 74 |
+
success: false,
|
| 75 |
+
msg: 'Missing required parameter: text'
|
| 76 |
+
})
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
const copilot = new Copilot()
|
| 80 |
+
const result = await copilot.chat(text)
|
| 81 |
+
|
| 82 |
+
res.json({
|
| 83 |
+
author: 'Herza',
|
| 84 |
+
success: true,
|
| 85 |
+
model: 'copilot',
|
| 86 |
+
msg: result.text.trim(),
|
| 87 |
+
citations: result.citations
|
| 88 |
+
})
|
| 89 |
+
|
| 90 |
+
} catch (error) {
|
| 91 |
+
console.error('Error fetching from Copilot:', error)
|
| 92 |
+
res.status(500).json({
|
| 93 |
+
author: 'Herza',
|
| 94 |
+
success: false,
|
| 95 |
+
msg: 'Terjadi kesalahan saat menghubungi AI.'
|
| 96 |
+
})
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
module.exports = {
|
| 101 |
+
name: 'Copilot AI',
|
| 102 |
+
description: 'Generate responses using Microsoft Copilot',
|
| 103 |
+
type: 'GET',
|
| 104 |
+
routes: ['api/AI/copilot'],
|
| 105 |
+
tags: ['ai', 'copilot'],
|
| 106 |
+
parameters: ['text'],
|
| 107 |
+
enabled: true,
|
| 108 |
+
main: ['AI'],
|
| 109 |
+
handler
|
| 110 |
+
}
|
plugins/deepseek.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const Groq = require('groq-sdk');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
author: 'Herza',
|
| 10 |
+
success: false,
|
| 11 |
+
msg: 'Missing required parameter: text'
|
| 12 |
+
});
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
const client = new Groq({
|
| 16 |
+
apiKey: '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',
|
| 17 |
+
});
|
| 18 |
+
|
| 19 |
+
const chatCompletion = await client.chat.completions.create({
|
| 20 |
+
messages: [{ role: 'user', content: text }],
|
| 21 |
+
model: 'deepseek-r1-distill-llama-70b',
|
| 22 |
+
});
|
| 23 |
+
|
| 24 |
+
const result = chatCompletion.choices[0]?.message?.content || 'Maaf, saya tidak bisa menjawab itu.';
|
| 25 |
+
|
| 26 |
+
res.json({
|
| 27 |
+
author: 'Herza',
|
| 28 |
+
success: true,
|
| 29 |
+
msg: result
|
| 30 |
+
});
|
| 31 |
+
|
| 32 |
+
} catch (error) {
|
| 33 |
+
console.error('Error fetching from Deepseek:', error);
|
| 34 |
+
res.status(500).json({
|
| 35 |
+
author: 'Herza',
|
| 36 |
+
success: false,
|
| 37 |
+
msg: 'Terjadi kesalahan saat menghubungi AI.'
|
| 38 |
+
});
|
| 39 |
+
}
|
| 40 |
+
};
|
| 41 |
+
|
| 42 |
+
module.exports = {
|
| 43 |
+
name: 'DeepSeek AI',
|
| 44 |
+
description: 'Generate responses using DeepSeek AI via Groq',
|
| 45 |
+
type: 'GET',
|
| 46 |
+
routes: ['api/AI/deepseek'],
|
| 47 |
+
tags: ['ai', 'deepseek', 'groq'],
|
| 48 |
+
parameters: ['text', 'key'],
|
| 49 |
+
enabled: true,
|
| 50 |
+
main: ['AI'],
|
| 51 |
+
handler
|
| 52 |
+
};
|
plugins/douyin.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function douyin(url) {
|
| 4 |
+
if (!url) {
|
| 5 |
+
return {
|
| 6 |
+
author: "Herza",
|
| 7 |
+
success: false,
|
| 8 |
+
error: "URL is required"
|
| 9 |
+
};
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
try {
|
| 13 |
+
const response = await axios.post("https://snapdouyin.app/wp-json/mx-downloader/video-data/",
|
| 14 |
+
{ url },
|
| 15 |
+
{
|
| 16 |
+
headers: {
|
| 17 |
+
"Content-Type": "application/json",
|
| 18 |
+
"Origin": "https://snapdouyin.app",
|
| 19 |
+
"Referer": "https://snapdouyin.app/"
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
);
|
| 23 |
+
|
| 24 |
+
return {
|
| 25 |
+
author: "Herza",
|
| 26 |
+
success: true,
|
| 27 |
+
data: response.data
|
| 28 |
+
};
|
| 29 |
+
} catch (error) {
|
| 30 |
+
return {
|
| 31 |
+
author: "Herza",
|
| 32 |
+
success: false,
|
| 33 |
+
error: error.message
|
| 34 |
+
};
|
| 35 |
+
}
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
const handler = async (req, res) => {
|
| 39 |
+
try {
|
| 40 |
+
const { url } = req.query;
|
| 41 |
+
|
| 42 |
+
if (!url) {
|
| 43 |
+
return res.status(400).json({
|
| 44 |
+
success: false,
|
| 45 |
+
error: 'Missing required parameter: url'
|
| 46 |
+
});
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
const result = await douyin(url);
|
| 50 |
+
res.json(result);
|
| 51 |
+
|
| 52 |
+
} catch (error) {
|
| 53 |
+
res.status(500).json({
|
| 54 |
+
success: false,
|
| 55 |
+
error: error.message
|
| 56 |
+
});
|
| 57 |
+
}
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
module.exports = {
|
| 61 |
+
name: 'Douyin DL',
|
| 62 |
+
description: 'Download Douyin Video',
|
| 63 |
+
type: 'GET',
|
| 64 |
+
routes: ['api/download/douyin'],
|
| 65 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 66 |
+
parameters: ['url', 'key'],
|
| 67 |
+
enabled: true,
|
| 68 |
+
main: ['Downloader'],
|
| 69 |
+
handler
|
| 70 |
+
};
|
plugins/faceswap.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const upload = require('../lib/uploadImage');
|
| 3 |
+
|
| 4 |
+
async function faceSwap(img_url1, img_url2) {
|
| 5 |
+
try {
|
| 6 |
+
const response1 = await axios.get(img_url1, { responseType: 'arraybuffer' });
|
| 7 |
+
const base64_1 = Buffer.from(response1.data).toString('base64');
|
| 8 |
+
|
| 9 |
+
const response2 = await axios.get(img_url2, { responseType: 'arraybuffer' });
|
| 10 |
+
const base64_2 = Buffer.from(response2.data).toString('base64');
|
| 11 |
+
|
| 12 |
+
const swapResponse = await axios.post('https://api.faceswapper.ai/swap', {
|
| 13 |
+
target: base64_1,
|
| 14 |
+
source: base64_2,
|
| 15 |
+
type: 'invisible',
|
| 16 |
+
id: 'faceswapper'
|
| 17 |
+
}, {
|
| 18 |
+
headers: {
|
| 19 |
+
'Accept': 'application/json, text/plain, */*',
|
| 20 |
+
'Content-Type': 'application/json',
|
| 21 |
+
'type': 'rapid'
|
| 22 |
+
}
|
| 23 |
+
});
|
| 24 |
+
|
| 25 |
+
const base64Data = swapResponse.data.result.replace(/^data:image\/\w+;base64,/, '');
|
| 26 |
+
const buffer = Buffer.from(base64Data, 'base64');
|
| 27 |
+
|
| 28 |
+
const imageUrl = await upload(buffer);
|
| 29 |
+
|
| 30 |
+
return {
|
| 31 |
+
success: true,
|
| 32 |
+
elapsedTime: swapResponse.data.elapsedTime,
|
| 33 |
+
result: swapResponse.data.result,
|
| 34 |
+
url: imageUrl
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
} catch (error) {
|
| 38 |
+
throw error;
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
const handler = async (req, res) => {
|
| 43 |
+
try {
|
| 44 |
+
const { img, img2, key } = req.query;
|
| 45 |
+
|
| 46 |
+
if (!img) {
|
| 47 |
+
return res.status(400).json({
|
| 48 |
+
success: false,
|
| 49 |
+
error: 'Missing required parameter: img'
|
| 50 |
+
});
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
if (!img2) {
|
| 54 |
+
return res.status(400).json({
|
| 55 |
+
success: false,
|
| 56 |
+
error: 'Missing required parameter: img2'
|
| 57 |
+
});
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
if (!key) {
|
| 61 |
+
return res.status(400).json({
|
| 62 |
+
success: false,
|
| 63 |
+
error: 'Missing required parameter: key'
|
| 64 |
+
});
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
const result = await faceSwap(img, img2);
|
| 68 |
+
|
| 69 |
+
return res.json({
|
| 70 |
+
author: "Herza",
|
| 71 |
+
success: true,
|
| 72 |
+
data: {
|
| 73 |
+
elapsedTime: result.elapsedTime,
|
| 74 |
+
result: result.result,
|
| 75 |
+
url: result.url
|
| 76 |
+
}
|
| 77 |
+
});
|
| 78 |
+
|
| 79 |
+
} catch (error) {
|
| 80 |
+
res.status(500).json({
|
| 81 |
+
success: false,
|
| 82 |
+
error: error.message,
|
| 83 |
+
timestamp: new Date().toISOString()
|
| 84 |
+
});
|
| 85 |
+
}
|
| 86 |
+
};
|
| 87 |
+
|
| 88 |
+
module.exports = {
|
| 89 |
+
name: 'Face Swap',
|
| 90 |
+
description: 'Swap faces between two images using AI',
|
| 91 |
+
type: 'GET',
|
| 92 |
+
routes: ['api/AI/faceswap'],
|
| 93 |
+
tags: ['AI', 'tools'],
|
| 94 |
+
parameters: ['img', 'img2', 'key'],
|
| 95 |
+
limit: 3,
|
| 96 |
+
enabled: true,
|
| 97 |
+
main: ['AI', 'tools'],
|
| 98 |
+
handler
|
| 99 |
+
};
|
plugins/fbdl.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function fbdl(url) {
|
| 4 |
+
if (!url) {
|
| 5 |
+
return {
|
| 6 |
+
author: "Herza",
|
| 7 |
+
success: false,
|
| 8 |
+
error: "URL is required"
|
| 9 |
+
};
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
try {
|
| 13 |
+
const verifyResponse = await axios.post('https://fdownloader.net/api/userverify',
|
| 14 |
+
`url=${encodeURIComponent(url)}`,
|
| 15 |
+
{
|
| 16 |
+
headers: {
|
| 17 |
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
| 18 |
+
'Accept': '*/*',
|
| 19 |
+
'X-Requested-With': 'XMLHttpRequest'
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
);
|
| 23 |
+
|
| 24 |
+
if (!verifyResponse.data.success) {
|
| 25 |
+
return {
|
| 26 |
+
author: "Herza",
|
| 27 |
+
success: false,
|
| 28 |
+
error: 'User verification failed'
|
| 29 |
+
};
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
const token = verifyResponse.data.token;
|
| 33 |
+
const currentTime = Math.floor(Date.now() / 1000);
|
| 34 |
+
const k_exp = currentTime + 300;
|
| 35 |
+
|
| 36 |
+
const searchResponse = await axios.post('https://v3.fdownloader.net/api/ajaxSearch',
|
| 37 |
+
`k_exp=${k_exp}&k_token=${token.split('.')[2]}&q=${encodeURIComponent(url)}&lang=en&web=fdownloader.net&v=v2&w=&cftoken=${token}`,
|
| 38 |
+
{
|
| 39 |
+
headers: {
|
| 40 |
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
| 41 |
+
'Accept': '*/*'
|
| 42 |
+
}
|
| 43 |
+
}
|
| 44 |
+
);
|
| 45 |
+
|
| 46 |
+
const htmlData = searchResponse.data.data;
|
| 47 |
+
const titleMatch = htmlData.match(/<h3>(.+?)<\/h3>/);
|
| 48 |
+
const durationMatch = htmlData.match(/<p>(\d+:\d+)<\/p>/);
|
| 49 |
+
const thumbnailMatch = htmlData.match(/src="(https:\/\/scontent[^"]+)"/);
|
| 50 |
+
|
| 51 |
+
const hdMatch = htmlData.match(/href="(https:\/\/dl\.snapcdn\.app\/download\?token=[^"]+)"[^>]*title="Download 720p \(HD\)"/);
|
| 52 |
+
const sdMatch = htmlData.match(/href="(https:\/\/dl\.snapcdn\.app\/download\?token=[^"]+)"[^>]*title="Download 360p \(SD\)"/);
|
| 53 |
+
|
| 54 |
+
return {
|
| 55 |
+
author: 'Herza',
|
| 56 |
+
success: true,
|
| 57 |
+
data: {
|
| 58 |
+
title: titleMatch ? titleMatch[1] : 'Facebook Video',
|
| 59 |
+
duration: durationMatch ? durationMatch[1] : '0:00',
|
| 60 |
+
thumbnail: thumbnailMatch ? thumbnailMatch[1].replace(/&/g, '&') : null,
|
| 61 |
+
downloads: {
|
| 62 |
+
hd: hdMatch ? hdMatch[1] : null,
|
| 63 |
+
sd: sdMatch ? sdMatch[1] : null
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
};
|
| 67 |
+
} catch (error) {
|
| 68 |
+
return {
|
| 69 |
+
author: 'Herza',
|
| 70 |
+
success: false,
|
| 71 |
+
error: error.message
|
| 72 |
+
};
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
const handler = async (req, res) => {
|
| 77 |
+
try {
|
| 78 |
+
const { url } = req.query;
|
| 79 |
+
|
| 80 |
+
if (!url) {
|
| 81 |
+
return res.status(400).json({
|
| 82 |
+
author: "Herza",
|
| 83 |
+
success: false,
|
| 84 |
+
error: 'Missing required parameter: url'
|
| 85 |
+
});
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
const result = await fbdl(url);
|
| 89 |
+
res.json(result);
|
| 90 |
+
|
| 91 |
+
} catch (error) {
|
| 92 |
+
res.status(500).json({
|
| 93 |
+
author: "Herza",
|
| 94 |
+
success: false,
|
| 95 |
+
error: error.message
|
| 96 |
+
});
|
| 97 |
+
}
|
| 98 |
+
};
|
| 99 |
+
|
| 100 |
+
module.exports = {
|
| 101 |
+
name: 'Facebook DL',
|
| 102 |
+
description: 'Download Facebook Video',
|
| 103 |
+
type: 'GET',
|
| 104 |
+
routes: ['api/download/fbdl'],
|
| 105 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 106 |
+
parameters: ['url', 'key'],
|
| 107 |
+
enabled: true,
|
| 108 |
+
main: ['Downloader'],
|
| 109 |
+
handler
|
| 110 |
+
};
|
plugins/flixer.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const puppeteer = require('puppeteer');
|
| 2 |
+
|
| 3 |
+
const scrapeFlixer = async (searchQuery) => {
|
| 4 |
+
const browser = await puppeteer.launch({
|
| 5 |
+
headless: true,
|
| 6 |
+
args: [
|
| 7 |
+
'--no-sandbox',
|
| 8 |
+
'--disable-setuid-sandbox',
|
| 9 |
+
'--disable-dev-shm-usage',
|
| 10 |
+
'--disable-gpu'
|
| 11 |
+
]
|
| 12 |
+
});
|
| 13 |
+
|
| 14 |
+
const page = await browser.newPage();
|
| 15 |
+
|
| 16 |
+
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
|
| 17 |
+
|
| 18 |
+
const searchUrl = `https://flixer.sh/search?q=${encodeURIComponent(searchQuery)}`;
|
| 19 |
+
await page.goto(searchUrl, { waitUntil: 'networkidle0', timeout: 30000 });
|
| 20 |
+
|
| 21 |
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
| 22 |
+
|
| 23 |
+
const searchResults = await page.evaluate(() => {
|
| 24 |
+
const results = [];
|
| 25 |
+
const images = document.querySelectorAll('img[alt]');
|
| 26 |
+
|
| 27 |
+
images.forEach(img => {
|
| 28 |
+
const link = img.closest('a');
|
| 29 |
+
if (link && img.alt) {
|
| 30 |
+
results.push({
|
| 31 |
+
title: img.alt,
|
| 32 |
+
image: img.src,
|
| 33 |
+
url: link.href
|
| 34 |
+
});
|
| 35 |
+
}
|
| 36 |
+
});
|
| 37 |
+
|
| 38 |
+
return results;
|
| 39 |
+
});
|
| 40 |
+
|
| 41 |
+
if (searchResults.length === 0) {
|
| 42 |
+
await browser.close();
|
| 43 |
+
throw new Error('No results found');
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
const movieUrl = searchResults[0].url;
|
| 47 |
+
await page.goto(movieUrl, { waitUntil: 'networkidle0', timeout: 30000 });
|
| 48 |
+
|
| 49 |
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
| 50 |
+
|
| 51 |
+
const servers = await page.evaluate(() => {
|
| 52 |
+
const serverList = [];
|
| 53 |
+
const buttons = document.querySelectorAll('button');
|
| 54 |
+
|
| 55 |
+
buttons.forEach(btn => {
|
| 56 |
+
const nameEl = btn.querySelector('.font-medium');
|
| 57 |
+
const statusEl = btn.querySelector('.text-green-400');
|
| 58 |
+
|
| 59 |
+
if (nameEl && statusEl && statusEl.textContent.includes('AVAILABLE')) {
|
| 60 |
+
serverList.push({
|
| 61 |
+
name: nameEl.textContent.trim(),
|
| 62 |
+
available: true
|
| 63 |
+
});
|
| 64 |
+
}
|
| 65 |
+
});
|
| 66 |
+
|
| 67 |
+
return serverList;
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
let videoUrl = null;
|
| 71 |
+
|
| 72 |
+
page.on('response', async response => {
|
| 73 |
+
const url = response.url();
|
| 74 |
+
if (url.includes('.m3u8') || url.includes('.mp4') || url.includes('stream')) {
|
| 75 |
+
videoUrl = url;
|
| 76 |
+
}
|
| 77 |
+
});
|
| 78 |
+
|
| 79 |
+
for (const server of servers) {
|
| 80 |
+
try {
|
| 81 |
+
await page.evaluate((serverName) => {
|
| 82 |
+
const buttons = Array.from(document.querySelectorAll('button'));
|
| 83 |
+
const btn = buttons.find(b => {
|
| 84 |
+
const nameEl = b.querySelector('.font-medium');
|
| 85 |
+
return nameEl && nameEl.textContent.trim() === serverName;
|
| 86 |
+
});
|
| 87 |
+
if (btn) btn.click();
|
| 88 |
+
}, server.name);
|
| 89 |
+
|
| 90 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 91 |
+
|
| 92 |
+
const currentVideoUrl = await page.evaluate(() => {
|
| 93 |
+
const video = document.querySelector('video');
|
| 94 |
+
return video ? video.src : null;
|
| 95 |
+
});
|
| 96 |
+
|
| 97 |
+
if (currentVideoUrl && !currentVideoUrl.startsWith('blob:')) {
|
| 98 |
+
videoUrl = currentVideoUrl;
|
| 99 |
+
break;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
if (videoUrl && !videoUrl.startsWith('blob:')) {
|
| 103 |
+
break;
|
| 104 |
+
}
|
| 105 |
+
} catch (e) {
|
| 106 |
+
continue;
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
await browser.close();
|
| 111 |
+
|
| 112 |
+
return {
|
| 113 |
+
title: searchResults[0].title,
|
| 114 |
+
image: searchResults[0].image,
|
| 115 |
+
movieUrl: movieUrl,
|
| 116 |
+
servers: servers,
|
| 117 |
+
videoUrl: videoUrl,
|
| 118 |
+
allResults: searchResults
|
| 119 |
+
};
|
| 120 |
+
};
|
| 121 |
+
|
| 122 |
+
const handler = async (req, res) => {
|
| 123 |
+
try {
|
| 124 |
+
const { q } = req.query;
|
| 125 |
+
|
| 126 |
+
if (!q) {
|
| 127 |
+
return res.status(400).json({
|
| 128 |
+
success: false,
|
| 129 |
+
error: 'Missing required parameter: q'
|
| 130 |
+
});
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
const result = await scrapeFlixer(q);
|
| 134 |
+
res.json({
|
| 135 |
+
author: "Herza",
|
| 136 |
+
success: true,
|
| 137 |
+
msg: result
|
| 138 |
+
});
|
| 139 |
+
|
| 140 |
+
} catch (error) {
|
| 141 |
+
res.status(500).json({
|
| 142 |
+
success: false,
|
| 143 |
+
error: error.message
|
| 144 |
+
});
|
| 145 |
+
}
|
| 146 |
+
};
|
| 147 |
+
|
| 148 |
+
module.exports = {
|
| 149 |
+
name: 'Flixer Search',
|
| 150 |
+
description: 'Search and get video from Flixer',
|
| 151 |
+
type: 'GET',
|
| 152 |
+
routes: ['api/search/flixer'],
|
| 153 |
+
tags: ['search', 'movie', 'tools'],
|
| 154 |
+
parameters: ['q', 'key'],
|
| 155 |
+
enabled: true,
|
| 156 |
+
main: ['Downloader', 'Search'],
|
| 157 |
+
handler
|
| 158 |
+
};
|
plugins/flux.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const fs = require('fs');
|
| 3 |
+
const path = require('path');
|
| 4 |
+
|
| 5 |
+
async function fluxImage(prompt, width = 1024, height = 1024, server = "Azure Lite Supercomputer Server") {
|
| 6 |
+
try {
|
| 7 |
+
const { data: init } = await axios.post(
|
| 8 |
+
"https://nihalgazi-flux-unlimited.hf.space/gradio_api/call/generate_image",
|
| 9 |
+
{ data: [prompt, width, height, 3, true, server] },
|
| 10 |
+
{
|
| 11 |
+
headers: {
|
| 12 |
+
"Content-Type": "application/json",
|
| 13 |
+
Origin: "https://chrunos.com",
|
| 14 |
+
Referer: "https://chrunos.com/",
|
| 15 |
+
},
|
| 16 |
+
}
|
| 17 |
+
);
|
| 18 |
+
|
| 19 |
+
const eventId = init.event_id;
|
| 20 |
+
if (!eventId) throw new Error("Failed to obtain event_id.");
|
| 21 |
+
|
| 22 |
+
const streamUrl = `https://nihalgazi-flux-unlimited.hf.space/gradio_api/call/generate_image/${eventId}`;
|
| 23 |
+
let imageUrl = null;
|
| 24 |
+
|
| 25 |
+
for (let i = 0; i < 15; i++) {
|
| 26 |
+
const { data } = await axios.get(streamUrl, {
|
| 27 |
+
headers: { Accept: "text/event-stream" },
|
| 28 |
+
});
|
| 29 |
+
|
| 30 |
+
const match = data.match(/"url":\s*"([^"]+)"/);
|
| 31 |
+
if (match) {
|
| 32 |
+
imageUrl = match[1];
|
| 33 |
+
break;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
await new Promise(r => setTimeout(r, 2000));
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
if (!imageUrl) throw new Error("Failed to retrieve image URL from stream.");
|
| 40 |
+
return imageUrl;
|
| 41 |
+
} catch (err) {
|
| 42 |
+
throw new Error(`fluxImage error: ${err.message}`);
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
async function downloadAndSaveImage(imageUrl, fileId) {
|
| 47 |
+
const tmpDir = path.join(process.cwd(), 'tmp');
|
| 48 |
+
|
| 49 |
+
if (!fs.existsSync(tmpDir)) {
|
| 50 |
+
fs.mkdirSync(tmpDir, { recursive: true });
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
const filePath = path.join(tmpDir, `flux-${fileId}.webp`);
|
| 54 |
+
|
| 55 |
+
const response = await axios.get(imageUrl, {
|
| 56 |
+
responseType: 'arraybuffer',
|
| 57 |
+
timeout: 30000
|
| 58 |
+
});
|
| 59 |
+
|
| 60 |
+
fs.writeFileSync(filePath, Buffer.from(response.data));
|
| 61 |
+
|
| 62 |
+
setTimeout(() => {
|
| 63 |
+
if (fs.existsSync(filePath)) {
|
| 64 |
+
fs.unlinkSync(filePath);
|
| 65 |
+
}
|
| 66 |
+
}, 60000);
|
| 67 |
+
|
| 68 |
+
return `flux-${fileId}.webp`;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
const handler = async (req, res) => {
|
| 72 |
+
try {
|
| 73 |
+
const { prompt, key, width, height, server } = req.query;
|
| 74 |
+
|
| 75 |
+
if (!prompt) {
|
| 76 |
+
return res.status(400).json({
|
| 77 |
+
author: "Herza",
|
| 78 |
+
success: false,
|
| 79 |
+
error: 'Missing required parameter: prompt'
|
| 80 |
+
});
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
if (!key) {
|
| 84 |
+
return res.status(400).json({
|
| 85 |
+
author: "Herza",
|
| 86 |
+
success: false,
|
| 87 |
+
error: 'Missing required parameter: key'
|
| 88 |
+
});
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
const imgWidth = width ? parseInt(width) : 1024;
|
| 92 |
+
const imgHeight = height ? parseInt(height) : 1024;
|
| 93 |
+
const selectedServer = server || "NSFW-Core: Uncensored Server 2";
|
| 94 |
+
|
| 95 |
+
const imageUrl = await fluxImage(prompt, imgWidth, imgHeight, selectedServer);
|
| 96 |
+
|
| 97 |
+
if (!imageUrl) {
|
| 98 |
+
return res.status(500).json({
|
| 99 |
+
author: "Herza",
|
| 100 |
+
success: false,
|
| 101 |
+
error: 'Failed to generate image'
|
| 102 |
+
});
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
const fileId = Date.now() + '_' + Math.random().toString(36).substring(7);
|
| 106 |
+
const filename = await downloadAndSaveImage(imageUrl, fileId);
|
| 107 |
+
|
| 108 |
+
const baseUrl = `${req.protocol}://${req.get('host')}`;
|
| 109 |
+
const localUrl = `${baseUrl}/tmp/${filename}`;
|
| 110 |
+
|
| 111 |
+
res.json({
|
| 112 |
+
author: "Herza",
|
| 113 |
+
success: true,
|
| 114 |
+
data: {
|
| 115 |
+
result: localUrl
|
| 116 |
+
}
|
| 117 |
+
});
|
| 118 |
+
|
| 119 |
+
} catch (error) {
|
| 120 |
+
res.status(500).json({
|
| 121 |
+
author: "Herza",
|
| 122 |
+
success: false,
|
| 123 |
+
error: error.message
|
| 124 |
+
});
|
| 125 |
+
}
|
| 126 |
+
};
|
| 127 |
+
|
| 128 |
+
module.exports = {
|
| 129 |
+
name: 'Flux Image Generator',
|
| 130 |
+
description: 'Generate images using Flux AI model',
|
| 131 |
+
type: 'GET',
|
| 132 |
+
routes: ['api/AI/Flux'],
|
| 133 |
+
tags: ['ai', 'image', 'flux', 'generator'],
|
| 134 |
+
main: ['AI'],
|
| 135 |
+
parameters: ['prompt', 'key', 'width', 'height', 'server'],
|
| 136 |
+
enabled: true,
|
| 137 |
+
handler
|
| 138 |
+
};
|
plugins/google.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { googleit } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: text'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const results = await googleit(text);
|
| 15 |
+
|
| 16 |
+
res.json({
|
| 17 |
+
author: 'Herza',
|
| 18 |
+
success: true,
|
| 19 |
+
data: results.data
|
| 20 |
+
});
|
| 21 |
+
|
| 22 |
+
} catch (error) {
|
| 23 |
+
res.status(500).json({
|
| 24 |
+
success: false,
|
| 25 |
+
error: error.message
|
| 26 |
+
});
|
| 27 |
+
}
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
module.exports = {
|
| 31 |
+
name: 'Google Search',
|
| 32 |
+
description: 'Search Google by keyword',
|
| 33 |
+
type: 'GET',
|
| 34 |
+
routes: ['api/search/google'],
|
| 35 |
+
tags: ['search', 'google', 'tools'],
|
| 36 |
+
parameters: ['text'],
|
| 37 |
+
enabled: true,
|
| 38 |
+
main: ['Search'],
|
| 39 |
+
handler
|
| 40 |
+
};
|
plugins/gpt-5.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const WebSocket = require('ws')
|
| 2 |
+
const axios = require('axios')
|
| 3 |
+
|
| 4 |
+
class GPT5 {
|
| 5 |
+
constructor() {
|
| 6 |
+
this.conversationId = null
|
| 7 |
+
this.headers = {
|
| 8 |
+
origin: 'https://copilot.microsoft.com',
|
| 9 |
+
'user-agent': 'Mozilla/5.0 (Linux; Android 15; SM-F958 Build/AP3A.240905.015) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.86 Mobile Safari/537.36'
|
| 10 |
+
}
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
async createConversation() {
|
| 14 |
+
let { data } = await axios.post('https://copilot.microsoft.com/c/api/conversations', null, { headers: this.headers })
|
| 15 |
+
this.conversationId = data.id
|
| 16 |
+
return this.conversationId
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
async chat(message) {
|
| 20 |
+
if (!this.conversationId) await this.createConversation()
|
| 21 |
+
return new Promise((resolve, reject) => {
|
| 22 |
+
const ws = new WebSocket(`wss://copilot.microsoft.com/c/api/chat?api-version=2&features=-,ncedge,edgepagecontext&setflight=-,ncedge,edgepagecontext&ncedge=1`, { headers: this.headers })
|
| 23 |
+
const response = { text: '', citations: [] }
|
| 24 |
+
ws.on('open', () => {
|
| 25 |
+
ws.send(JSON.stringify({
|
| 26 |
+
event: 'setOptions',
|
| 27 |
+
supportedFeatures: ['partial-generated-images'],
|
| 28 |
+
supportedCards: ['weather', 'local', 'image', 'sports', 'video', 'ads', 'safetyHelpline', 'quiz', 'finance', 'recipe'],
|
| 29 |
+
ads: { supportedTypes: ['text', 'product', 'multimedia', 'tourActivity', 'propertyPromotion'] }
|
| 30 |
+
}))
|
| 31 |
+
ws.send(JSON.stringify({
|
| 32 |
+
event: 'send',
|
| 33 |
+
mode: 'smart',
|
| 34 |
+
conversationId: this.conversationId,
|
| 35 |
+
content: [{ type: 'text', text: message }],
|
| 36 |
+
context: {}
|
| 37 |
+
}))
|
| 38 |
+
})
|
| 39 |
+
ws.on('message', (chunk) => {
|
| 40 |
+
try {
|
| 41 |
+
const parsed = JSON.parse(chunk.toString())
|
| 42 |
+
switch (parsed.event) {
|
| 43 |
+
case 'appendText':
|
| 44 |
+
response.text += parsed.text || ''
|
| 45 |
+
break
|
| 46 |
+
case 'citation':
|
| 47 |
+
response.citations.push({ title: parsed.title, icon: parsed.iconUrl, url: parsed.url })
|
| 48 |
+
break
|
| 49 |
+
case 'done':
|
| 50 |
+
resolve(response)
|
| 51 |
+
ws.close()
|
| 52 |
+
break
|
| 53 |
+
case 'error':
|
| 54 |
+
reject(new Error(parsed.message))
|
| 55 |
+
ws.close()
|
| 56 |
+
break
|
| 57 |
+
}
|
| 58 |
+
} catch (error) {
|
| 59 |
+
reject(error.message)
|
| 60 |
+
}
|
| 61 |
+
})
|
| 62 |
+
ws.on('error', reject)
|
| 63 |
+
})
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
const handler = async (req, res) => {
|
| 68 |
+
try {
|
| 69 |
+
const { text } = req.query
|
| 70 |
+
|
| 71 |
+
if (!text) {
|
| 72 |
+
return res.status(400).json({
|
| 73 |
+
author: 'Herza',
|
| 74 |
+
success: false,
|
| 75 |
+
msg: 'Missing required parameter: text'
|
| 76 |
+
})
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
const gpt5 = new GPT5()
|
| 80 |
+
const result = await gpt5.chat(text)
|
| 81 |
+
|
| 82 |
+
res.json({
|
| 83 |
+
author: 'Herza',
|
| 84 |
+
success: true,
|
| 85 |
+
model: 'gpt-5',
|
| 86 |
+
msg: result.text.trim(),
|
| 87 |
+
citations: result.citations
|
| 88 |
+
})
|
| 89 |
+
|
| 90 |
+
} catch (error) {
|
| 91 |
+
console.error('Error fetching from GPT-5:', error)
|
| 92 |
+
res.status(500).json({
|
| 93 |
+
author: 'Herza',
|
| 94 |
+
success: false,
|
| 95 |
+
msg: 'Terjadi kesalahan saat menghubungi AI.'
|
| 96 |
+
})
|
| 97 |
+
}
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
module.exports = {
|
| 101 |
+
name: 'GPT-5 AI',
|
| 102 |
+
description: 'Generate responses using GPT-5 Smart Model via Copilot',
|
| 103 |
+
type: 'GET',
|
| 104 |
+
routes: ['api/AI/gpt-5'],
|
| 105 |
+
tags: ['ai', 'gpt-5', 'smart'],
|
| 106 |
+
parameters: ['text'],
|
| 107 |
+
enabled: true,
|
| 108 |
+
main: ['AI'],
|
| 109 |
+
handler
|
| 110 |
+
}
|
plugins/herxa
ADDED
|
File without changes
|
plugins/ig.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { instagram } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { url } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!url) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: url'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await instagram(url);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
data: result.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'Instagram DL',
|
| 31 |
+
description: 'Download Instagram Video Without WM',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/download/instagram'],
|
| 34 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 35 |
+
parameters: ['url', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['Downloader'],
|
| 38 |
+
handler
|
| 39 |
+
}
|
plugins/igstalk.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function igstalk(user) {
|
| 4 |
+
try {
|
| 5 |
+
const profileResponse = await axios.post(
|
| 6 |
+
'https://api.boostfluence.com/api/instagram-profile-v2',
|
| 7 |
+
{ username: user },
|
| 8 |
+
{ headers: { 'Content-Type': 'application/json' } }
|
| 9 |
+
);
|
| 10 |
+
|
| 11 |
+
const profile = profileResponse.data;
|
| 12 |
+
|
| 13 |
+
let postsData = null;
|
| 14 |
+
try {
|
| 15 |
+
const initialPostsResponse = await axios.post(
|
| 16 |
+
'https://api.boostfluence.com/api/instagram-viewer-v2-2',
|
| 17 |
+
{ username: user, type: 'photo', pagination_token: null },
|
| 18 |
+
{ headers: { 'Content-Type': 'application/json' } }
|
| 19 |
+
);
|
| 20 |
+
|
| 21 |
+
if (initialPostsResponse.data.error === 'COMPUTE_REQUIRED') {
|
| 22 |
+
const { timestamp, expectedCompute } = initialPostsResponse.data.challenge;
|
| 23 |
+
|
| 24 |
+
const verifiedPostsResponse = await axios.post(
|
| 25 |
+
'https://api.boostfluence.com/api/instagram-viewer-v2-2',
|
| 26 |
+
{ username: user, type: 'photo', pagination_token: null },
|
| 27 |
+
{
|
| 28 |
+
headers: {
|
| 29 |
+
'Content-Type': 'application/json',
|
| 30 |
+
'X-Compute': expectedCompute.toString(),
|
| 31 |
+
'X-Timestamp': timestamp.toString()
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
);
|
| 35 |
+
|
| 36 |
+
postsData = verifiedPostsResponse.data;
|
| 37 |
+
} else {
|
| 38 |
+
postsData = initialPostsResponse.data;
|
| 39 |
+
}
|
| 40 |
+
} catch (postsError) {
|
| 41 |
+
console.error('Error fetching posts:', postsError.message);
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
return {
|
| 45 |
+
profile: {
|
| 46 |
+
username: profile.username,
|
| 47 |
+
full_name: profile.full_name,
|
| 48 |
+
biography: profile.biography,
|
| 49 |
+
follower_count: profile.follower_count,
|
| 50 |
+
following_count: profile.following_count,
|
| 51 |
+
media_count: profile.media_count,
|
| 52 |
+
profile_pic_url: profile.profile_pic_url,
|
| 53 |
+
profile_pic_url_hd: profile.profile_pic_url_hd,
|
| 54 |
+
is_verified: profile.is_verified,
|
| 55 |
+
is_private: profile.is_private,
|
| 56 |
+
external_url: profile.external_url,
|
| 57 |
+
category: profile.category
|
| 58 |
+
}
|
| 59 |
+
};
|
| 60 |
+
} catch (error) {
|
| 61 |
+
throw new Error(`Failed to fetch Instagram data: ${error.message}`);
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
const handler = async (req, res) => {
|
| 66 |
+
try {
|
| 67 |
+
const { username } = req.query;
|
| 68 |
+
|
| 69 |
+
if (!username) {
|
| 70 |
+
return res.status(400).json({
|
| 71 |
+
success: false,
|
| 72 |
+
error: 'Missing required parameter: username'
|
| 73 |
+
});
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
const usernameRegex = /^[a-zA-Z0-9._]{1,30}$/;
|
| 77 |
+
if (!usernameRegex.test(username)) {
|
| 78 |
+
return res.status(400).json({
|
| 79 |
+
success: false,
|
| 80 |
+
error: 'Invalid username format'
|
| 81 |
+
});
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
const result = await igstalk(username);
|
| 85 |
+
|
| 86 |
+
res.json({
|
| 87 |
+
author: "Herza",
|
| 88 |
+
success: true,
|
| 89 |
+
data: result
|
| 90 |
+
});
|
| 91 |
+
|
| 92 |
+
} catch (error) {
|
| 93 |
+
res.status(500).json({
|
| 94 |
+
author: "Herza",
|
| 95 |
+
success: false,
|
| 96 |
+
error: error.message
|
| 97 |
+
});
|
| 98 |
+
}
|
| 99 |
+
};
|
| 100 |
+
|
| 101 |
+
module.exports = {
|
| 102 |
+
name: 'Instagram Stalk',
|
| 103 |
+
description: 'Get Instagram user profile information including stats, bio, and posts',
|
| 104 |
+
type: 'GET',
|
| 105 |
+
routes: ['api/stalk/instagram'],
|
| 106 |
+
tags: ['social', 'instagram', 'stalk', 'profile'],
|
| 107 |
+
parameters: ['username', 'key'],
|
| 108 |
+
enabled: true,
|
| 109 |
+
main: ['Stalk'],
|
| 110 |
+
handler
|
| 111 |
+
};
|
plugins/img2pixel.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const fs = require('fs');
|
| 3 |
+
const os = require('os');
|
| 4 |
+
const path = require('path');
|
| 5 |
+
|
| 6 |
+
async function img2pixel(imgUrl) {
|
| 7 |
+
let tempFilePath = null;
|
| 8 |
+
|
| 9 |
+
try {
|
| 10 |
+
const response = await axios.get(imgUrl, {
|
| 11 |
+
responseType: 'arraybuffer',
|
| 12 |
+
timeout: 30000
|
| 13 |
+
});
|
| 14 |
+
|
| 15 |
+
const imageBuffer = Buffer.from(response.data);
|
| 16 |
+
|
| 17 |
+
const tempFileName = `img2pixel_${Date.now()}_${Math.random().toString(36).substring(7)}.jpg`;
|
| 18 |
+
tempFilePath = path.join(os.tmpdir(), tempFileName);
|
| 19 |
+
fs.writeFileSync(tempFilePath, imageBuffer);
|
| 20 |
+
|
| 21 |
+
const filename = imgUrl.split('/').pop().split('?')[0] || tempFileName;
|
| 22 |
+
const contentType = 'image/jpeg';
|
| 23 |
+
|
| 24 |
+
const presignedResponse = await axios.post(
|
| 25 |
+
'https://pixelartgenerator.app/api/upload/presigned-url',
|
| 26 |
+
{
|
| 27 |
+
filename: filename,
|
| 28 |
+
contentType: contentType,
|
| 29 |
+
type: 'pixel-art-source'
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
headers: {
|
| 33 |
+
'Content-Type': 'application/json'
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
);
|
| 37 |
+
|
| 38 |
+
const { uploadUrl, key, publicUrl } = presignedResponse.data.data;
|
| 39 |
+
|
| 40 |
+
await axios.put(uploadUrl, imageBuffer, {
|
| 41 |
+
headers: {
|
| 42 |
+
'Content-Type': contentType
|
| 43 |
+
}
|
| 44 |
+
});
|
| 45 |
+
|
| 46 |
+
if (tempFilePath && fs.existsSync(tempFilePath)) {
|
| 47 |
+
fs.unlinkSync(tempFilePath);
|
| 48 |
+
tempFilePath = null;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
const generateResponse = await axios.post(
|
| 52 |
+
'https://pixelartgenerator.app/api/pixel/generate',
|
| 53 |
+
{
|
| 54 |
+
size: '1:1',
|
| 55 |
+
type: 'image',
|
| 56 |
+
imageKey: key,
|
| 57 |
+
prompt: ''
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
headers: {
|
| 61 |
+
'Content-Type': 'application/json'
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
);
|
| 65 |
+
|
| 66 |
+
const { taskId } = generateResponse.data.data;
|
| 67 |
+
|
| 68 |
+
let attempts = 0;
|
| 69 |
+
const maxAttempts = 60;
|
| 70 |
+
|
| 71 |
+
while (attempts < maxAttempts) {
|
| 72 |
+
const statusResponse = await axios.get(
|
| 73 |
+
`https://pixelartgenerator.app/api/pixel/status?taskId=${taskId}`
|
| 74 |
+
);
|
| 75 |
+
|
| 76 |
+
const { status, progress, images, error } = statusResponse.data.data;
|
| 77 |
+
|
| 78 |
+
if (status === 'SUCCESS' && images.length > 0) {
|
| 79 |
+
return images[0];
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
if (error) {
|
| 83 |
+
throw new Error(`Generation failed: ${error}`);
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
attempts++;
|
| 87 |
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
throw new Error('Timeout: Generation took too long');
|
| 91 |
+
|
| 92 |
+
} catch (error) {
|
| 93 |
+
if (tempFilePath && fs.existsSync(tempFilePath)) {
|
| 94 |
+
try {
|
| 95 |
+
fs.unlinkSync(tempFilePath);
|
| 96 |
+
} catch (cleanupError) {
|
| 97 |
+
console.error('Failed to cleanup temp file:', cleanupError);
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
throw new Error(`img2pixel error: ${error.message}`);
|
| 101 |
+
}
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
const handler = async (req, res) => {
|
| 105 |
+
try {
|
| 106 |
+
const { img, key } = req.query;
|
| 107 |
+
|
| 108 |
+
if (!img) {
|
| 109 |
+
return res.status(400).json({
|
| 110 |
+
author: "Herza",
|
| 111 |
+
success: false,
|
| 112 |
+
error: 'Missing required parameter: img (image URL)'
|
| 113 |
+
});
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
if (!key) {
|
| 117 |
+
return res.status(400).json({
|
| 118 |
+
author: "Herza",
|
| 119 |
+
success: false,
|
| 120 |
+
error: 'Missing required parameter: key'
|
| 121 |
+
});
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
try {
|
| 125 |
+
new URL(img);
|
| 126 |
+
} catch (e) {
|
| 127 |
+
return res.status(400).json({
|
| 128 |
+
author: "Herza",
|
| 129 |
+
success: false,
|
| 130 |
+
error: 'Invalid image URL format'
|
| 131 |
+
});
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
const result = await img2pixel(img);
|
| 135 |
+
|
| 136 |
+
res.json({
|
| 137 |
+
author: "Herza",
|
| 138 |
+
success: true,
|
| 139 |
+
data: {
|
| 140 |
+
result: result
|
| 141 |
+
}
|
| 142 |
+
});
|
| 143 |
+
|
| 144 |
+
} catch (error) {
|
| 145 |
+
res.status(500).json({
|
| 146 |
+
author: "Herza",
|
| 147 |
+
success: false,
|
| 148 |
+
error: error.message
|
| 149 |
+
});
|
| 150 |
+
}
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
module.exports = {
|
| 154 |
+
name: 'Image to Pixel Art',
|
| 155 |
+
description: 'Convert image to pixel art style',
|
| 156 |
+
type: 'GET',
|
| 157 |
+
routes: ['api/AI/img2pixel'],
|
| 158 |
+
tags: ['ai', 'image', 'pixel-art'],
|
| 159 |
+
main: ['AI'],
|
| 160 |
+
parameters: ['img', 'key'],
|
| 161 |
+
enabled: true,
|
| 162 |
+
handler
|
| 163 |
+
};
|
plugins/likee.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function likee(url) {
|
| 4 |
+
try {
|
| 5 |
+
const apiResponse = await axios.post(
|
| 6 |
+
'https://steptodown.com/wp-json/aio-dl/video-data/',
|
| 7 |
+
{ url: url },
|
| 8 |
+
{
|
| 9 |
+
headers: {
|
| 10 |
+
'Content-Type': 'application/json',
|
| 11 |
+
'Origin': 'https://steptodown.com',
|
| 12 |
+
'Referer': 'https://steptodown.com/',
|
| 13 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
| 14 |
+
'Accept': 'application/json, text/plain, */*',
|
| 15 |
+
'Accept-Language': 'en-US,en;q=0.9',
|
| 16 |
+
'Sec-Fetch-Dest': 'empty',
|
| 17 |
+
'Sec-Fetch-Mode': 'cors',
|
| 18 |
+
'Sec-Fetch-Site': 'same-origin'
|
| 19 |
+
},
|
| 20 |
+
timeout: 15000
|
| 21 |
+
}
|
| 22 |
+
);
|
| 23 |
+
|
| 24 |
+
const apiData = apiResponse.data;
|
| 25 |
+
|
| 26 |
+
return {
|
| 27 |
+
url: apiData.url || url,
|
| 28 |
+
title: apiData.title || null,
|
| 29 |
+
thumbnail: apiData.thumbnail || null,
|
| 30 |
+
duration: apiData.duration || null,
|
| 31 |
+
source: apiData.source || 'likee',
|
| 32 |
+
medias: apiData.medias || [],
|
| 33 |
+
sid: apiData.sid || null
|
| 34 |
+
};
|
| 35 |
+
} catch (error) {
|
| 36 |
+
throw new Error(error.message);
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
const handler = async (req, res) => {
|
| 41 |
+
try {
|
| 42 |
+
const { url } = req.query;
|
| 43 |
+
|
| 44 |
+
if (!url) {
|
| 45 |
+
return res.status(400).json({
|
| 46 |
+
author: 'Herza',
|
| 47 |
+
success: false,
|
| 48 |
+
error: 'Missing required parameter: url',
|
| 49 |
+
message: 'Please provide a Likee video URL'
|
| 50 |
+
});
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
if (!url.includes('likee.video') && !url.includes('likee.com')) {
|
| 54 |
+
return res.status(400).json({
|
| 55 |
+
author: 'Herza',
|
| 56 |
+
success: false,
|
| 57 |
+
error: 'Invalid URL',
|
| 58 |
+
message: 'Please provide a valid Likee video URL'
|
| 59 |
+
});
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
const result = await likee(url);
|
| 63 |
+
|
| 64 |
+
res.json({
|
| 65 |
+
author: 'Herza',
|
| 66 |
+
success: true,
|
| 67 |
+
data: result
|
| 68 |
+
});
|
| 69 |
+
} catch (error) {
|
| 70 |
+
res.status(500).json({
|
| 71 |
+
author: 'Herza',
|
| 72 |
+
success: false,
|
| 73 |
+
error: error.message
|
| 74 |
+
});
|
| 75 |
+
}
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
module.exports = {
|
| 79 |
+
name: 'Likee Downloader',
|
| 80 |
+
description: 'Download Likee videos without watermark using steptodown API',
|
| 81 |
+
type: 'GET',
|
| 82 |
+
routes: ['api/download/likee'],
|
| 83 |
+
tags: ['tools', 'likee', 'downloader', 'social-media'],
|
| 84 |
+
main: ['Downloader'],
|
| 85 |
+
parameters: ['url', 'key'],
|
| 86 |
+
enabled: true,
|
| 87 |
+
handler
|
| 88 |
+
};
|
plugins/lyrics.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { query } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!query) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: query'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
let result = await axios.get(`https://lyrics.lewdhutao.my.eu.org/v2/youtube/lyrics?title=${encodeURIComponent(query)}`)
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
data: result.data.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'Lyrics Search',
|
| 31 |
+
description: 'Input song name and system will get the lyrics for you',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/search/lyrics'],
|
| 34 |
+
tags: ['Youtube', 'Genius Lyrics', 'Lyrics'],
|
| 35 |
+
main: ['Search'],
|
| 36 |
+
parameters: ['query', 'key'],
|
| 37 |
+
enabled: true,
|
| 38 |
+
limit: 5,
|
| 39 |
+
handler
|
| 40 |
+
};
|
plugins/mcstalk.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { mcstalk } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: text'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await mcstalk(text);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
data: result.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'Minecraft Stalk',
|
| 31 |
+
description: 'Stalk someone Minecraft account with username',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/stalk/minecraft'],
|
| 34 |
+
tags: ['stalk', 'tools', 'misc'],
|
| 35 |
+
parameters: ['text', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['Stalk'],
|
| 38 |
+
handler
|
| 39 |
+
}
|
plugins/mediafire.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const cheerio = require('cheerio');
|
| 2 |
+
const { basename, extname } = require('path');
|
| 3 |
+
|
| 4 |
+
async function mediafire(url) {
|
| 5 |
+
const $ = cheerio.load(await (await fetch(url.trim())).text())
|
| 6 |
+
const title = $("meta[property='og:title']").attr("content")?.trim() || "Unknown"
|
| 7 |
+
const size = /Download\s*\(([\d.]+\s*[KMGT]?B)\)/i.exec($.html())?.[1] || "Unknown"
|
| 8 |
+
const dl = $("a.popsok[href^='https://download']").attr("href")?.trim() || $("a.popsok:not([href^='javascript'])").attr("href")?.trim() || (() => { throw new Error("Download URL not found.") })()
|
| 9 |
+
return { name: title, filename: basename(dl), type: extname(dl), size, download: dl, link: url.trim() }
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
const handler = async (req, res) => {
|
| 13 |
+
try {
|
| 14 |
+
const { url } = req.query;
|
| 15 |
+
|
| 16 |
+
if (!url) {
|
| 17 |
+
return res.status(400).json({
|
| 18 |
+
success: false,
|
| 19 |
+
error: 'Missing required parameter: url'
|
| 20 |
+
});
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
const result = await mediafire(url);
|
| 24 |
+
res.json({
|
| 25 |
+
author: "Herza",
|
| 26 |
+
success: true,
|
| 27 |
+
data: result
|
| 28 |
+
});
|
| 29 |
+
|
| 30 |
+
} catch (error) {
|
| 31 |
+
res.status(500).json({
|
| 32 |
+
success: false,
|
| 33 |
+
error: error.message
|
| 34 |
+
});
|
| 35 |
+
}
|
| 36 |
+
};
|
| 37 |
+
|
| 38 |
+
module.exports = {
|
| 39 |
+
name: 'MediaFire DL',
|
| 40 |
+
description: 'Download File From Mediafire',
|
| 41 |
+
type: 'GET',
|
| 42 |
+
routes: ['api/download/mediafire'],
|
| 43 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 44 |
+
parameters: ['url', 'key'],
|
| 45 |
+
enabled: true,
|
| 46 |
+
main: ['Downloader'],
|
| 47 |
+
handler
|
| 48 |
+
}
|
plugins/nnbana.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require("axios");
|
| 2 |
+
|
| 3 |
+
async function NanoBanana(prompt, imageUrl, cookie) {
|
| 4 |
+
try {
|
| 5 |
+
const api = `https://anabot.my.id/api/ai/geminiOption?prompt=${encodeURIComponent(prompt)}&type=NanoBanana&imageUrl=${encodeURIComponent(imageUrl)}&imageUrl2=&imageUrl3=&imageUrl4=&cookie=${encodeURIComponent(cookie)}&apikey=freeApikey`;
|
| 6 |
+
|
| 7 |
+
const response = await axios.get(api, {
|
| 8 |
+
headers: { 'Accept': 'application/json' }
|
| 9 |
+
});
|
| 10 |
+
|
| 11 |
+
if (response.data && response.data.data && response.data.data.result) {
|
| 12 |
+
return {
|
| 13 |
+
success: true,
|
| 14 |
+
url: response.data.data.result.url,
|
| 15 |
+
prompt: prompt
|
| 16 |
+
};
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
throw new Error('Gagal memproses gambar');
|
| 20 |
+
} catch (err) {
|
| 21 |
+
throw new Error(err.response?.data?.message || err.message);
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
const handler = async (req, res) => {
|
| 26 |
+
try {
|
| 27 |
+
const { prompt, imageUrl, cookie, key } = req.query;
|
| 28 |
+
|
| 29 |
+
if (!key) {
|
| 30 |
+
return res.status(400).json({
|
| 31 |
+
success: false,
|
| 32 |
+
error: 'Missing required parameter: key'
|
| 33 |
+
});
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
if (!prompt) {
|
| 37 |
+
return res.status(400).json({
|
| 38 |
+
success: false,
|
| 39 |
+
error: 'Missing required parameter: prompt'
|
| 40 |
+
});
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
if (!imageUrl) {
|
| 44 |
+
return res.status(400).json({
|
| 45 |
+
success: false,
|
| 46 |
+
error: 'Missing required parameter: imageUrl'
|
| 47 |
+
});
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
if (!cookie) {
|
| 51 |
+
return res.status(400).json({
|
| 52 |
+
success: false,
|
| 53 |
+
error: 'Missing required parameter: cookie'
|
| 54 |
+
});
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
const result = await NanoBanana(prompt, imageUrl, cookie);
|
| 58 |
+
|
| 59 |
+
return res.json({
|
| 60 |
+
author: "Herza",
|
| 61 |
+
success: true,
|
| 62 |
+
data: {
|
| 63 |
+
prompt: result.prompt,
|
| 64 |
+
image_url: result.url,
|
| 65 |
+
original_url: imageUrl
|
| 66 |
+
},
|
| 67 |
+
timestamp: new Date().toISOString()
|
| 68 |
+
});
|
| 69 |
+
|
| 70 |
+
} catch (error) {
|
| 71 |
+
res.status(500).json({
|
| 72 |
+
success: false,
|
| 73 |
+
error: error.message,
|
| 74 |
+
timestamp: new Date().toISOString()
|
| 75 |
+
});
|
| 76 |
+
}
|
| 77 |
+
};
|
| 78 |
+
|
| 79 |
+
module.exports = {
|
| 80 |
+
name: 'Nano Banana',
|
| 81 |
+
description: 'AI Image Editing using Gemini - Edit images with text prompts',
|
| 82 |
+
type: 'GET',
|
| 83 |
+
routes: ['api/AI/nanobanana'],
|
| 84 |
+
tags: ['ai', 'image', 'editing', 'gemini', 'nanobanana'],
|
| 85 |
+
parameters: ['prompt', 'imageUrl', 'cookie', 'key'],
|
| 86 |
+
limit: 5,
|
| 87 |
+
enabled: true,
|
| 88 |
+
main: ['AI'],
|
| 89 |
+
handler,
|
| 90 |
+
NanoBanana
|
| 91 |
+
};
|
plugins/openai.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { openai } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: text'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await openai(text);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
msg: result.msg
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'ChatGPT AI',
|
| 31 |
+
description: 'Generate responses using OpenAI ChatGPT',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/AI/chatgpt'],
|
| 34 |
+
tags: ['ai', 'chatgpt', 'openai'],
|
| 35 |
+
main: ['AI'],
|
| 36 |
+
parameters: ['text', 'key'],
|
| 37 |
+
enabled: true,
|
| 38 |
+
handler
|
| 39 |
+
};
|
plugins/perplexity.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { perplexity } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: text'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await perplexity(text);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
msg: result.msg
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'Perplexity AI',
|
| 31 |
+
description: 'Generate responses using Perplexity AI',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/AI/perplexity'],
|
| 34 |
+
tags: ['ai', 'perplexity'],
|
| 35 |
+
parameters: ['text', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['AI'],
|
| 38 |
+
handler
|
| 39 |
+
};
|
plugins/pinlens.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const FormData = require('form-data');
|
| 3 |
+
const crypto = require('crypto');
|
| 4 |
+
// SCRAPE BY SIPUTZX
|
| 5 |
+
class PinterestLensScraper {
|
| 6 |
+
constructor(authToken) {
|
| 7 |
+
this.authToken = authToken;
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
getRandomHeaders() {
|
| 11 |
+
const devices = [
|
| 12 |
+
{ model: 'SM-G991B', manufacturer: 'samsung', name: 'Samsung Galaxy S21' },
|
| 13 |
+
{ model: 'SM-A525F', manufacturer: 'samsung', name: 'Samsung Galaxy A52' },
|
| 14 |
+
{ model: 'Pixel 6', manufacturer: 'Google', name: 'Google Pixel 6' },
|
| 15 |
+
{ model: 'Pixel 7 Pro', manufacturer: 'Google', name: 'Google Pixel 7 Pro' },
|
| 16 |
+
{ model: 'M2101K6G', manufacturer: 'Xiaomi', name: 'Xiaomi Redmi Note 10' },
|
| 17 |
+
{ model: '2201117TG', manufacturer: 'Xiaomi', name: 'Xiaomi 11T' },
|
| 18 |
+
{ model: 'CPH2121', manufacturer: 'OPPO', name: 'OPPO Reno5' },
|
| 19 |
+
{ model: 'RMX3085', manufacturer: 'realme', name: 'realme 8 Pro' },
|
| 20 |
+
{ model: 'itel S665L', manufacturer: 'ITEL', name: 'itel S665L' },
|
| 21 |
+
{ model: 'TECNO KE5', manufacturer: 'TECNO', name: 'TECNO Spark 7' }
|
| 22 |
+
];
|
| 23 |
+
|
| 24 |
+
const versions = ['13.36.2', '13.35.0', '13.34.1', '13.33.0', '13.32.1'];
|
| 25 |
+
const androidVersions = ['11', '12', '13'];
|
| 26 |
+
|
| 27 |
+
const device = devices[Math.floor(Math.random() * devices.length)];
|
| 28 |
+
const version = versions[Math.floor(Math.random() * versions.length)];
|
| 29 |
+
const androidVer = androidVersions[Math.floor(Math.random() * androidVersions.length)];
|
| 30 |
+
const advertisingId = crypto.randomUUID();
|
| 31 |
+
const hardwareId = crypto.randomBytes(8).toString('hex');
|
| 32 |
+
const installId = crypto.randomBytes(16).toString('hex');
|
| 33 |
+
|
| 34 |
+
return {
|
| 35 |
+
'User-Agent': `Pinterest for Android/${version} (${device.model}; ${androidVer})`,
|
| 36 |
+
'accept-language': 'id-ID',
|
| 37 |
+
'x-pinterest-advertising-id': advertisingId,
|
| 38 |
+
'x-pinterest-app-type-detailed': '3',
|
| 39 |
+
'x-pinterest-device': device.model,
|
| 40 |
+
'x-pinterest-device-hardwareid': hardwareId,
|
| 41 |
+
'x-pinterest-device-manufacturer': device.manufacturer,
|
| 42 |
+
'x-pinterest-installid': installId,
|
| 43 |
+
'x-pinterest-webview-supported': 'false',
|
| 44 |
+
'x-pinterest-appstate': 'active',
|
| 45 |
+
'x-node-id': 'true',
|
| 46 |
+
'authorization': `Bearer ${this.authToken}`
|
| 47 |
+
};
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
async searchByImage(imageUrl, pageSize = 12) {
|
| 51 |
+
const data = new FormData();
|
| 52 |
+
data.append('camera_type', '0');
|
| 53 |
+
data.append('source_type', '1');
|
| 54 |
+
data.append('video_autoplay_disabled', '0');
|
| 55 |
+
data.append('fields', this.getFields());
|
| 56 |
+
data.append('page_size', pageSize.toString());
|
| 57 |
+
data.append('image_url', imageUrl);
|
| 58 |
+
|
| 59 |
+
const headers = this.getRandomHeaders();
|
| 60 |
+
const response = await axios.post(
|
| 61 |
+
'https://api.pinterest.com/v3/visual_search/lens/search/',
|
| 62 |
+
data,
|
| 63 |
+
{ headers: { ...headers, ...data.getHeaders() } }
|
| 64 |
+
);
|
| 65 |
+
|
| 66 |
+
return this.parseResults(response.data);
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
async getMoreResults(bookmark, url, pageSize = 12) {
|
| 70 |
+
const params = new URLSearchParams({
|
| 71 |
+
bookmark,
|
| 72 |
+
camera_type: '0',
|
| 73 |
+
source_type: '1',
|
| 74 |
+
video_autoplay_disabled: '0',
|
| 75 |
+
fields: this.getFields(),
|
| 76 |
+
url,
|
| 77 |
+
page_size: pageSize.toString(),
|
| 78 |
+
view_type: '119',
|
| 79 |
+
view_parameter: '3064'
|
| 80 |
+
});
|
| 81 |
+
|
| 82 |
+
const headers = this.getRandomHeaders();
|
| 83 |
+
const response = await axios.get(
|
| 84 |
+
`https://api.pinterest.com/v3/visual_search/lens/search/?${params}`,
|
| 85 |
+
{ headers }
|
| 86 |
+
);
|
| 87 |
+
|
| 88 |
+
return this.parseResults(response.data);
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
async scrapeAll(imageUrl, maxPages = 5) {
|
| 92 |
+
const allResults = [];
|
| 93 |
+
|
| 94 |
+
const firstPage = await this.searchByImage(imageUrl);
|
| 95 |
+
allResults.push(...firstPage.pins);
|
| 96 |
+
|
| 97 |
+
let bookmark = firstPage.bookmark;
|
| 98 |
+
let url = firstPage.url;
|
| 99 |
+
let page = 2;
|
| 100 |
+
|
| 101 |
+
while (bookmark && page <= maxPages) {
|
| 102 |
+
const nextPage = await this.getMoreResults(bookmark, url);
|
| 103 |
+
allResults.push(...nextPage.pins);
|
| 104 |
+
bookmark = nextPage.bookmark;
|
| 105 |
+
page++;
|
| 106 |
+
await this.delay(100);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
return {
|
| 110 |
+
total: allResults.length,
|
| 111 |
+
pins: allResults,
|
| 112 |
+
visualObjects: firstPage.visualObjects,
|
| 113 |
+
searchIdentifier: firstPage.searchIdentifier
|
| 114 |
+
};
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
parseResults(response) {
|
| 118 |
+
const pins = response.data.map(pin => ({
|
| 119 |
+
id: pin.id,
|
| 120 |
+
title: pin.title || '',
|
| 121 |
+
description: pin.description || '',
|
| 122 |
+
imageUrl: pin.images?.['736x']?.url || pin.images?.originals?.url,
|
| 123 |
+
thumbnailUrl: pin.images?.['236x']?.url,
|
| 124 |
+
dominantColor: pin.dominant_color,
|
| 125 |
+
creator: {
|
| 126 |
+
id: pin.pinner?.id,
|
| 127 |
+
username: pin.pinner?.username,
|
| 128 |
+
fullName: pin.pinner?.full_name,
|
| 129 |
+
imageUrl: pin.pinner?.image_medium_url
|
| 130 |
+
},
|
| 131 |
+
board: {
|
| 132 |
+
id: pin.board?.id,
|
| 133 |
+
name: pin.board?.name,
|
| 134 |
+
url: pin.board?.url
|
| 135 |
+
},
|
| 136 |
+
stats: {
|
| 137 |
+
saves: pin.aggregated_pin_data?.aggregated_stats?.saves || 0,
|
| 138 |
+
comments: pin.comment_count || 0
|
| 139 |
+
},
|
| 140 |
+
createdAt: pin.created_at,
|
| 141 |
+
isVideo: pin.is_video || false,
|
| 142 |
+
link: pin.link,
|
| 143 |
+
domain: pin.domain
|
| 144 |
+
}));
|
| 145 |
+
|
| 146 |
+
return {
|
| 147 |
+
pins,
|
| 148 |
+
bookmark: response.bookmark,
|
| 149 |
+
url: response.url,
|
| 150 |
+
visualObjects: response.visual_objects,
|
| 151 |
+
searchIdentifier: response.search_identifier
|
| 152 |
+
};
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
getFields() {
|
| 156 |
+
return 'pin.{id,title,description,images[736x,236x],dominant_color,pinner(),board(),aggregated_pin_data(),comment_count,created_at,is_video,link,domain},user.{id,username,full_name,image_medium_url},board.{id,name,url},aggregatedpindata.{aggregated_stats}';
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
delay(ms) {
|
| 160 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
const handler = async (req, res) => {
|
| 165 |
+
try {
|
| 166 |
+
const { imageUrl, token, maxPages = 5, key } = req.query;
|
| 167 |
+
|
| 168 |
+
if (!imageUrl) {
|
| 169 |
+
return res.status(400).json({
|
| 170 |
+
success: false,
|
| 171 |
+
error: 'Missing required parameter: imageUrl'
|
| 172 |
+
});
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
if (!token) {
|
| 176 |
+
return res.status(400).json({
|
| 177 |
+
success: false,
|
| 178 |
+
error: 'Missing required parameter: token'
|
| 179 |
+
});
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
const scraper = new PinterestLensScraper(token);
|
| 183 |
+
const results = await scraper.scrapeAll(imageUrl, parseInt(maxPages));
|
| 184 |
+
|
| 185 |
+
res.json({
|
| 186 |
+
author: 'siputzx',
|
| 187 |
+
success: true,
|
| 188 |
+
data: results
|
| 189 |
+
});
|
| 190 |
+
|
| 191 |
+
} catch (error) {
|
| 192 |
+
res.status(500).json({
|
| 193 |
+
success: false,
|
| 194 |
+
error: error.message
|
| 195 |
+
});
|
| 196 |
+
}
|
| 197 |
+
};
|
| 198 |
+
|
| 199 |
+
module.exports = {
|
| 200 |
+
name: 'Pinterest Lens Scraper',
|
| 201 |
+
description: 'Scrape Pinterest pins using image search with lens',
|
| 202 |
+
type: 'GET',
|
| 203 |
+
routes: ['api/tools/pinlens'],
|
| 204 |
+
tags: ['tools', 'pinterest', 'image-search'],
|
| 205 |
+
main: ['tools', 'Search'],
|
| 206 |
+
parameters: ['imageUrl', 'token', 'maxPages', 'key'],
|
| 207 |
+
enabled: true,
|
| 208 |
+
limit: 10,
|
| 209 |
+
handler
|
| 210 |
+
};
|
plugins/pinterest.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { pinsearch } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: text'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const results = await pinsearch(text);
|
| 15 |
+
|
| 16 |
+
res.json({
|
| 17 |
+
author: 'Herza',
|
| 18 |
+
success: true,
|
| 19 |
+
data: results.results
|
| 20 |
+
});
|
| 21 |
+
|
| 22 |
+
} catch (error) {
|
| 23 |
+
res.status(500).json({
|
| 24 |
+
success: false,
|
| 25 |
+
error: error.message
|
| 26 |
+
});
|
| 27 |
+
}
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
module.exports = {
|
| 31 |
+
name: 'Pinterest Search',
|
| 32 |
+
description: 'Search Pinterest images by keyword',
|
| 33 |
+
type: 'GET',
|
| 34 |
+
routes: ['api/search/pinsearch'],
|
| 35 |
+
tags: ['search', 'pinterest', 'tools'],
|
| 36 |
+
parameters: ['text'],
|
| 37 |
+
enabled: true,
|
| 38 |
+
main: ['Search'],
|
| 39 |
+
handler
|
| 40 |
+
};
|
plugins/qr-generator.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const handler = async (req, res) => {
|
| 2 |
+
try {
|
| 3 |
+
const { text, size = 200, format = 'png' } = req.query;
|
| 4 |
+
|
| 5 |
+
if (!text) {
|
| 6 |
+
return res.status(400).json({
|
| 7 |
+
success: false,
|
| 8 |
+
error: 'Missing required parameter: text'
|
| 9 |
+
});
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
const validSizes = [100, 150, 200, 250, 300, 400, 500];
|
| 13 |
+
const validFormats = ['png', 'svg'];
|
| 14 |
+
|
| 15 |
+
if (!validSizes.includes(parseInt(size))) {
|
| 16 |
+
return res.status(400).json({
|
| 17 |
+
success: false,
|
| 18 |
+
error: 'Invalid size. Valid sizes: ' + validSizes.join(', ')
|
| 19 |
+
});
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
if (!validFormats.includes(format.toLowerCase())) {
|
| 23 |
+
return res.status(400).json({
|
| 24 |
+
success: false,
|
| 25 |
+
error: 'Invalid format. Valid formats: ' + validFormats.join(', ')
|
| 26 |
+
});
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=${size}x${size}&data=${encodeURIComponent(text)}&format=${format}`;
|
| 30 |
+
|
| 31 |
+
res.json({
|
| 32 |
+
success: true,
|
| 33 |
+
data: {
|
| 34 |
+
text,
|
| 35 |
+
size: parseInt(size),
|
| 36 |
+
format,
|
| 37 |
+
qr_url: qrApiUrl,
|
| 38 |
+
download_url: qrApiUrl + '&download=1'
|
| 39 |
+
}
|
| 40 |
+
});
|
| 41 |
+
|
| 42 |
+
} catch (error) {
|
| 43 |
+
res.status(500).json({
|
| 44 |
+
success: false,
|
| 45 |
+
error: error.message
|
| 46 |
+
});
|
| 47 |
+
}
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
module.exports = {
|
| 51 |
+
name: 'QR Code Generator',
|
| 52 |
+
description: 'Generate QR codes for text, URLs, and more with custom sizes',
|
| 53 |
+
type: 'GET',
|
| 54 |
+
routes: ['api/tools/qr/generate'],
|
| 55 |
+
tags: ['utility', 'qr', 'generator'],
|
| 56 |
+
parameters: ['text', 'size', 'format', 'key'],
|
| 57 |
+
enabled: true,
|
| 58 |
+
main: ['tools'],
|
| 59 |
+
handler
|
| 60 |
+
};
|
plugins/random-generator.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const crypto = require('crypto');
|
| 2 |
+
|
| 3 |
+
const WORD_LISTS = {
|
| 4 |
+
lorem: [
|
| 5 |
+
'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit',
|
| 6 |
+
'sed', 'do', 'eiusmod', 'tempor', 'incididunt', 'ut', 'labore', 'et', 'dolore',
|
| 7 |
+
'magna', 'aliqua', 'enim', 'ad', 'minim', 'veniam', 'quis', 'nostrud',
|
| 8 |
+
'exercitation', 'ullamco', 'laboris', 'nisi', 'aliquip', 'ex', 'ea', 'commodo',
|
| 9 |
+
'consequat', 'duis', 'aute', 'irure', 'in', 'reprehenderit', 'voluptate',
|
| 10 |
+
'velit', 'esse', 'cillum', 'fugiat', 'nulla', 'pariatur', 'excepteur', 'sint',
|
| 11 |
+
'occaecat', 'cupidatat', 'non', 'proident', 'sunt', 'culpa', 'qui', 'officia',
|
| 12 |
+
'deserunt', 'mollit', 'anim', 'id', 'est', 'laborum'
|
| 13 |
+
],
|
| 14 |
+
english: [
|
| 15 |
+
'the', 'quick', 'brown', 'fox', 'jumps', 'over', 'lazy', 'dog', 'and', 'runs',
|
| 16 |
+
'through', 'forest', 'while', 'birds', 'sing', 'beautiful', 'songs', 'under',
|
| 17 |
+
'bright', 'sunny', 'sky', 'with', 'clouds', 'floating', 'peacefully', 'above',
|
| 18 |
+
'green', 'trees', 'beside', 'flowing', 'river', 'where', 'fish', 'swim',
|
| 19 |
+
'quietly', 'among', 'rocks', 'covered', 'moss', 'creating', 'natural', 'harmony'
|
| 20 |
+
],
|
| 21 |
+
tech: [
|
| 22 |
+
'algorithm', 'database', 'framework', 'library', 'function', 'variable', 'array',
|
| 23 |
+
'object', 'method', 'class', 'interface', 'component', 'module', 'package',
|
| 24 |
+
'deployment', 'server', 'client', 'backend', 'frontend', 'fullstack', 'api',
|
| 25 |
+
'endpoint', 'authentication', 'authorization', 'encryption', 'decryption',
|
| 26 |
+
'blockchain', 'machine', 'learning', 'artificial', 'intelligence', 'neural',
|
| 27 |
+
'network', 'deep', 'learning', 'data', 'science', 'analytics', 'visualization'
|
| 28 |
+
]
|
| 29 |
+
};
|
| 30 |
+
|
| 31 |
+
const CHARACTERS = {
|
| 32 |
+
lowercase: 'abcdefghijklmnopqrstuvwxyz',
|
| 33 |
+
uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
| 34 |
+
numbers: '0123456789',
|
| 35 |
+
symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?',
|
| 36 |
+
special: '!@#$%^&*'
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
const generateRandomWords = (count, wordList) => {
|
| 40 |
+
const words = [];
|
| 41 |
+
for (let i = 0; i < count; i++) {
|
| 42 |
+
const randomIndex = Math.floor(Math.random() * wordList.length);
|
| 43 |
+
words.push(wordList[randomIndex]);
|
| 44 |
+
}
|
| 45 |
+
return words.join(' ');
|
| 46 |
+
};
|
| 47 |
+
|
| 48 |
+
const generateRandomString = (length, charset) => {
|
| 49 |
+
let result = '';
|
| 50 |
+
for (let i = 0; i < length; i++) {
|
| 51 |
+
result += charset.charAt(Math.floor(Math.random() * charset.length));
|
| 52 |
+
}
|
| 53 |
+
return result;
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
const generatePassword = (length, options) => {
|
| 57 |
+
let charset = '';
|
| 58 |
+
if (options.lowercase) charset += CHARACTERS.lowercase;
|
| 59 |
+
if (options.uppercase) charset += CHARACTERS.uppercase;
|
| 60 |
+
if (options.numbers) charset += CHARACTERS.numbers;
|
| 61 |
+
if (options.symbols) charset += CHARACTERS.symbols;
|
| 62 |
+
|
| 63 |
+
if (!charset) charset = CHARACTERS.lowercase + CHARACTERS.uppercase + CHARACTERS.numbers;
|
| 64 |
+
|
| 65 |
+
return generateRandomString(length, charset);
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
const generateSentences = (count, wordList, minWords = 5, maxWords = 15) => {
|
| 69 |
+
const sentences = [];
|
| 70 |
+
for (let i = 0; i < count; i++) {
|
| 71 |
+
const wordCount = Math.floor(Math.random() * (maxWords - minWords + 1)) + minWords;
|
| 72 |
+
const words = [];
|
| 73 |
+
for (let j = 0; j < wordCount; j++) {
|
| 74 |
+
const randomIndex = Math.floor(Math.random() * wordList.length);
|
| 75 |
+
words.push(wordList[randomIndex]);
|
| 76 |
+
}
|
| 77 |
+
let sentence = words.join(' ');
|
| 78 |
+
sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1) + '.';
|
| 79 |
+
sentences.push(sentence);
|
| 80 |
+
}
|
| 81 |
+
return sentences.join(' ');
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
const handler = async (req, res) => {
|
| 85 |
+
try {
|
| 86 |
+
const {
|
| 87 |
+
type = 'words',
|
| 88 |
+
count = 10,
|
| 89 |
+
length = 12,
|
| 90 |
+
wordType = 'lorem',
|
| 91 |
+
includeNumbers = true,
|
| 92 |
+
includeUppercase = true,
|
| 93 |
+
includeLowercase = true,
|
| 94 |
+
includeSymbols = false,
|
| 95 |
+
minWords = 5,
|
| 96 |
+
maxWords = 15
|
| 97 |
+
} = req.query;
|
| 98 |
+
|
| 99 |
+
const validTypes = ['words', 'sentences', 'paragraphs', 'password', 'string', 'uuid'];
|
| 100 |
+
const validWordTypes = Object.keys(WORD_LISTS);
|
| 101 |
+
|
| 102 |
+
if (!validTypes.includes(type)) {
|
| 103 |
+
return res.status(400).json({
|
| 104 |
+
success: false,
|
| 105 |
+
error: `Invalid type. Valid types: ${validTypes.join(', ')}`
|
| 106 |
+
});
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
if (!validWordTypes.includes(wordType) && ['words', 'sentences', 'paragraphs'].includes(type)) {
|
| 110 |
+
return res.status(400).json({
|
| 111 |
+
success: false,
|
| 112 |
+
error: `Invalid wordType. Valid wordTypes: ${validWordTypes.join(', ')}`
|
| 113 |
+
});
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
let result = '';
|
| 117 |
+
const wordList = WORD_LISTS[wordType] || WORD_LISTS.lorem;
|
| 118 |
+
|
| 119 |
+
switch (type) {
|
| 120 |
+
case 'words':
|
| 121 |
+
result = generateRandomWords(parseInt(count), wordList);
|
| 122 |
+
break;
|
| 123 |
+
|
| 124 |
+
case 'sentences':
|
| 125 |
+
result = generateSentences(parseInt(count), wordList, parseInt(minWords), parseInt(maxWords));
|
| 126 |
+
break;
|
| 127 |
+
|
| 128 |
+
case 'paragraphs':
|
| 129 |
+
const paragraphs = [];
|
| 130 |
+
for (let i = 0; i < parseInt(count); i++) {
|
| 131 |
+
const sentenceCount = Math.floor(Math.random() * 6) + 3;
|
| 132 |
+
paragraphs.push(generateSentences(sentenceCount, wordList, parseInt(minWords), parseInt(maxWords)));
|
| 133 |
+
}
|
| 134 |
+
result = paragraphs.join('\n\n');
|
| 135 |
+
break;
|
| 136 |
+
|
| 137 |
+
case 'password':
|
| 138 |
+
const passwordOptions = {
|
| 139 |
+
lowercase: includeLowercase === 'true',
|
| 140 |
+
uppercase: includeUppercase === 'true',
|
| 141 |
+
numbers: includeNumbers === 'true',
|
| 142 |
+
symbols: includeSymbols === 'true'
|
| 143 |
+
};
|
| 144 |
+
result = generatePassword(parseInt(length), passwordOptions);
|
| 145 |
+
break;
|
| 146 |
+
|
| 147 |
+
case 'string':
|
| 148 |
+
let charset = '';
|
| 149 |
+
if (includeLowercase === 'true') charset += CHARACTERS.lowercase;
|
| 150 |
+
if (includeUppercase === 'true') charset += CHARACTERS.uppercase;
|
| 151 |
+
if (includeNumbers === 'true') charset += CHARACTERS.numbers;
|
| 152 |
+
if (includeSymbols === 'true') charset += CHARACTERS.symbols;
|
| 153 |
+
if (!charset) charset = CHARACTERS.lowercase + CHARACTERS.numbers;
|
| 154 |
+
result = generateRandomString(parseInt(length), charset);
|
| 155 |
+
break;
|
| 156 |
+
|
| 157 |
+
case 'uuid':
|
| 158 |
+
result = crypto.randomUUID();
|
| 159 |
+
break;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
res.json({
|
| 163 |
+
success: true,
|
| 164 |
+
data: {
|
| 165 |
+
type,
|
| 166 |
+
result,
|
| 167 |
+
length: result.length,
|
| 168 |
+
word_count: result.split(' ').length,
|
| 169 |
+
generated_at: new Date().toISOString(),
|
| 170 |
+
parameters: {
|
| 171 |
+
type,
|
| 172 |
+
count: parseInt(count),
|
| 173 |
+
length: parseInt(length),
|
| 174 |
+
wordType,
|
| 175 |
+
includeNumbers: includeNumbers === 'true',
|
| 176 |
+
includeUppercase: includeUppercase === 'true',
|
| 177 |
+
includeLowercase: includeLowercase === 'true',
|
| 178 |
+
includeSymbols: includeSymbols === 'true'
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
});
|
| 182 |
+
|
| 183 |
+
} catch (error) {
|
| 184 |
+
res.status(500).json({
|
| 185 |
+
success: false,
|
| 186 |
+
error: error.message
|
| 187 |
+
});
|
| 188 |
+
}
|
| 189 |
+
};
|
| 190 |
+
|
| 191 |
+
module.exports = {
|
| 192 |
+
name: 'Random Text Generator',
|
| 193 |
+
description: 'Generate random text, words, sentences, passwords, and UUIDs',
|
| 194 |
+
type: 'GET',
|
| 195 |
+
routes: ['api/tools/random/text'],
|
| 196 |
+
tags: ['utility', 'random', 'generator', 'text'],
|
| 197 |
+
parameters: ['type', 'count', 'length', 'wordType', 'includeNumbers', 'includeUppercase', 'includeLowercase', 'includeSymbols'],
|
| 198 |
+
enabled: true,
|
| 199 |
+
main: ['tools'],
|
| 200 |
+
handler
|
| 201 |
+
};
|
plugins/removebg.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function removebg(img_url) {
|
| 4 |
+
const uploadResponse = await axios.get('https://aibackgroundremover.org/api/get-upload-url');
|
| 5 |
+
const { uploadUrl, publicUrl } = uploadResponse.data;
|
| 6 |
+
|
| 7 |
+
const imageResponse = await axios.get(img_url, { responseType: 'arraybuffer' });
|
| 8 |
+
|
| 9 |
+
await axios.put(uploadUrl, imageResponse.data, {
|
| 10 |
+
headers: {
|
| 11 |
+
'Content-Type': 'image/png',
|
| 12 |
+
'Referer': 'https://aibackgroundremover.org/?utm_source=chatgpt.com'
|
| 13 |
+
}
|
| 14 |
+
});
|
| 15 |
+
|
| 16 |
+
const removeBgResponse = await axios.post('https://aibackgroundremover.org/api/remove-bg', {
|
| 17 |
+
image: publicUrl
|
| 18 |
+
}, {
|
| 19 |
+
headers: {
|
| 20 |
+
'Content-Type': 'application/json',
|
| 21 |
+
'Referer': 'https://aibackgroundremover.org/?utm_source=chatgpt.com'
|
| 22 |
+
}
|
| 23 |
+
});
|
| 24 |
+
|
| 25 |
+
const { id } = removeBgResponse.data;
|
| 26 |
+
|
| 27 |
+
while (true) {
|
| 28 |
+
const statusResponse = await axios.get(`https://aibackgroundremover.org/api/check-status?id=${id}`, {
|
| 29 |
+
headers: {
|
| 30 |
+
'Referer': 'https://aibackgroundremover.org/?utm_source=chatgpt.com'
|
| 31 |
+
}
|
| 32 |
+
});
|
| 33 |
+
|
| 34 |
+
const { status, output, error } = statusResponse.data;
|
| 35 |
+
|
| 36 |
+
if (status === 'succeeded') {
|
| 37 |
+
return output;
|
| 38 |
+
} else if (status === 'failed') {
|
| 39 |
+
throw new Error(error || 'Background removal failed');
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
const handler = async (req, res) => {
|
| 47 |
+
try {
|
| 48 |
+
const { url } = req.query;
|
| 49 |
+
|
| 50 |
+
if (!url) {
|
| 51 |
+
return res.status(400).json({
|
| 52 |
+
success: false,
|
| 53 |
+
error: 'Missing required parameter: url'
|
| 54 |
+
});
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
const result = await removebg(url);
|
| 58 |
+
|
| 59 |
+
res.json({
|
| 60 |
+
success: true,
|
| 61 |
+
data: {
|
| 62 |
+
original_url: url,
|
| 63 |
+
output_url: result
|
| 64 |
+
}
|
| 65 |
+
});
|
| 66 |
+
|
| 67 |
+
} catch (error) {
|
| 68 |
+
res.status(500).json({
|
| 69 |
+
success: false,
|
| 70 |
+
error: error.message
|
| 71 |
+
});
|
| 72 |
+
}
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
module.exports = {
|
| 76 |
+
name: 'Background Remover',
|
| 77 |
+
description: 'Remove background from images using AI',
|
| 78 |
+
type: 'GET',
|
| 79 |
+
routes: ['api/tools/removebg'],
|
| 80 |
+
tags: ['image', 'ai', 'background'],
|
| 81 |
+
parameters: ['url', 'key'],
|
| 82 |
+
enabled: true,
|
| 83 |
+
main: ['tools'],
|
| 84 |
+
handler
|
| 85 |
+
};
|
plugins/sc.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { soundcloud } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { url } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!url) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: url'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await soundcloud(url);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
data: result.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'SoundCloud DL',
|
| 31 |
+
description: 'Download Soundcloud Music from our server',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/download/soundcloud'],
|
| 34 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 35 |
+
parameters: ['url', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['Downloader'],
|
| 38 |
+
handler
|
| 39 |
+
}
|
plugins/sora2-img2vid.js
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const dns = require('dns').promises;
|
| 3 |
+
|
| 4 |
+
const PROXY_URL = 'https://proxy-sigma-roan.vercel.app/api/proxy';
|
| 5 |
+
|
| 6 |
+
dns.setServers(['1.1.1.1', '8.8.8.8', '8.8.4.4']);
|
| 7 |
+
|
| 8 |
+
function generateUniqueId() {
|
| 9 |
+
return Array.from({ length: 32 }, () =>
|
| 10 |
+
Math.floor(Math.random() * 16).toString(16)
|
| 11 |
+
).join('');
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
function generatePassword() {
|
| 15 |
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| 16 |
+
let password = '';
|
| 17 |
+
for (let i = 0; i < 12; i++) {
|
| 18 |
+
password += chars.charAt(Math.floor(Math.random() * chars.length));
|
| 19 |
+
}
|
| 20 |
+
return password;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
function randomDelay(min = 1000, max = 3000) {
|
| 24 |
+
const delay = Math.floor(Math.random() * (max - min + 1)) + min;
|
| 25 |
+
return new Promise(resolve => setTimeout(resolve, delay));
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
function generateRandomIP() {
|
| 29 |
+
return `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
async function proxyRequest(url, options = {}) {
|
| 33 |
+
const targetPath = url.startsWith('http') ? url : url;
|
| 34 |
+
const fakeIP = generateRandomIP();
|
| 35 |
+
|
| 36 |
+
const headers = {
|
| 37 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 38 |
+
'Accept': 'application/json, text/plain, */*',
|
| 39 |
+
'X-Forwarded-For': fakeIP,
|
| 40 |
+
'X-Real-IP': fakeIP,
|
| 41 |
+
'X-Client-IP': fakeIP,
|
| 42 |
+
...(options.headers || {})
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
await randomDelay(500, 1500);
|
| 46 |
+
|
| 47 |
+
const axiosConfig = {
|
| 48 |
+
method: options.method || 'GET',
|
| 49 |
+
headers: headers,
|
| 50 |
+
timeout: 30000,
|
| 51 |
+
params: { url: targetPath },
|
| 52 |
+
validateStatus: (status) => status >= 200 && status < 600
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
if (options.data && (options.method === 'POST' || options.method === 'PUT')) {
|
| 56 |
+
axiosConfig.data = options.data;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
let lastError = null;
|
| 60 |
+
|
| 61 |
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
| 62 |
+
try {
|
| 63 |
+
axiosConfig.url = PROXY_URL;
|
| 64 |
+
const response = await axios(axiosConfig);
|
| 65 |
+
|
| 66 |
+
console.log(`[Proxy] Status: ${response.status}, URL: ${targetPath}`);
|
| 67 |
+
|
| 68 |
+
if (response.status === 500) {
|
| 69 |
+
console.error('[Proxy] 500 Error Details:', JSON.stringify(response.data));
|
| 70 |
+
throw new Error(`Proxy server error: ${JSON.stringify(response.data)}`);
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
if (response.status === 403) {
|
| 74 |
+
await randomDelay(3000, 5000);
|
| 75 |
+
throw new Error('API Bylo returned 403 Forbidden');
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
if (response.status === 429) {
|
| 79 |
+
await randomDelay(5000, 10000);
|
| 80 |
+
if (attempt < 3) continue;
|
| 81 |
+
throw new Error('Rate limit exceeded');
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
if (response.status >= 200 && response.status < 300) {
|
| 85 |
+
if (!response.data) throw new Error('Empty response from proxy');
|
| 86 |
+
return response;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
if (response.status >= 400) {
|
| 90 |
+
const errorMsg = response.data?.msg || response.data?.message || 'Unknown error';
|
| 91 |
+
throw new Error(`API error (${response.status}): ${errorMsg}`);
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
if (attempt < 3) await randomDelay(2000, 4000);
|
| 95 |
+
|
| 96 |
+
} catch (error) {
|
| 97 |
+
console.error('[Proxy] Request failed:', {
|
| 98 |
+
url: targetPath,
|
| 99 |
+
status: error.response?.status,
|
| 100 |
+
data: error.response?.data,
|
| 101 |
+
message: error.message
|
| 102 |
+
});
|
| 103 |
+
lastError = error;
|
| 104 |
+
if (attempt < 3) {
|
| 105 |
+
const waitTime = 3000 * attempt;
|
| 106 |
+
await randomDelay(waitTime, waitTime + 2000);
|
| 107 |
+
}
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
throw new Error(`Proxy request failed after 3 attempts: ${lastError?.message || 'Unknown error'}`);
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
async function createTempEmail() {
|
| 115 |
+
const { data } = await axios.post('https://api.internal.temp-mail.io/api/v3/email/new', {
|
| 116 |
+
min_name_length: 10,
|
| 117 |
+
max_name_length: 10
|
| 118 |
+
}, {
|
| 119 |
+
headers: {
|
| 120 |
+
'Content-Type': 'application/json',
|
| 121 |
+
'Application-Name': 'web',
|
| 122 |
+
'Application-Version': '4.0.0',
|
| 123 |
+
'X-CORS-Header': 'iaWg3pchvFx48fY'
|
| 124 |
+
},
|
| 125 |
+
timeout: 15000
|
| 126 |
+
});
|
| 127 |
+
return data;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
async function getHcaptchaToken() {
|
| 131 |
+
const { data } = await axios.get(
|
| 132 |
+
'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',
|
| 133 |
+
{ timeout: 15000 }
|
| 134 |
+
);
|
| 135 |
+
|
| 136 |
+
if (!data.success) throw new Error('Failed to get hCaptcha token');
|
| 137 |
+
return data.data.result.token;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
async function sendVerificationEmail(email) {
|
| 141 |
+
await randomDelay(1000, 2000);
|
| 142 |
+
const hcaptchaToken = await getHcaptchaToken();
|
| 143 |
+
const encodedEmail = encodeURIComponent(email);
|
| 144 |
+
await randomDelay(500, 1000);
|
| 145 |
+
|
| 146 |
+
const { data } = await proxyRequest(
|
| 147 |
+
`/api/auth/send-captcha?email=${encodedEmail}&type=register`,
|
| 148 |
+
{
|
| 149 |
+
method: 'GET',
|
| 150 |
+
headers: {
|
| 151 |
+
'Accept': 'application/json, text/plain, */*',
|
| 152 |
+
'hcaptcha-token': hcaptchaToken,
|
| 153 |
+
'uniqueId': generateUniqueId()
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
);
|
| 157 |
+
|
| 158 |
+
if (data.code !== 200) {
|
| 159 |
+
throw new Error(`Failed to send verification email: ${data.msg || 'Unknown error'}`);
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
await randomDelay(3000, 5000);
|
| 163 |
+
return true;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
async function getVerificationCode(email) {
|
| 167 |
+
let attempts = 0;
|
| 168 |
+
const maxAttempts = 30;
|
| 169 |
+
|
| 170 |
+
while (attempts < maxAttempts) {
|
| 171 |
+
try {
|
| 172 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 173 |
+
|
| 174 |
+
const { data } = await axios.get(
|
| 175 |
+
`https://api.internal.temp-mail.io/api/v3/email/${email}/messages`,
|
| 176 |
+
{
|
| 177 |
+
headers: {
|
| 178 |
+
'Content-Type': 'application/json',
|
| 179 |
+
'Application-Name': 'web',
|
| 180 |
+
'Application-Version': '4.0.0',
|
| 181 |
+
'X-CORS-Header': 'iaWg3pchvFx48fY'
|
| 182 |
+
},
|
| 183 |
+
timeout: 10000
|
| 184 |
+
}
|
| 185 |
+
);
|
| 186 |
+
|
| 187 |
+
if (data.length > 0) {
|
| 188 |
+
const bodyText = data[0].body_text;
|
| 189 |
+
const codeMatch = bodyText.match(/Verification Code:\s*(\d{6})/);
|
| 190 |
+
if (codeMatch) return codeMatch[1];
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
attempts++;
|
| 194 |
+
} catch (error) {
|
| 195 |
+
attempts++;
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
throw new Error('Verification code not received after 30 attempts');
|
| 200 |
+
}
|
| 201 |
+
|
| 202 |
+
async function registerAccount(email, password, verificationCode) {
|
| 203 |
+
const { data } = await proxyRequest('/api/auth/register', {
|
| 204 |
+
method: 'POST',
|
| 205 |
+
headers: {
|
| 206 |
+
'Accept': 'application/json, text/plain, */*',
|
| 207 |
+
'Content-Type': 'application/json',
|
| 208 |
+
'uniqueId': generateUniqueId()
|
| 209 |
+
},
|
| 210 |
+
data: {
|
| 211 |
+
email: email,
|
| 212 |
+
password: password,
|
| 213 |
+
confirmPassword: password,
|
| 214 |
+
verificationCode: verificationCode,
|
| 215 |
+
referDomain: ''
|
| 216 |
+
}
|
| 217 |
+
});
|
| 218 |
+
|
| 219 |
+
if (data.code !== 200) {
|
| 220 |
+
throw new Error(`Registration failed: ${data.msg || 'Unknown error'}`);
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
return data.data.token;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
async function createVideoFromImage(prompt, imageUrl, ratio, duration, authToken, email) {
|
| 227 |
+
await randomDelay(2000, 3000);
|
| 228 |
+
|
| 229 |
+
const payloadVariants = [
|
| 230 |
+
{
|
| 231 |
+
prompt: prompt,
|
| 232 |
+
channel: 'SORA2',
|
| 233 |
+
pageId: 536,
|
| 234 |
+
source: 'bylo.ai',
|
| 235 |
+
watermarkFlag: false,
|
| 236 |
+
privateFlag: false,
|
| 237 |
+
isTemp: true,
|
| 238 |
+
model: 'sora_video2',
|
| 239 |
+
videoType: 'image-to-video',
|
| 240 |
+
duration: duration.toString(),
|
| 241 |
+
aspectRatio: ratio,
|
| 242 |
+
imageUrls: [imageUrl],
|
| 243 |
+
email: email
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
prompt: prompt,
|
| 247 |
+
channel: 'SORA2',
|
| 248 |
+
pageId: 536,
|
| 249 |
+
source: 'bylo.ai',
|
| 250 |
+
watermarkFlag: false,
|
| 251 |
+
privateFlag: false,
|
| 252 |
+
isTemp: true,
|
| 253 |
+
model: 'sora_video2',
|
| 254 |
+
videoType: 'image-to-video',
|
| 255 |
+
duration: duration.toString(),
|
| 256 |
+
aspectRatio: ratio,
|
| 257 |
+
imageUrl: imageUrl,
|
| 258 |
+
email: email
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
prompt: prompt,
|
| 262 |
+
channel: 'SORA2',
|
| 263 |
+
pageId: 536,
|
| 264 |
+
source: 'bylo.ai',
|
| 265 |
+
watermarkFlag: false,
|
| 266 |
+
privateFlag: false,
|
| 267 |
+
isTemp: true,
|
| 268 |
+
model: 'sora_video2',
|
| 269 |
+
videoType: 'image-to-video',
|
| 270 |
+
duration: duration.toString(),
|
| 271 |
+
aspectRatio: ratio,
|
| 272 |
+
image: imageUrl,
|
| 273 |
+
email: email
|
| 274 |
+
}
|
| 275 |
+
];
|
| 276 |
+
|
| 277 |
+
let lastError = null;
|
| 278 |
+
|
| 279 |
+
for (let i = 0; i < payloadVariants.length; i++) {
|
| 280 |
+
try {
|
| 281 |
+
console.log(`[DEBUG] Trying payload variant ${i + 1}:`, JSON.stringify(payloadVariants[i], null, 2));
|
| 282 |
+
|
| 283 |
+
const { data } = await proxyRequest('/aimodels/api/v1/ai/video/create', {
|
| 284 |
+
method: 'POST',
|
| 285 |
+
headers: {
|
| 286 |
+
'Content-Type': 'application/json',
|
| 287 |
+
'uniqueid': generateUniqueId(),
|
| 288 |
+
'verify': '',
|
| 289 |
+
'authorization': authToken
|
| 290 |
+
},
|
| 291 |
+
data: payloadVariants[i]
|
| 292 |
+
});
|
| 293 |
+
|
| 294 |
+
console.log('[DEBUG] Response:', JSON.stringify(data, null, 2));
|
| 295 |
+
|
| 296 |
+
if (data.code === 200) {
|
| 297 |
+
return data.data;
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
lastError = new Error(`Failed with code ${data.code}: ${data.message || data.msg || 'Unknown error'}`);
|
| 301 |
+
|
| 302 |
+
} catch (error) {
|
| 303 |
+
console.error(`[DEBUG] Payload variant ${i + 1} failed:`, error.message);
|
| 304 |
+
lastError = error;
|
| 305 |
+
}
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
throw lastError || new Error('All payload variants failed');
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
async function getTaskStatus(taskId, authToken) {
|
| 312 |
+
const { data } = await proxyRequest(
|
| 313 |
+
`/aimodels/api/v1/ai/${taskId}?channel=SORA2`,
|
| 314 |
+
{
|
| 315 |
+
method: 'GET',
|
| 316 |
+
headers: {
|
| 317 |
+
'Content-Type': 'application/json',
|
| 318 |
+
'authorization': authToken
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
);
|
| 322 |
+
|
| 323 |
+
if (!data || !data.data) {
|
| 324 |
+
throw new Error('Invalid response from task status API');
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
return data.data;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
async function waitForVideoCompletion(taskId, authToken) {
|
| 331 |
+
let attempts = 0;
|
| 332 |
+
const maxAttempts = 120;
|
| 333 |
+
|
| 334 |
+
while (attempts < maxAttempts) {
|
| 335 |
+
await randomDelay(5000, 7000);
|
| 336 |
+
const taskData = await getTaskStatus(taskId, authToken);
|
| 337 |
+
|
| 338 |
+
console.log(`[Progress] Attempt ${attempts + 1}/${maxAttempts} - State: ${taskData.state}`);
|
| 339 |
+
|
| 340 |
+
if (taskData.state === 1 && taskData.completeData) {
|
| 341 |
+
const completeData = JSON.parse(taskData.completeData);
|
| 342 |
+
return completeData.data.result_urls[0];
|
| 343 |
+
}
|
| 344 |
+
|
| 345 |
+
if (taskData.failMsg) {
|
| 346 |
+
throw new Error(`Video generation failed: ${taskData.failMsg}`);
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
attempts++;
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
throw new Error('Video generation timeout after 10 minutes');
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
async function sora2ImageToVideo(prompt, imageUrl, ratio = 'portrait', duration = 10) {
|
| 356 |
+
console.log('[1/6] Creating temporary email...');
|
| 357 |
+
const tempMail = await createTempEmail();
|
| 358 |
+
const email = tempMail.email;
|
| 359 |
+
const password = generatePassword();
|
| 360 |
+
console.log(`[Email] ${email}`);
|
| 361 |
+
|
| 362 |
+
console.log('[2/6] Sending verification email...');
|
| 363 |
+
await sendVerificationEmail(email);
|
| 364 |
+
|
| 365 |
+
console.log('[3/6] Waiting for verification code...');
|
| 366 |
+
const verificationCode = await getVerificationCode(email);
|
| 367 |
+
console.log(`[Code] ${verificationCode}`);
|
| 368 |
+
|
| 369 |
+
console.log('[4/6] Registering account...');
|
| 370 |
+
const authToken = await registerAccount(email, password, verificationCode);
|
| 371 |
+
console.log('[Auth] Token received');
|
| 372 |
+
|
| 373 |
+
console.log('[5/6] Creating video task...');
|
| 374 |
+
const taskId = await createVideoFromImage(prompt, imageUrl, ratio, duration, authToken, email);
|
| 375 |
+
console.log(`[Task ID] ${taskId}`);
|
| 376 |
+
|
| 377 |
+
console.log('[6/6] Waiting for video completion...');
|
| 378 |
+
const videoUrl = await waitForVideoCompletion(taskId, authToken);
|
| 379 |
+
console.log(`[Video URL] ${videoUrl}`);
|
| 380 |
+
|
| 381 |
+
return {
|
| 382 |
+
success: true,
|
| 383 |
+
email: email,
|
| 384 |
+
password: password,
|
| 385 |
+
videoUrl: videoUrl,
|
| 386 |
+
taskId: taskId
|
| 387 |
+
};
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
const handler = async (req, res) => {
|
| 391 |
+
const startTime = Date.now();
|
| 392 |
+
|
| 393 |
+
try {
|
| 394 |
+
const { prompt, imageUrl, key, ratio = 'portrait' } = req.query;
|
| 395 |
+
|
| 396 |
+
if (!prompt) {
|
| 397 |
+
return res.status(400).json({
|
| 398 |
+
author: 'Herza',
|
| 399 |
+
success: false,
|
| 400 |
+
msg: 'Missing required parameter: prompt',
|
| 401 |
+
usage: '/api/AI/sora2img2video?prompt=your_prompt&imageUrl=image_url&ratio=portrait&key=your_key'
|
| 402 |
+
});
|
| 403 |
+
}
|
| 404 |
+
|
| 405 |
+
if (!imageUrl) {
|
| 406 |
+
return res.status(400).json({
|
| 407 |
+
author: 'Herza',
|
| 408 |
+
success: false,
|
| 409 |
+
msg: 'Missing required parameter: imageUrl'
|
| 410 |
+
});
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
if (!key) {
|
| 414 |
+
return res.status(400).json({
|
| 415 |
+
author: 'Herza',
|
| 416 |
+
success: false,
|
| 417 |
+
msg: 'Missing required parameter: key'
|
| 418 |
+
});
|
| 419 |
+
}
|
| 420 |
+
|
| 421 |
+
if (!['portrait', 'landscape'].includes(ratio)) {
|
| 422 |
+
return res.status(400).json({
|
| 423 |
+
author: 'Herza',
|
| 424 |
+
success: false,
|
| 425 |
+
msg: 'Invalid ratio. Use: portrait or landscape'
|
| 426 |
+
});
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
console.log(`\n${'='.repeat(60)}`);
|
| 430 |
+
console.log('NEW IMAGE TO VIDEO REQUEST RECEIVED');
|
| 431 |
+
console.log(`Prompt: ${prompt}`);
|
| 432 |
+
console.log(`Image URL: ${imageUrl}`);
|
| 433 |
+
console.log(`Ratio: ${ratio}`);
|
| 434 |
+
console.log(`${'='.repeat(60)}\n`);
|
| 435 |
+
|
| 436 |
+
const result = await sora2ImageToVideo(prompt, imageUrl, ratio, 10);
|
| 437 |
+
|
| 438 |
+
const processingTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 439 |
+
|
| 440 |
+
console.log(`\n${'='.repeat(60)}`);
|
| 441 |
+
console.log('REQUEST COMPLETED');
|
| 442 |
+
console.log(`Duration: ${processingTime}s`);
|
| 443 |
+
console.log(`${'='.repeat(60)}\n`);
|
| 444 |
+
|
| 445 |
+
res.json({
|
| 446 |
+
author: 'Herza',
|
| 447 |
+
success: true,
|
| 448 |
+
data: {
|
| 449 |
+
model: 'sora-video2',
|
| 450 |
+
prompt: prompt,
|
| 451 |
+
imageUrl: imageUrl,
|
| 452 |
+
ratio: ratio,
|
| 453 |
+
duration: '10s',
|
| 454 |
+
videoUrl: result.videoUrl,
|
| 455 |
+
taskId: result.taskId,
|
| 456 |
+
account: {
|
| 457 |
+
email: result.email,
|
| 458 |
+
password: result.password
|
| 459 |
+
},
|
| 460 |
+
processingTime: `${processingTime}s`
|
| 461 |
+
}
|
| 462 |
+
});
|
| 463 |
+
} catch (error) {
|
| 464 |
+
console.error('\n❌ ERROR:', error.message);
|
| 465 |
+
console.error('Stack:', error.stack);
|
| 466 |
+
|
| 467 |
+
const processingTime = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 468 |
+
|
| 469 |
+
const errorMessage = error.response?.data?.error ||
|
| 470 |
+
error.response?.data?.message ||
|
| 471 |
+
error.message ||
|
| 472 |
+
'Unknown error occurred';
|
| 473 |
+
|
| 474 |
+
res.status(error.response?.status || 500).json({
|
| 475 |
+
author: 'Herza',
|
| 476 |
+
success: false,
|
| 477 |
+
msg: errorMessage,
|
| 478 |
+
processingTime: `${processingTime}s`,
|
| 479 |
+
error: {
|
| 480 |
+
code: error.code || 'UNKNOWN',
|
| 481 |
+
statusCode: error.response?.status,
|
| 482 |
+
details: error.response?.data || error.message
|
| 483 |
+
}
|
| 484 |
+
});
|
| 485 |
+
}
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
module.exports = {
|
| 489 |
+
name: 'Sora2 Image to Video Generator',
|
| 490 |
+
description: 'Generate videos from images using Sora2 AI model from Bylo.ai via Vercel Proxy',
|
| 491 |
+
type: 'GET',
|
| 492 |
+
routes: ['api/AI/sora2img2video'],
|
| 493 |
+
tags: ['AI', 'Sora', 'OpenAI', 'Video', 'Image to Video'],
|
| 494 |
+
parameters: ['prompt', 'imageUrl', 'ratio', 'key'],
|
| 495 |
+
enabled: true,
|
| 496 |
+
main: ['AI'],
|
| 497 |
+
limit: 13,
|
| 498 |
+
handler
|
| 499 |
+
};
|
plugins/sora2.js
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const dns = require('dns').promises;
|
| 3 |
+
|
| 4 |
+
const PROXY_URL = 'https://proxy-sigma-roan.vercel.app/api/proxy';
|
| 5 |
+
|
| 6 |
+
dns.setServers([
|
| 7 |
+
'1.1.1.1',
|
| 8 |
+
'8.8.8.8',
|
| 9 |
+
'8.8.4.4'
|
| 10 |
+
]);
|
| 11 |
+
|
| 12 |
+
function generateUniqueId() {
|
| 13 |
+
return Array.from({ length: 32 }, () =>
|
| 14 |
+
Math.floor(Math.random() * 16).toString(16)
|
| 15 |
+
).join('');
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
function generatePassword() {
|
| 19 |
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
| 20 |
+
let password = '';
|
| 21 |
+
for (let i = 0; i < 12; i++) {
|
| 22 |
+
password += chars.charAt(Math.floor(Math.random() * chars.length));
|
| 23 |
+
}
|
| 24 |
+
return password;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
function randomDelay(min = 1000, max = 3000) {
|
| 28 |
+
const delay = Math.floor(Math.random() * (max - min + 1)) + min;
|
| 29 |
+
return new Promise(resolve => setTimeout(resolve, delay));
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
function generateRandomIP() {
|
| 33 |
+
return `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`;
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
async function proxyRequest(url, options = {}) {
|
| 37 |
+
const targetPath = url.startsWith('http') ? url : url;
|
| 38 |
+
|
| 39 |
+
const fakeIP = generateRandomIP();
|
| 40 |
+
|
| 41 |
+
const headers = {
|
| 42 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 43 |
+
'Accept': 'application/json, text/plain, */*',
|
| 44 |
+
'X-Forwarded-For': fakeIP,
|
| 45 |
+
'X-Real-IP': fakeIP,
|
| 46 |
+
'X-Client-IP': fakeIP,
|
| 47 |
+
...(options.headers || {})
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
await randomDelay(500, 1500);
|
| 51 |
+
|
| 52 |
+
const axiosConfig = {
|
| 53 |
+
method: options.method || 'GET',
|
| 54 |
+
headers: headers,
|
| 55 |
+
timeout: 30000,
|
| 56 |
+
params: {
|
| 57 |
+
url: targetPath
|
| 58 |
+
},
|
| 59 |
+
validateStatus: function (status) {
|
| 60 |
+
return status >= 200 && status < 600;
|
| 61 |
+
}
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
if (options.data && (options.method === 'POST' || options.method === 'PUT')) {
|
| 65 |
+
axiosConfig.data = options.data;
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
let lastError = null;
|
| 69 |
+
|
| 70 |
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
| 71 |
+
try {
|
| 72 |
+
axiosConfig.url = PROXY_URL;
|
| 73 |
+
console.log(`Attempt ${attempt}: ${PROXY_URL}?url=${targetPath}`);
|
| 74 |
+
|
| 75 |
+
const response = await axios(axiosConfig);
|
| 76 |
+
|
| 77 |
+
console.log(`Attempt ${attempt} got status ${response.status}`);
|
| 78 |
+
console.log(`Response data:`, JSON.stringify(response.data).substring(0, 200));
|
| 79 |
+
|
| 80 |
+
if (response.status === 403) {
|
| 81 |
+
console.log('Got 403, waiting longer before retry...');
|
| 82 |
+
await randomDelay(3000, 5000);
|
| 83 |
+
throw new Error('API Bylo returned 403 Forbidden - possible rate limit or IP block');
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
if (response.status === 429) {
|
| 87 |
+
console.log('Got 429 Too Many Requests, waiting...');
|
| 88 |
+
await randomDelay(5000, 10000);
|
| 89 |
+
if (attempt < 3) continue;
|
| 90 |
+
throw new Error('Rate limit exceeded');
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
if (response.status >= 200 && response.status < 300) {
|
| 94 |
+
if (!response.data) {
|
| 95 |
+
throw new Error('Empty response from proxy');
|
| 96 |
+
}
|
| 97 |
+
return response;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
if (response.status >= 400) {
|
| 101 |
+
const errorMsg = response.data?.msg || response.data?.message || response.data?.error || 'Unknown error';
|
| 102 |
+
throw new Error(`API error (${response.status}): ${errorMsg}`);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
if (attempt < 3) {
|
| 106 |
+
await randomDelay(2000, 4000);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
} catch (error) {
|
| 110 |
+
lastError = error;
|
| 111 |
+
console.error(`Attempt ${attempt} failed:`, error.message);
|
| 112 |
+
|
| 113 |
+
if (error.response) {
|
| 114 |
+
console.error(`Response status: ${error.response.status}`);
|
| 115 |
+
console.error(`Response data:`, error.response.data);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
if (attempt < 3) {
|
| 119 |
+
const waitTime = 3000 * attempt;
|
| 120 |
+
console.log(`Retrying in ${waitTime/1000} seconds...`);
|
| 121 |
+
await randomDelay(waitTime, waitTime + 2000);
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
throw new Error(`Proxy request failed after 3 attempts: ${lastError?.message || 'Unknown error'}`);
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
async function createTempEmail() {
|
| 130 |
+
console.log('Creating temporary email...');
|
| 131 |
+
const { data } = await axios.post('https://api.internal.temp-mail.io/api/v3/email/new', {
|
| 132 |
+
min_name_length: 10,
|
| 133 |
+
max_name_length: 10
|
| 134 |
+
}, {
|
| 135 |
+
headers: {
|
| 136 |
+
'Content-Type': 'application/json',
|
| 137 |
+
'Application-Name': 'web',
|
| 138 |
+
'Application-Version': '4.0.0',
|
| 139 |
+
'X-CORS-Header': 'iaWg3pchvFx48fY'
|
| 140 |
+
},
|
| 141 |
+
timeout: 15000
|
| 142 |
+
});
|
| 143 |
+
|
| 144 |
+
console.log(`Email created: ${data.email}`);
|
| 145 |
+
return data;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
async function getHcaptchaToken() {
|
| 149 |
+
console.log('Getting hCaptcha token...');
|
| 150 |
+
const { data } = await axios.get(
|
| 151 |
+
'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',
|
| 152 |
+
{
|
| 153 |
+
timeout: 15000
|
| 154 |
+
}
|
| 155 |
+
);
|
| 156 |
+
|
| 157 |
+
if (!data.success) {
|
| 158 |
+
throw new Error('Failed to get hCaptcha token');
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
console.log('hCaptcha token obtained');
|
| 162 |
+
return data.data.result.token;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
async function sendVerificationEmail(email) {
|
| 166 |
+
console.log(`Sending verification email to ${email}...`);
|
| 167 |
+
|
| 168 |
+
await randomDelay(1000, 2000);
|
| 169 |
+
|
| 170 |
+
const hcaptchaToken = await getHcaptchaToken();
|
| 171 |
+
const encodedEmail = encodeURIComponent(email);
|
| 172 |
+
|
| 173 |
+
await randomDelay(500, 1000);
|
| 174 |
+
|
| 175 |
+
const { data } = await proxyRequest(
|
| 176 |
+
`/api/auth/send-captcha?email=${encodedEmail}&type=register`,
|
| 177 |
+
{
|
| 178 |
+
method: 'GET',
|
| 179 |
+
headers: {
|
| 180 |
+
'Accept': 'application/json, text/plain, */*',
|
| 181 |
+
'hcaptcha-token': hcaptchaToken,
|
| 182 |
+
'uniqueId': generateUniqueId()
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
);
|
| 186 |
+
|
| 187 |
+
if (data.code !== 200) {
|
| 188 |
+
throw new Error(`Failed to send verification email: ${data.msg || 'Unknown error'}`);
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
console.log('Verification email sent successfully');
|
| 192 |
+
await randomDelay(3000, 5000);
|
| 193 |
+
return true;
|
| 194 |
+
}
|
| 195 |
+
|
| 196 |
+
async function getVerificationCode(email) {
|
| 197 |
+
console.log('Waiting for verification code...');
|
| 198 |
+
let attempts = 0;
|
| 199 |
+
const maxAttempts = 30;
|
| 200 |
+
|
| 201 |
+
while (attempts < maxAttempts) {
|
| 202 |
+
try {
|
| 203 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 204 |
+
|
| 205 |
+
const { data } = await axios.get(
|
| 206 |
+
`https://api.internal.temp-mail.io/api/v3/email/${email}/messages`,
|
| 207 |
+
{
|
| 208 |
+
headers: {
|
| 209 |
+
'Content-Type': 'application/json',
|
| 210 |
+
'Application-Name': 'web',
|
| 211 |
+
'Application-Version': '4.0.0',
|
| 212 |
+
'X-CORS-Header': 'iaWg3pchvFx48fY'
|
| 213 |
+
},
|
| 214 |
+
timeout: 10000
|
| 215 |
+
}
|
| 216 |
+
);
|
| 217 |
+
|
| 218 |
+
if (data.length > 0) {
|
| 219 |
+
const bodyText = data[0].body_text;
|
| 220 |
+
const codeMatch = bodyText.match(/Verification Code:\s*(\d{6})/);
|
| 221 |
+
|
| 222 |
+
if (codeMatch) {
|
| 223 |
+
console.log(`Verification code received: ${codeMatch[1]}`);
|
| 224 |
+
return codeMatch[1];
|
| 225 |
+
}
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
attempts++;
|
| 229 |
+
console.log(`Checking for verification code... attempt ${attempts}/${maxAttempts}`);
|
| 230 |
+
} catch (error) {
|
| 231 |
+
console.log(`Email check attempt ${attempts} failed:`, error.message);
|
| 232 |
+
attempts++;
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
throw new Error('Verification code not received after 30 attempts');
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
async function registerAccount(email, password, verificationCode) {
|
| 240 |
+
console.log('Registering account...');
|
| 241 |
+
const { data } = await proxyRequest('/api/auth/register', {
|
| 242 |
+
method: 'POST',
|
| 243 |
+
headers: {
|
| 244 |
+
'Accept': 'application/json, text/plain, */*',
|
| 245 |
+
'Content-Type': 'application/json',
|
| 246 |
+
'uniqueId': generateUniqueId()
|
| 247 |
+
},
|
| 248 |
+
data: {
|
| 249 |
+
email: email,
|
| 250 |
+
password: password,
|
| 251 |
+
confirmPassword: password,
|
| 252 |
+
verificationCode: verificationCode,
|
| 253 |
+
referDomain: ''
|
| 254 |
+
}
|
| 255 |
+
});
|
| 256 |
+
|
| 257 |
+
if (data.code !== 200) {
|
| 258 |
+
throw new Error(`Registration failed: ${data.msg || 'Unknown error'}`);
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
console.log('Account registered successfully');
|
| 262 |
+
return data.data.token;
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
async function createVideo(prompt, ratio, authToken, email) {
|
| 266 |
+
console.log('Creating video task...');
|
| 267 |
+
await randomDelay(2000, 3000);
|
| 268 |
+
|
| 269 |
+
const { data } = await proxyRequest('/aimodels/api/v1/ai/video/create', {
|
| 270 |
+
method: 'POST',
|
| 271 |
+
headers: {
|
| 272 |
+
'Content-Type': 'application/json',
|
| 273 |
+
'uniqueid': generateUniqueId(),
|
| 274 |
+
'verify': '',
|
| 275 |
+
'authorization': authToken
|
| 276 |
+
},
|
| 277 |
+
data: {
|
| 278 |
+
prompt: prompt,
|
| 279 |
+
channel: 'SORA2',
|
| 280 |
+
pageId: 536,
|
| 281 |
+
source: 'bylo.ai',
|
| 282 |
+
watermarkFlag: false,
|
| 283 |
+
privateFlag: false,
|
| 284 |
+
isTemp: true,
|
| 285 |
+
model: 'sora_video2',
|
| 286 |
+
videoType: 'text-to-video',
|
| 287 |
+
duration: '10',
|
| 288 |
+
aspectRatio: ratio,
|
| 289 |
+
email: email
|
| 290 |
+
}
|
| 291 |
+
});
|
| 292 |
+
|
| 293 |
+
if (data.code !== 200) {
|
| 294 |
+
throw new Error(`Failed to create video: ${data.message || 'Unknown error'}`);
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
console.log(`Video task created with ID: ${data.data}`);
|
| 298 |
+
return data.data;
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
async function getTaskStatus(taskId, authToken) {
|
| 302 |
+
try {
|
| 303 |
+
const { data } = await proxyRequest(
|
| 304 |
+
`/aimodels/api/v1/ai/${taskId}?channel=SORA2`,
|
| 305 |
+
{
|
| 306 |
+
method: 'GET',
|
| 307 |
+
headers: {
|
| 308 |
+
'Content-Type': 'application/json',
|
| 309 |
+
'authorization': authToken
|
| 310 |
+
}
|
| 311 |
+
}
|
| 312 |
+
);
|
| 313 |
+
|
| 314 |
+
if (!data || !data.data) {
|
| 315 |
+
throw new Error('Invalid response from task status API');
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
return data.data;
|
| 319 |
+
} catch (error) {
|
| 320 |
+
console.error('Error getting task status:', error.message);
|
| 321 |
+
throw error;
|
| 322 |
+
}
|
| 323 |
+
}
|
| 324 |
+
|
| 325 |
+
async function waitForVideoCompletion(taskId, authToken) {
|
| 326 |
+
console.log('Waiting for video generation...');
|
| 327 |
+
let attempts = 0;
|
| 328 |
+
const maxAttempts = 120;
|
| 329 |
+
|
| 330 |
+
while (attempts < maxAttempts) {
|
| 331 |
+
await randomDelay(5000, 7000);
|
| 332 |
+
|
| 333 |
+
const taskData = await getTaskStatus(taskId, authToken);
|
| 334 |
+
|
| 335 |
+
console.log(`Video status check ${attempts + 1}/${maxAttempts} - State: ${taskData.state}`);
|
| 336 |
+
|
| 337 |
+
if (taskData.state === 1 && taskData.completeData) {
|
| 338 |
+
const completeData = JSON.parse(taskData.completeData);
|
| 339 |
+
console.log('Video generation completed!');
|
| 340 |
+
return completeData.data.result_urls[0];
|
| 341 |
+
}
|
| 342 |
+
|
| 343 |
+
if (taskData.failMsg) {
|
| 344 |
+
throw new Error(`Video generation failed: ${taskData.failMsg}`);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
attempts++;
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
throw new Error('Video generation timeout after 10 minutes');
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
async function sora2(prompt, ratio = 'portrait') {
|
| 354 |
+
console.log('=== Starting Sora2 Video Generation ===');
|
| 355 |
+
console.log(`Prompt: ${prompt}`);
|
| 356 |
+
console.log(`Ratio: ${ratio}`);
|
| 357 |
+
|
| 358 |
+
const tempMail = await createTempEmail();
|
| 359 |
+
const email = tempMail.email;
|
| 360 |
+
const password = generatePassword();
|
| 361 |
+
|
| 362 |
+
await sendVerificationEmail(email);
|
| 363 |
+
const verificationCode = await getVerificationCode(email);
|
| 364 |
+
const authToken = await registerAccount(email, password, verificationCode);
|
| 365 |
+
const taskId = await createVideo(prompt, ratio, authToken, email);
|
| 366 |
+
const videoUrl = await waitForVideoCompletion(taskId, authToken);
|
| 367 |
+
|
| 368 |
+
console.log('=== Video Generation Completed ===');
|
| 369 |
+
console.log(`Video URL: ${videoUrl}`);
|
| 370 |
+
|
| 371 |
+
return {
|
| 372 |
+
success: true,
|
| 373 |
+
email: email,
|
| 374 |
+
password: password,
|
| 375 |
+
videoUrl: videoUrl,
|
| 376 |
+
taskId: taskId
|
| 377 |
+
};
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
+
const handler = async (req, res) => {
|
| 381 |
+
const startTime = Date.now();
|
| 382 |
+
|
| 383 |
+
try {
|
| 384 |
+
const { prompt, key, ratio = 'portrait' } = req.query;
|
| 385 |
+
|
| 386 |
+
if (!prompt) {
|
| 387 |
+
return res.status(400).json({
|
| 388 |
+
author: 'Herza',
|
| 389 |
+
success: false,
|
| 390 |
+
msg: 'Missing required parameter: prompt',
|
| 391 |
+
usage: '/api/AI/sora2?prompt=your_prompt&ratio=portrait&key=your_key'
|
| 392 |
+
});
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
if (!key) {
|
| 396 |
+
return res.status(400).json({
|
| 397 |
+
author: 'Herza',
|
| 398 |
+
success: false,
|
| 399 |
+
msg: 'Missing required parameter: key'
|
| 400 |
+
});
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
if (!['portrait', 'landscape', 'square'].includes(ratio)) {
|
| 404 |
+
return res.status(400).json({
|
| 405 |
+
author: 'Herza',
|
| 406 |
+
success: false,
|
| 407 |
+
msg: 'Invalid ratio. Use: portrait, landscape, or square'
|
| 408 |
+
});
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
console.log(`\n${'='.repeat(60)}`);
|
| 412 |
+
console.log('NEW REQUEST RECEIVED');
|
| 413 |
+
console.log(`Prompt: ${prompt}`);
|
| 414 |
+
console.log(`Ratio: ${ratio}`);
|
| 415 |
+
console.log(`${'='.repeat(60)}\n`);
|
| 416 |
+
|
| 417 |
+
const result = await sora2(prompt, ratio);
|
| 418 |
+
|
| 419 |
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 420 |
+
|
| 421 |
+
console.log(`\n${'='.repeat(60)}`);
|
| 422 |
+
console.log('REQUEST COMPLETED');
|
| 423 |
+
console.log(`Duration: ${duration}s`);
|
| 424 |
+
console.log(`${'='.repeat(60)}\n`);
|
| 425 |
+
|
| 426 |
+
res.json({
|
| 427 |
+
author: 'Herza',
|
| 428 |
+
success: true,
|
| 429 |
+
data: {
|
| 430 |
+
model: 'sora-video2',
|
| 431 |
+
prompt: prompt,
|
| 432 |
+
ratio: ratio,
|
| 433 |
+
videoUrl: result.videoUrl,
|
| 434 |
+
taskId: result.taskId,
|
| 435 |
+
account: {
|
| 436 |
+
email: result.email,
|
| 437 |
+
password: result.password
|
| 438 |
+
},
|
| 439 |
+
processingTime: `${duration}s`
|
| 440 |
+
}
|
| 441 |
+
});
|
| 442 |
+
} catch (error) {
|
| 443 |
+
console.error('\n❌ ERROR:', error.message);
|
| 444 |
+
console.error('Stack:', error.stack);
|
| 445 |
+
|
| 446 |
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 447 |
+
|
| 448 |
+
res.status(500).json({
|
| 449 |
+
author: 'Herza',
|
| 450 |
+
success: false,
|
| 451 |
+
msg: error.message || 'Terjadi kesalahan saat generate video.',
|
| 452 |
+
processingTime: `${duration}s`,
|
| 453 |
+
error: {
|
| 454 |
+
code: error.code || 'UNKNOWN',
|
| 455 |
+
details: error.response?.data || null
|
| 456 |
+
}
|
| 457 |
+
});
|
| 458 |
+
}
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
module.exports = {
|
| 462 |
+
name: 'Sora2 Video Generator',
|
| 463 |
+
description: 'Generate videos using Sora2 AI model from Bylo.ai via Vercel Proxy',
|
| 464 |
+
type: 'GET',
|
| 465 |
+
routes: ['api/AI/sora2'],
|
| 466 |
+
tags: ['AI', 'Sora', 'OpenAI', 'Video'],
|
| 467 |
+
parameters: ['prompt', 'ratio', 'key'],
|
| 468 |
+
enabled: true,
|
| 469 |
+
main: ['AI'],
|
| 470 |
+
limit: 10,
|
| 471 |
+
handler
|
| 472 |
+
};
|
plugins/sora2nowm.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
async function videoGenerator(prompt) {
|
| 2 |
+
if (!prompt) return { error: "Prompt tidak boleh kosong" };
|
| 3 |
+
|
| 4 |
+
const videoId = `video_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
|
| 5 |
+
const apiUrl = "https://veo31.ai/api";
|
| 6 |
+
|
| 7 |
+
try {
|
| 8 |
+
const res = await fetch(`${apiUrl}/generate/stream`, {
|
| 9 |
+
method: "POST",
|
| 10 |
+
headers: { "Content-Type": "application/json" },
|
| 11 |
+
body: JSON.stringify({
|
| 12 |
+
prompt,
|
| 13 |
+
aspectRatio: "9:16",
|
| 14 |
+
videoId,
|
| 15 |
+
}),
|
| 16 |
+
});
|
| 17 |
+
|
| 18 |
+
const data = await res.json();
|
| 19 |
+
if (!data.success) return { status: "failed", error: "Error generating video", detail: data };
|
| 20 |
+
|
| 21 |
+
await new Promise((r) => setTimeout(r, 120000));
|
| 22 |
+
|
| 23 |
+
while (true) {
|
| 24 |
+
const check = await fetch(`${apiUrl}/webhook?videoId=${videoId}`);
|
| 25 |
+
const status = await check.json();
|
| 26 |
+
|
| 27 |
+
if (status.status === "completed") {
|
| 28 |
+
return {
|
| 29 |
+
status: "completed",
|
| 30 |
+
videoUrl: status.videoUrl,
|
| 31 |
+
videoId,
|
| 32 |
+
};
|
| 33 |
+
} else if (status.status === "failed") {
|
| 34 |
+
return {
|
| 35 |
+
status: "failed",
|
| 36 |
+
error: status.error || "unknown",
|
| 37 |
+
};
|
| 38 |
+
} else {
|
| 39 |
+
await new Promise((r) => setTimeout(r, 60000));
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
} catch (err) {
|
| 43 |
+
return { status: "error", error: err.message };
|
| 44 |
+
}
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
const handler = async (req, res) => {
|
| 48 |
+
const startTime = Date.now();
|
| 49 |
+
|
| 50 |
+
try {
|
| 51 |
+
const { prompt, key } = req.query;
|
| 52 |
+
|
| 53 |
+
if (!prompt) {
|
| 54 |
+
return res.status(400).json({
|
| 55 |
+
author: 'Herza',
|
| 56 |
+
success: false,
|
| 57 |
+
msg: 'Missing required parameter: prompt',
|
| 58 |
+
usage: '/api/AI/sora2nowm?prompt=your_prompt&key=your_key'
|
| 59 |
+
});
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
if (!key) {
|
| 63 |
+
return res.status(400).json({
|
| 64 |
+
author: 'Herza',
|
| 65 |
+
success: false,
|
| 66 |
+
msg: 'Missing required parameter: key'
|
| 67 |
+
});
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
console.log(`\n${'='.repeat(60)}`);
|
| 71 |
+
console.log('NEW REQUEST RECEIVED');
|
| 72 |
+
console.log(`Prompt: ${prompt}`);
|
| 73 |
+
console.log(`${'='.repeat(60)}\n`);
|
| 74 |
+
|
| 75 |
+
const result = await videoGenerator(prompt);
|
| 76 |
+
|
| 77 |
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 78 |
+
|
| 79 |
+
if (result.status === "completed") {
|
| 80 |
+
console.log(`\n${'='.repeat(60)}`);
|
| 81 |
+
console.log('REQUEST COMPLETED');
|
| 82 |
+
console.log(`Duration: ${duration}s`);
|
| 83 |
+
console.log(`${'='.repeat(60)}\n`);
|
| 84 |
+
|
| 85 |
+
res.json({
|
| 86 |
+
author: 'Herza',
|
| 87 |
+
success: true,
|
| 88 |
+
data: {
|
| 89 |
+
model: 'veo31-sora2',
|
| 90 |
+
prompt: prompt,
|
| 91 |
+
videoUrl: result.videoUrl,
|
| 92 |
+
videoId: result.videoId,
|
| 93 |
+
processingTime: `${duration}s`
|
| 94 |
+
}
|
| 95 |
+
});
|
| 96 |
+
} else {
|
| 97 |
+
throw new Error(result.error || 'Video generation failed');
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
} catch (error) {
|
| 101 |
+
console.error('\n❌ ERROR:', error.message);
|
| 102 |
+
console.error('Stack:', error.stack);
|
| 103 |
+
|
| 104 |
+
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
|
| 105 |
+
|
| 106 |
+
res.status(500).json({
|
| 107 |
+
author: 'Herza',
|
| 108 |
+
success: false,
|
| 109 |
+
msg: error.message || 'Terjadi kesalahan saat generate video.',
|
| 110 |
+
processingTime: `${duration}s`,
|
| 111 |
+
error: {
|
| 112 |
+
code: error.code || 'UNKNOWN',
|
| 113 |
+
details: error.response?.data || null
|
| 114 |
+
}
|
| 115 |
+
});
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
module.exports = {
|
| 120 |
+
name: 'Sora2 Video Generator No Watermark',
|
| 121 |
+
description: 'Generate videos using Sora2 AI model without watermark',
|
| 122 |
+
type: 'GET',
|
| 123 |
+
routes: ['api/AI/sora2nowm'],
|
| 124 |
+
tags: ['AI', 'Sora', 'Video', 'NoWatermark'],
|
| 125 |
+
parameters: ['prompt', 'key'],
|
| 126 |
+
enabled: true,
|
| 127 |
+
main: ['AI'],
|
| 128 |
+
limit: 15,
|
| 129 |
+
handler
|
| 130 |
+
};
|
plugins/spotifydl.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { spotydl } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { url } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!url) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: url'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await spotydl(url);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
msg: result.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'Spotify DL',
|
| 31 |
+
description: 'Download Spotify Music Without Effort',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/download/spotifydl'],
|
| 34 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 35 |
+
parameters: ['url', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['Downloader'],
|
| 38 |
+
handler
|
| 39 |
+
}
|
plugins/spotifysearch.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { spotifysearch } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { text } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!text) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: text'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await spotifysearch(text);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
data: result.results
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'Spotify Search',
|
| 31 |
+
description: 'Generate responses using OpenAI ChatGPT',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/search/spotify'],
|
| 34 |
+
tags: ['tools', 'spotify', 'downloader'],
|
| 35 |
+
main: ['Search'],
|
| 36 |
+
parameters: ['text', 'key'],
|
| 37 |
+
enabled: true,
|
| 38 |
+
handler
|
| 39 |
+
};
|
plugins/subdo.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const TURNSTILE_SOLVER_URL = 'https://herzaj-turnstile-solver.hf.space';
|
| 2 |
+
|
| 3 |
+
async function getTurnstileToken() {
|
| 4 |
+
try {
|
| 5 |
+
const params = new URLSearchParams({
|
| 6 |
+
url: 'https://www.subdomainfinder.in',
|
| 7 |
+
sitekey: '0x4AAAAAAAj7jyMV3Zv9ZMN-'
|
| 8 |
+
});
|
| 9 |
+
|
| 10 |
+
const submitResponse = await fetch(`${TURNSTILE_SOLVER_URL}/turnstile?${params}`, {
|
| 11 |
+
method: 'GET'
|
| 12 |
+
});
|
| 13 |
+
|
| 14 |
+
if (!submitResponse.ok) {
|
| 15 |
+
throw new Error(`Failed to submit task: ${submitResponse.status}`);
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
const taskData = await submitResponse.json();
|
| 19 |
+
const taskId = taskData.task_id;
|
| 20 |
+
|
| 21 |
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
| 22 |
+
|
| 23 |
+
const resultResponse = await fetch(`${TURNSTILE_SOLVER_URL}/result?id=${taskId}`);
|
| 24 |
+
|
| 25 |
+
if (!resultResponse.ok) {
|
| 26 |
+
throw new Error(`Failed to get result: ${resultResponse.status}`);
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
const resultData = await resultResponse.json();
|
| 30 |
+
return resultData.value;
|
| 31 |
+
|
| 32 |
+
} catch (error) {
|
| 33 |
+
throw new Error("Gagal mendapatkan Turnstile token: " + error.message);
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
async function findSubdomains(domain, token) {
|
| 38 |
+
const response = await fetch(`https://api.subdomainfinder.in/?domain=${domain}`, {
|
| 39 |
+
method: 'GET',
|
| 40 |
+
headers: {
|
| 41 |
+
'X-Secure-Token': token,
|
| 42 |
+
'X-Referer': 'https://www.google.com/',
|
| 43 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
| 44 |
+
}
|
| 45 |
+
});
|
| 46 |
+
|
| 47 |
+
if (!response.ok) {
|
| 48 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
return await response.json();
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
async function resolveDNS(subdomain) {
|
| 55 |
+
const response = await fetch(`https://lookup.subdomainfinder.in/resolve?name=${subdomain}&rd=1`, {
|
| 56 |
+
method: 'GET',
|
| 57 |
+
headers: {
|
| 58 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
| 59 |
+
}
|
| 60 |
+
});
|
| 61 |
+
|
| 62 |
+
if (!response.ok) {
|
| 63 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
return await response.json();
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
async function getIPInfo(ip) {
|
| 70 |
+
const response = await fetch(`https://ipresolver.subdomainfinder.in/${ip}`, {
|
| 71 |
+
method: 'GET',
|
| 72 |
+
headers: {
|
| 73 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
| 74 |
+
}
|
| 75 |
+
});
|
| 76 |
+
|
| 77 |
+
if (!response.ok) {
|
| 78 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
return await response.json();
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
function extractIPFromDNS(dnsData) {
|
| 85 |
+
if (!dnsData || !dnsData.Answer) return null;
|
| 86 |
+
|
| 87 |
+
for (const answer of dnsData.Answer) {
|
| 88 |
+
if (answer.type === 1 && answer.data) {
|
| 89 |
+
return answer.data;
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
return null;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
async function subdo(domain) {
|
| 96 |
+
const token = await getTurnstileToken();
|
| 97 |
+
const subdomainData = await findSubdomains(domain, token);
|
| 98 |
+
const results = [];
|
| 99 |
+
|
| 100 |
+
for (const sub of subdomainData.data) {
|
| 101 |
+
try {
|
| 102 |
+
const dnsData = await resolveDNS(sub.subdomain);
|
| 103 |
+
const ip = extractIPFromDNS(dnsData);
|
| 104 |
+
|
| 105 |
+
let result = {
|
| 106 |
+
subdomain: sub.subdomain,
|
| 107 |
+
ip: ip || 'N/A',
|
| 108 |
+
cloudflare: sub.cloudflare,
|
| 109 |
+
dnsStatus: dnsData.Status
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
if (ip) {
|
| 113 |
+
try {
|
| 114 |
+
const ipInfo = await getIPInfo(ip);
|
| 115 |
+
if (ipInfo.success && ipInfo.result && ipInfo.result.ip) {
|
| 116 |
+
result.ipInfo = {
|
| 117 |
+
location: ipInfo.result.ip.locationName,
|
| 118 |
+
asn: ipInfo.result.ip.asnName,
|
| 119 |
+
country: ipInfo.result.ip.location,
|
| 120 |
+
flag: ipInfo.result.ip.flag
|
| 121 |
+
};
|
| 122 |
+
}
|
| 123 |
+
} catch (e) {
|
| 124 |
+
result.ipInfo = null;
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
results.push(result);
|
| 129 |
+
} catch (error) {
|
| 130 |
+
results.push({
|
| 131 |
+
subdomain: sub.subdomain,
|
| 132 |
+
error: error.message
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
return {
|
| 138 |
+
domain: domain,
|
| 139 |
+
count: subdomainData.count,
|
| 140 |
+
data: results
|
| 141 |
+
};
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
const handler = async (req, res) => {
|
| 145 |
+
try {
|
| 146 |
+
const { domain } = req.query;
|
| 147 |
+
|
| 148 |
+
if (!domain) {
|
| 149 |
+
return res.status(400).json({
|
| 150 |
+
success: false,
|
| 151 |
+
error: 'Missing required parameter: domain'
|
| 152 |
+
});
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.([a-zA-Z]{2,}\.?)+$/;
|
| 156 |
+
if (!domainRegex.test(domain)) {
|
| 157 |
+
return res.status(400).json({
|
| 158 |
+
success: false,
|
| 159 |
+
error: 'Invalid domain format'
|
| 160 |
+
});
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
const result = await subdo(domain);
|
| 164 |
+
|
| 165 |
+
res.json({
|
| 166 |
+
success: true,
|
| 167 |
+
data: {
|
| 168 |
+
domain: result.domain,
|
| 169 |
+
total_subdomains: result.count,
|
| 170 |
+
subdomains: result.data
|
| 171 |
+
}
|
| 172 |
+
});
|
| 173 |
+
|
| 174 |
+
} catch (error) {
|
| 175 |
+
res.status(500).json({
|
| 176 |
+
success: false,
|
| 177 |
+
error: error.message
|
| 178 |
+
});
|
| 179 |
+
}
|
| 180 |
+
};
|
| 181 |
+
|
| 182 |
+
module.exports = {
|
| 183 |
+
name: 'Subdomain Finder',
|
| 184 |
+
description: 'Find subdomains with IP addresses and location information',
|
| 185 |
+
type: 'GET',
|
| 186 |
+
routes: ['api/tools/subdofinder'],
|
| 187 |
+
tags: ['security', 'subdomain', 'dns', 'recon'],
|
| 188 |
+
parameters: ['domain', 'key'],
|
| 189 |
+
enabled: true,
|
| 190 |
+
main: ['tools', 'Search'],
|
| 191 |
+
handler
|
| 192 |
+
};
|
plugins/suno.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const { v4: uuidv4 } = require('uuid');
|
| 3 |
+
const readline = require('readline');
|
| 4 |
+
|
| 5 |
+
const sonu = {
|
| 6 |
+
api: {
|
| 7 |
+
base: 'https://musicai.apihub.today/api/v1',
|
| 8 |
+
endpoints: {
|
| 9 |
+
register: '/users',
|
| 10 |
+
create: '/song/create',
|
| 11 |
+
checkStatus: '/song/user'
|
| 12 |
+
}
|
| 13 |
+
},
|
| 14 |
+
|
| 15 |
+
headers: {
|
| 16 |
+
'user-agent': 'NB Android/1.0.0',
|
| 17 |
+
'content-type': 'application/json',
|
| 18 |
+
'accept': 'application/json',
|
| 19 |
+
'x-platform': 'android',
|
| 20 |
+
'x-app-version': '1.0.0',
|
| 21 |
+
'x-country': 'ID',
|
| 22 |
+
'accept-language': 'id-ID',
|
| 23 |
+
'x-client-timezone': 'Asia/Jakarta'
|
| 24 |
+
},
|
| 25 |
+
|
| 26 |
+
deviceId: uuidv4(),
|
| 27 |
+
userId: null,
|
| 28 |
+
fcmToken: 'eqnTqlxMTSKQL5NQz6r5aP:APA91bHa3CvL5Nlcqx2yzqTDAeqxm_L_vIYxXqehkgmTsCXrV29eAak6_jqXv5v1mQrdw4BGMLXl_BFNrJ67Em0vmdr3hQPVAYF8kR7RDtTRHQ08F3jLRRI',
|
| 29 |
+
|
| 30 |
+
register: async () => {
|
| 31 |
+
const msgId = uuidv4();
|
| 32 |
+
const time = Date.now().toString();
|
| 33 |
+
const header = {
|
| 34 |
+
...sonu.headers,
|
| 35 |
+
'x-device-id': sonu.deviceId,
|
| 36 |
+
'x-request-id': msgId,
|
| 37 |
+
'x-message-id': msgId,
|
| 38 |
+
'x-request-time': time
|
| 39 |
+
};
|
| 40 |
+
|
| 41 |
+
try {
|
| 42 |
+
const response = await axios.put(
|
| 43 |
+
`${sonu.api.base}${sonu.api.endpoints.register}`,
|
| 44 |
+
{
|
| 45 |
+
deviceId: sonu.deviceId,
|
| 46 |
+
fcmToken: sonu.fcmToken
|
| 47 |
+
},
|
| 48 |
+
{ headers: header }
|
| 49 |
+
);
|
| 50 |
+
sonu.userId = response.data.id;
|
| 51 |
+
return {
|
| 52 |
+
success: true,
|
| 53 |
+
code: 200,
|
| 54 |
+
result: { userId: sonu.userId }
|
| 55 |
+
};
|
| 56 |
+
} catch (err) {
|
| 57 |
+
return {
|
| 58 |
+
success: false,
|
| 59 |
+
code: err.response?.status || 500,
|
| 60 |
+
result: { error: err.message }
|
| 61 |
+
};
|
| 62 |
+
}
|
| 63 |
+
},
|
| 64 |
+
|
| 65 |
+
create: async ({ title, mood, genre, lyrics, gender }) => {
|
| 66 |
+
if (!title || title.trim() === '') {
|
| 67 |
+
return {
|
| 68 |
+
success: false,
|
| 69 |
+
code: 400,
|
| 70 |
+
result: { error: "Judul lagunya kagak boleh kosong bree 😂" }
|
| 71 |
+
};
|
| 72 |
+
}
|
| 73 |
+
if (!lyrics || lyrics.trim() === '') {
|
| 74 |
+
return {
|
| 75 |
+
success: false,
|
| 76 |
+
code: 400,
|
| 77 |
+
result: { error: "Lirik lagunya mana? Mau generate lagu kan? Yaa mana liriknya 😂" }
|
| 78 |
+
};
|
| 79 |
+
}
|
| 80 |
+
if (lyrics.length > 1500) {
|
| 81 |
+
return {
|
| 82 |
+
success: false,
|
| 83 |
+
code: 400,
|
| 84 |
+
result: { error: "Lirik lagu kagak boleh lebih dari 1500 karakter yak bree 🗿"}
|
| 85 |
+
};
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
const msgId = uuidv4();
|
| 89 |
+
const time = Date.now().toString();
|
| 90 |
+
const header = {
|
| 91 |
+
...sonu.headers,
|
| 92 |
+
'x-device-id': sonu.deviceId,
|
| 93 |
+
'x-client-id': sonu.userId,
|
| 94 |
+
'x-request-id': msgId,
|
| 95 |
+
'x-message-id': msgId,
|
| 96 |
+
'x-request-time': time
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
const body = {
|
| 100 |
+
type: 'lyrics',
|
| 101 |
+
name: title,
|
| 102 |
+
lyrics
|
| 103 |
+
};
|
| 104 |
+
if (mood && mood.trim() !== '') body.mood = mood;
|
| 105 |
+
if (genre && genre.trim() !== '') body.genre = genre;
|
| 106 |
+
if (gender && gender.trim() !== '') body.gender = gender;
|
| 107 |
+
|
| 108 |
+
try {
|
| 109 |
+
const response = await axios.post(
|
| 110 |
+
`${sonu.api.base}${sonu.api.endpoints.create}`,
|
| 111 |
+
body,
|
| 112 |
+
{ headers: header }
|
| 113 |
+
);
|
| 114 |
+
|
| 115 |
+
return {
|
| 116 |
+
success: true,
|
| 117 |
+
code: 200,
|
| 118 |
+
result: { songId: response.data.id }
|
| 119 |
+
};
|
| 120 |
+
} catch (err) {
|
| 121 |
+
return {
|
| 122 |
+
success: false,
|
| 123 |
+
code: err.response?.status || 500,
|
| 124 |
+
result: { error: err.message }
|
| 125 |
+
};
|
| 126 |
+
}
|
| 127 |
+
},
|
| 128 |
+
|
| 129 |
+
task: async (songId) => {
|
| 130 |
+
const header = {
|
| 131 |
+
...sonu.headers,
|
| 132 |
+
'x-client-id': sonu.userId
|
| 133 |
+
};
|
| 134 |
+
|
| 135 |
+
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
| 136 |
+
|
| 137 |
+
try {
|
| 138 |
+
let attempt = 0;
|
| 139 |
+
let found = null;
|
| 140 |
+
|
| 141 |
+
while (true) {
|
| 142 |
+
const response = await axios.get(
|
| 143 |
+
`${sonu.api.base}${sonu.api.endpoints.checkStatus}`,
|
| 144 |
+
{
|
| 145 |
+
params: {
|
| 146 |
+
userId: sonu.userId,
|
| 147 |
+
isFavorite: false,
|
| 148 |
+
page: 1,
|
| 149 |
+
searchText: ''
|
| 150 |
+
},
|
| 151 |
+
headers: header
|
| 152 |
+
}
|
| 153 |
+
);
|
| 154 |
+
|
| 155 |
+
found = response.data.datas.find(song => song.id === songId);
|
| 156 |
+
if (!found) {
|
| 157 |
+
return {
|
| 158 |
+
success: false,
|
| 159 |
+
code: 404,
|
| 160 |
+
result: { error: "Lagunya belum jadi keknya bree, soalnya kagak ada 😂" }
|
| 161 |
+
};
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
attempt++;
|
| 165 |
+
|
| 166 |
+
if (found.url) {
|
| 167 |
+
return {
|
| 168 |
+
success: true,
|
| 169 |
+
code: 200,
|
| 170 |
+
result: {
|
| 171 |
+
status: found.status,
|
| 172 |
+
songId: found.id,
|
| 173 |
+
title: found.name,
|
| 174 |
+
username: found.username,
|
| 175 |
+
url: found.url,
|
| 176 |
+
thumbnail: found.thumbnail_url
|
| 177 |
+
}
|
| 178 |
+
};
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
await delay(3000);
|
| 182 |
+
}
|
| 183 |
+
} catch (err) {
|
| 184 |
+
return {
|
| 185 |
+
success: false,
|
| 186 |
+
code: err.response?.status || 500,
|
| 187 |
+
result: { error: err.message }
|
| 188 |
+
};
|
| 189 |
+
}
|
| 190 |
+
}
|
| 191 |
+
};
|
| 192 |
+
|
| 193 |
+
const handler = async (req, res) => {
|
| 194 |
+
try {
|
| 195 |
+
const { title, mood, genre, lyrics, gender } = req.query;
|
| 196 |
+
|
| 197 |
+
if (!title) {
|
| 198 |
+
return res.status(400).json({
|
| 199 |
+
success: false,
|
| 200 |
+
error: 'Missing required parameter: title'
|
| 201 |
+
});
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
if (!lyrics) {
|
| 205 |
+
return res.status(400).json({
|
| 206 |
+
success: false,
|
| 207 |
+
error: 'Missing required parameter: lyrics'
|
| 208 |
+
});
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
const registerResult = await sonu.register();
|
| 212 |
+
if (!registerResult.success) {
|
| 213 |
+
return res.status(registerResult.code).json({
|
| 214 |
+
author: "Herza",
|
| 215 |
+
success: false,
|
| 216 |
+
error: registerResult.result.error
|
| 217 |
+
});
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
const createResult = await sonu.create({ title, mood, genre, lyrics, gender });
|
| 221 |
+
if (!createResult.success) {
|
| 222 |
+
return res.status(createResult.code).json({
|
| 223 |
+
author: "Herza",
|
| 224 |
+
success: false,
|
| 225 |
+
error: createResult.result.error
|
| 226 |
+
});
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
const taskResult = await sonu.task(createResult.result.songId);
|
| 230 |
+
if (!taskResult.success) {
|
| 231 |
+
return res.status(taskResult.code).json({
|
| 232 |
+
author: "Herza",
|
| 233 |
+
success: false,
|
| 234 |
+
error: taskResult.result.error
|
| 235 |
+
});
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
res.json({
|
| 239 |
+
author: "Herza",
|
| 240 |
+
success: true,
|
| 241 |
+
result: taskResult.result
|
| 242 |
+
});
|
| 243 |
+
|
| 244 |
+
} catch (error) {
|
| 245 |
+
res.status(500).json({
|
| 246 |
+
success: false,
|
| 247 |
+
error: error.message
|
| 248 |
+
});
|
| 249 |
+
}
|
| 250 |
+
};
|
| 251 |
+
|
| 252 |
+
module.exports = {
|
| 253 |
+
name: 'Suno AI Music Generator',
|
| 254 |
+
description: 'Generate music using Suno AI with custom lyrics',
|
| 255 |
+
type: 'GET',
|
| 256 |
+
routes: ['api/AI/sunov1'],
|
| 257 |
+
tags: ['ai', 'music', 'suno', 'generator'],
|
| 258 |
+
main: ['AI'],
|
| 259 |
+
limit: 6,
|
| 260 |
+
parameters: ['title', 'lyrics', 'mood', 'genre', 'gender', 'key'],
|
| 261 |
+
enabled: true,
|
| 262 |
+
handler
|
| 263 |
+
};
|
plugins/suno4.js
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const crypto = require('crypto');
|
| 3 |
+
const HttpProxyAgent = require('http-proxy-agent');
|
| 4 |
+
const HttpsProxyAgent = require('https-proxy-agent');
|
| 5 |
+
|
| 6 |
+
async function getRandomProxy() {
|
| 7 |
+
try {
|
| 8 |
+
const response = await axios.get('https://raw.githubusercontent.com/proxifly/free-proxy-list/refs/heads/main/proxies/protocols/https/data.json');
|
| 9 |
+
const proxies = response.data;
|
| 10 |
+
if (proxies.length === 0) return null;
|
| 11 |
+
return proxies[Math.floor(Math.random() * proxies.length)].proxy;
|
| 12 |
+
} catch (err) {
|
| 13 |
+
return null;
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
const aiMu = {
|
| 18 |
+
api: {
|
| 19 |
+
base: 'https://aimu.1010diy.com',
|
| 20 |
+
endpoint: {
|
| 21 |
+
credits: '/and/getUserActualCredits',
|
| 22 |
+
musicAI: '/music/MusicAI',
|
| 23 |
+
taskStatus: '/music/getTaskStatus',
|
| 24 |
+
generateList: '/and/data/generateList',
|
| 25 |
+
options: '/and/home/index',
|
| 26 |
+
},
|
| 27 |
+
},
|
| 28 |
+
|
| 29 |
+
headers: {
|
| 30 |
+
'user-agent': 'NB Android/1.0.0',
|
| 31 |
+
'accept-encoding': 'gzip',
|
| 32 |
+
'x-version-code': '27',
|
| 33 |
+
'x-token': '',
|
| 34 |
+
},
|
| 35 |
+
|
| 36 |
+
sid: null,
|
| 37 |
+
|
| 38 |
+
setDeviceId: (id) => {
|
| 39 |
+
aiMu.sid = id;
|
| 40 |
+
},
|
| 41 |
+
|
| 42 |
+
getDeviceId: () => {
|
| 43 |
+
if (!aiMu.sid) {
|
| 44 |
+
aiMu.sid = crypto.randomBytes(8).toString('hex');
|
| 45 |
+
}
|
| 46 |
+
return aiMu.sid;
|
| 47 |
+
},
|
| 48 |
+
|
| 49 |
+
opts: async () => {
|
| 50 |
+
try {
|
| 51 |
+
const proxyUrl = await getRandomProxy();
|
| 52 |
+
const axiosConfig = { headers: { ...aiMu.headers, 'x-device-id': aiMu.getDeviceId() } };
|
| 53 |
+
|
| 54 |
+
if (proxyUrl) {
|
| 55 |
+
axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl);
|
| 56 |
+
axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
const res = await axios.get(
|
| 60 |
+
`${aiMu.api.base}${aiMu.api.endpoint.options}`,
|
| 61 |
+
axiosConfig
|
| 62 |
+
);
|
| 63 |
+
|
| 64 |
+
const { code, msg, data } = res.data;
|
| 65 |
+
if (code !== 200) {
|
| 66 |
+
return {
|
| 67 |
+
success: false,
|
| 68 |
+
code,
|
| 69 |
+
author: 'Daffa ~',
|
| 70 |
+
team: 'NB Team',
|
| 71 |
+
result: {
|
| 72 |
+
error: { msg }
|
| 73 |
+
}
|
| 74 |
+
};
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
const moods = [...(data.mood?.default || []), ...(data.mood?.more || [])].map(m => m.text);
|
| 78 |
+
const genres = [...(data.genre?.default || []), ...(data.genre?.more || [])].map(g => g.text);
|
| 79 |
+
const voices = ['female', 'male', 'random'];
|
| 80 |
+
|
| 81 |
+
return {
|
| 82 |
+
success: true,
|
| 83 |
+
code: 200,
|
| 84 |
+
author: 'Daffa ~',
|
| 85 |
+
team: 'NB Team',
|
| 86 |
+
result: {
|
| 87 |
+
moods,
|
| 88 |
+
genres,
|
| 89 |
+
voices
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
} catch (err) {
|
| 93 |
+
return {
|
| 94 |
+
success: false,
|
| 95 |
+
code: err.response?.status || 500,
|
| 96 |
+
author: 'Daffa ~',
|
| 97 |
+
team: 'NB Team',
|
| 98 |
+
result: {
|
| 99 |
+
error: err.message
|
| 100 |
+
}
|
| 101 |
+
};
|
| 102 |
+
}
|
| 103 |
+
},
|
| 104 |
+
|
| 105 |
+
getCredits: async () => {
|
| 106 |
+
try {
|
| 107 |
+
const proxyUrl = await getRandomProxy();
|
| 108 |
+
const axiosConfig = { headers: { ...aiMu.headers, 'x-device-id': aiMu.getDeviceId() } };
|
| 109 |
+
|
| 110 |
+
if (proxyUrl) {
|
| 111 |
+
axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl);
|
| 112 |
+
axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
const res = await axios.get(
|
| 116 |
+
`${aiMu.api.base}${aiMu.api.endpoint.credits}`,
|
| 117 |
+
axiosConfig
|
| 118 |
+
);
|
| 119 |
+
const { code, msg, data } = res.data;
|
| 120 |
+
if (code === 200) {
|
| 121 |
+
return {
|
| 122 |
+
success: true,
|
| 123 |
+
code: 200,
|
| 124 |
+
author: 'Daffa ~',
|
| 125 |
+
team: 'NB Team',
|
| 126 |
+
result: {
|
| 127 |
+
...data
|
| 128 |
+
}
|
| 129 |
+
};
|
| 130 |
+
}
|
| 131 |
+
return {
|
| 132 |
+
success: false,
|
| 133 |
+
code,
|
| 134 |
+
author: 'Daffa ~',
|
| 135 |
+
team: 'NB Team',
|
| 136 |
+
result: {
|
| 137 |
+
error: msg
|
| 138 |
+
}
|
| 139 |
+
};
|
| 140 |
+
} catch (err) {
|
| 141 |
+
return {
|
| 142 |
+
success: false,
|
| 143 |
+
code: err.response?.status || 500,
|
| 144 |
+
author: 'Daffa ~',
|
| 145 |
+
team: 'NB Team',
|
| 146 |
+
result: {
|
| 147 |
+
error: err.message
|
| 148 |
+
}
|
| 149 |
+
};
|
| 150 |
+
}
|
| 151 |
+
},
|
| 152 |
+
|
| 153 |
+
generate: async (params) => {
|
| 154 |
+
let make_instrumental = params.make_instrumental ? 1 : 0;
|
| 155 |
+
let vocal_only = params.vocal_only ? 1 : 0;
|
| 156 |
+
if (make_instrumental === 1) vocal_only = 0;
|
| 157 |
+
|
| 158 |
+
const { lyrics = '', prompt = '' } = params;
|
| 159 |
+
if (!lyrics.trim() && !prompt.trim()) {
|
| 160 |
+
return {
|
| 161 |
+
success: false,
|
| 162 |
+
code: 400,
|
| 163 |
+
author: 'Daffa ~',
|
| 164 |
+
team: 'NB Team',
|
| 165 |
+
result: {
|
| 166 |
+
error: 'Lu bisa pilih Lyric atau Prompt bree'
|
| 167 |
+
}
|
| 168 |
+
};
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
if (prompt && prompt.length > 1000) {
|
| 172 |
+
return {
|
| 173 |
+
success: false,
|
| 174 |
+
code: 400,
|
| 175 |
+
author: 'Daffa ~',
|
| 176 |
+
team: 'NB Team',
|
| 177 |
+
result: {
|
| 178 |
+
error: 'Promptnya kepanjangan yak, max 1k karakter aja.. '
|
| 179 |
+
}
|
| 180 |
+
};
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
const payload = { make_instrumental, vocal_only, lyrics, prompt, ...params };
|
| 184 |
+
|
| 185 |
+
try {
|
| 186 |
+
const proxyUrl = await getRandomProxy();
|
| 187 |
+
const axiosConfig = {
|
| 188 |
+
headers: {
|
| 189 |
+
...aiMu.headers,
|
| 190 |
+
'content-type': 'application/json',
|
| 191 |
+
'x-device-id': aiMu.getDeviceId(),
|
| 192 |
+
},
|
| 193 |
+
};
|
| 194 |
+
|
| 195 |
+
if (proxyUrl) {
|
| 196 |
+
axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl);
|
| 197 |
+
axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl);
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
const res = await axios.post(
|
| 201 |
+
`${aiMu.api.base}${aiMu.api.endpoint.musicAI}`,
|
| 202 |
+
payload,
|
| 203 |
+
axiosConfig
|
| 204 |
+
);
|
| 205 |
+
const { code, msg, data } = res.data;
|
| 206 |
+
if (code === 200) {
|
| 207 |
+
return {
|
| 208 |
+
success: true,
|
| 209 |
+
code: 200,
|
| 210 |
+
author: 'Daffa ~',
|
| 211 |
+
team: 'NB Team',
|
| 212 |
+
result: {
|
| 213 |
+
taskId: data?.task_id,
|
| 214 |
+
inputType: prompt ? 'prompt' : 'lyrics',
|
| 215 |
+
inputValue: prompt || lyrics
|
| 216 |
+
}
|
| 217 |
+
};
|
| 218 |
+
}
|
| 219 |
+
return {
|
| 220 |
+
success: false,
|
| 221 |
+
code,
|
| 222 |
+
author: 'Daffa ~',
|
| 223 |
+
team: 'NB Team',
|
| 224 |
+
result: {
|
| 225 |
+
error: msg
|
| 226 |
+
}
|
| 227 |
+
};
|
| 228 |
+
} catch (err) {
|
| 229 |
+
return {
|
| 230 |
+
success: false,
|
| 231 |
+
code: err.response?.status || 500,
|
| 232 |
+
author: 'Daffa ~',
|
| 233 |
+
team: 'NB Team',
|
| 234 |
+
result: {
|
| 235 |
+
error: err.message
|
| 236 |
+
}
|
| 237 |
+
};
|
| 238 |
+
}
|
| 239 |
+
},
|
| 240 |
+
|
| 241 |
+
polling: async (taskId) => {
|
| 242 |
+
if (!String(taskId)?.trim()) {
|
| 243 |
+
return {
|
| 244 |
+
success: false,
|
| 245 |
+
code: 400,
|
| 246 |
+
author: 'Daffa ~',
|
| 247 |
+
team: 'NB Team',
|
| 248 |
+
result: {
|
| 249 |
+
error: 'Task IDnya kagak boleh kosong bree... '
|
| 250 |
+
}
|
| 251 |
+
};
|
| 252 |
+
}
|
| 253 |
+
try {
|
| 254 |
+
const proxyUrl = await getRandomProxy();
|
| 255 |
+
const axiosConfig = {
|
| 256 |
+
params: { task_id: taskId },
|
| 257 |
+
headers: { ...aiMu.headers, 'x-device-id': aiMu.getDeviceId() },
|
| 258 |
+
};
|
| 259 |
+
|
| 260 |
+
if (proxyUrl) {
|
| 261 |
+
axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl);
|
| 262 |
+
axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl);
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
const res = await axios.get(
|
| 266 |
+
`${aiMu.api.base}${aiMu.api.endpoint.taskStatus}`,
|
| 267 |
+
axiosConfig
|
| 268 |
+
);
|
| 269 |
+
const { code, msg, data } = res.data;
|
| 270 |
+
if (code === 200) {
|
| 271 |
+
return {
|
| 272 |
+
success: true,
|
| 273 |
+
code: 200,
|
| 274 |
+
author: 'Daffa ~',
|
| 275 |
+
team: 'NB Team',
|
| 276 |
+
result: {
|
| 277 |
+
status: data?.status,
|
| 278 |
+
}
|
| 279 |
+
};
|
| 280 |
+
}
|
| 281 |
+
return {
|
| 282 |
+
success: false,
|
| 283 |
+
code,
|
| 284 |
+
author: 'Daffa ~',
|
| 285 |
+
team: 'NB Team',
|
| 286 |
+
result: {
|
| 287 |
+
error: msg
|
| 288 |
+
}
|
| 289 |
+
};
|
| 290 |
+
} catch (err) {
|
| 291 |
+
return {
|
| 292 |
+
success: false,
|
| 293 |
+
code: err.response?.status || 500,
|
| 294 |
+
author: 'Daffa ~',
|
| 295 |
+
team: 'NB Team',
|
| 296 |
+
result: {
|
| 297 |
+
error: err.message
|
| 298 |
+
}
|
| 299 |
+
};
|
| 300 |
+
}
|
| 301 |
+
},
|
| 302 |
+
|
| 303 |
+
getGenerateList: async () => {
|
| 304 |
+
try {
|
| 305 |
+
const proxyUrl = await getRandomProxy();
|
| 306 |
+
const axiosConfig = { headers: { ...aiMu.headers, 'x-device-id': aiMu.getDeviceId() } };
|
| 307 |
+
|
| 308 |
+
if (proxyUrl) {
|
| 309 |
+
axiosConfig.httpAgent = new HttpProxyAgent(proxyUrl);
|
| 310 |
+
axiosConfig.httpsAgent = new HttpsProxyAgent(proxyUrl);
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
const res = await axios.get(
|
| 314 |
+
`${aiMu.api.base}${aiMu.api.endpoint.generateList}`,
|
| 315 |
+
axiosConfig
|
| 316 |
+
);
|
| 317 |
+
const { code, msg, data } = res.data;
|
| 318 |
+
if (code === 200) {
|
| 319 |
+
const results = (data || []).map((item) => ({
|
| 320 |
+
taskId: item.task_id,
|
| 321 |
+
title: item.title,
|
| 322 |
+
duration: item.duration,
|
| 323 |
+
mp3: item.conversion_path,
|
| 324 |
+
cover: item.album_cover_path,
|
| 325 |
+
input: item.lyrics,
|
| 326 |
+
created_at: item.created_at,
|
| 327 |
+
updated_at: item.updated_at,
|
| 328 |
+
}));
|
| 329 |
+
return {
|
| 330 |
+
success: true,
|
| 331 |
+
code: 200,
|
| 332 |
+
author: 'Daffa ~',
|
| 333 |
+
team: 'NB Team',
|
| 334 |
+
result: {
|
| 335 |
+
results
|
| 336 |
+
}
|
| 337 |
+
};
|
| 338 |
+
}
|
| 339 |
+
return {
|
| 340 |
+
success: false,
|
| 341 |
+
code,
|
| 342 |
+
author: 'Daffa ~',
|
| 343 |
+
team: 'NB Team',
|
| 344 |
+
result: {
|
| 345 |
+
error: msg
|
| 346 |
+
}
|
| 347 |
+
};
|
| 348 |
+
} catch (err) {
|
| 349 |
+
return {
|
| 350 |
+
success: false,
|
| 351 |
+
code: err.response?.status || 500,
|
| 352 |
+
author: 'Daffa ~',
|
| 353 |
+
team: 'NB Team',
|
| 354 |
+
result: {
|
| 355 |
+
error: err.message
|
| 356 |
+
}
|
| 357 |
+
};
|
| 358 |
+
}
|
| 359 |
+
},
|
| 360 |
+
|
| 361 |
+
task: async (taskId, inputType, inputValue, intervalMs = 5000) => {
|
| 362 |
+
if (!String(taskId)?.trim()) {
|
| 363 |
+
return {
|
| 364 |
+
success: false,
|
| 365 |
+
code: 400,
|
| 366 |
+
author: 'Daffa ~',
|
| 367 |
+
team: 'NB Team',
|
| 368 |
+
result: {
|
| 369 |
+
error: 'Task IDnya kagak boleh kosong bree... '
|
| 370 |
+
}
|
| 371 |
+
};
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
while (true) {
|
| 375 |
+
const resx = await aiMu.polling(taskId);
|
| 376 |
+
if (!resx.success) return resx;
|
| 377 |
+
|
| 378 |
+
if (resx.result.status === 'complete') {
|
| 379 |
+
const re = await aiMu.getGenerateList();
|
| 380 |
+
if (!re.success) return re;
|
| 381 |
+
|
| 382 |
+
const tracks = re.result.results.filter((r) => String(r.taskId) === String(taskId));
|
| 383 |
+
|
| 384 |
+
const avr = tracks.every((t) => t.mp3.includes('vocal-remover.s3.us-west-2.amazonaws.com'));
|
| 385 |
+
|
| 386 |
+
if (tracks.length > 0 && avr) {
|
| 387 |
+
return {
|
| 388 |
+
success: true,
|
| 389 |
+
code: 200,
|
| 390 |
+
author: 'Daffa ~',
|
| 391 |
+
team: 'NB Team',
|
| 392 |
+
result: {
|
| 393 |
+
taskId: String(taskId),
|
| 394 |
+
count: tracks.length,
|
| 395 |
+
tracks: tracks.map((t) => ({
|
| 396 |
+
title: t.title,
|
| 397 |
+
duration: t.duration,
|
| 398 |
+
audio: t.mp3,
|
| 399 |
+
cover: t.cover,
|
| 400 |
+
[inputType]: t.input,
|
| 401 |
+
created_at: t.created_at,
|
| 402 |
+
updated_at: t.updated_at,
|
| 403 |
+
})),
|
| 404 |
+
inputValue
|
| 405 |
+
}
|
| 406 |
+
};
|
| 407 |
+
}
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
await new Promise((r) => setTimeout(r, intervalMs));
|
| 411 |
+
}
|
| 412 |
+
},
|
| 413 |
+
};
|
| 414 |
+
|
| 415 |
+
const handler = async (req, res) => {
|
| 416 |
+
try {
|
| 417 |
+
const { prompt, lyrics, mood, genre, voice, key } = req.query;
|
| 418 |
+
|
| 419 |
+
if (!prompt && !lyrics) {
|
| 420 |
+
return res.status(400).json({
|
| 421 |
+
success: false,
|
| 422 |
+
error: 'Missing required parameter: prompt or lyrics'
|
| 423 |
+
});
|
| 424 |
+
}
|
| 425 |
+
|
| 426 |
+
const params = {
|
| 427 |
+
prompt: prompt || '',
|
| 428 |
+
lyrics: lyrics || '',
|
| 429 |
+
mood: mood || '',
|
| 430 |
+
genre: genre || '',
|
| 431 |
+
voice: voice || 'random',
|
| 432 |
+
make_instrumental: 0,
|
| 433 |
+
vocal_only: 0
|
| 434 |
+
};
|
| 435 |
+
|
| 436 |
+
const genResult = await aiMu.generate(params);
|
| 437 |
+
|
| 438 |
+
if (!genResult.success) {
|
| 439 |
+
return res.status(400).json(genResult);
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
const taskId = genResult.result.taskId;
|
| 443 |
+
const inputType = genResult.result.inputType;
|
| 444 |
+
const inputValue = genResult.result.inputValue;
|
| 445 |
+
|
| 446 |
+
const taskResult = await aiMu.task(taskId, inputType, inputValue);
|
| 447 |
+
|
| 448 |
+
res.json(taskResult);
|
| 449 |
+
|
| 450 |
+
} catch (error) {
|
| 451 |
+
res.status(500).json({
|
| 452 |
+
success: false,
|
| 453 |
+
error: error.message
|
| 454 |
+
});
|
| 455 |
+
}
|
| 456 |
+
};
|
| 457 |
+
|
| 458 |
+
module.exports = {
|
| 459 |
+
name: 'Sunov4 Music Generator',
|
| 460 |
+
description: 'Generate music using AiMu AI model',
|
| 461 |
+
type: 'GET',
|
| 462 |
+
routes: ['api/AI/suno4'],
|
| 463 |
+
tags: ['ai', 'music', 'aimu', 'suno'],
|
| 464 |
+
main: ['AI'],
|
| 465 |
+
parameters: ['prompt', 'lyrics', 'mood', 'genre', 'voice', 'key'],
|
| 466 |
+
enabled: true,
|
| 467 |
+
limit: 18,
|
| 468 |
+
handler
|
| 469 |
+
};
|
plugins/sunov2.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
class YesChatMusicGenerator {
|
| 4 |
+
constructor() {
|
| 5 |
+
this.userAgent = "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36";
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
async getBypassToken() {
|
| 9 |
+
try {
|
| 10 |
+
const response = await axios.get('https://anabot.my.id/api/tools/bypass', {
|
| 11 |
+
params: {
|
| 12 |
+
url: 'https://www.yeschat.ai/',
|
| 13 |
+
siteKey: '0x4AAAAAAATOXAtQtziH-Rwq',
|
| 14 |
+
type: 'turnstile-min',
|
| 15 |
+
apikey: 'freeApikey'
|
| 16 |
+
},
|
| 17 |
+
headers: {
|
| 18 |
+
'accept': '*/*'
|
| 19 |
+
}
|
| 20 |
+
});
|
| 21 |
+
|
| 22 |
+
if (response.data.success && response.data.data?.result?.token) {
|
| 23 |
+
return response.data.data.result.token;
|
| 24 |
+
}
|
| 25 |
+
throw new Error('Failed to get token from response');
|
| 26 |
+
} catch (error) {
|
| 27 |
+
throw new Error(`Failed to get bypass token: ${error.message}`);
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
async generateSongLyrics({
|
| 32 |
+
prompt,
|
| 33 |
+
title = "Tanpa Judul",
|
| 34 |
+
style = "Happy",
|
| 35 |
+
instrumental = false,
|
| 36 |
+
customMode = true,
|
| 37 |
+
}) {
|
| 38 |
+
const token = await this.getBypassToken();
|
| 39 |
+
if (!token || typeof token !== "string") {
|
| 40 |
+
throw new Error("Failed to get bypass token.");
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
const res = await axios.post(
|
| 44 |
+
"https://aiarticle.erweima.ai/api/v1/secondary-page/api/create",
|
| 45 |
+
{
|
| 46 |
+
prompt,
|
| 47 |
+
channel: "MUSIC",
|
| 48 |
+
id: 1018,
|
| 49 |
+
type: "features",
|
| 50 |
+
source: "yeschat.ai",
|
| 51 |
+
style,
|
| 52 |
+
title,
|
| 53 |
+
customMode,
|
| 54 |
+
instrumental,
|
| 55 |
+
},
|
| 56 |
+
{
|
| 57 |
+
headers: {
|
| 58 |
+
authority: "aiarticle.erweima.ai",
|
| 59 |
+
accept: "application/json, text/plain, */*",
|
| 60 |
+
"accept-language": "ms-MY,ms;q=0.9,en-US;q=0.8,en;q=0.7,id;q=0.6",
|
| 61 |
+
origin: "https://www.yeschat.ai",
|
| 62 |
+
referer: "https://www.yeschat.ai/",
|
| 63 |
+
"sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132"',
|
| 64 |
+
"sec-ch-ua-mobile": "?1",
|
| 65 |
+
"sec-ch-ua-platform": '"Android"',
|
| 66 |
+
"sec-fetch-dest": "empty",
|
| 67 |
+
"sec-fetch-mode": "cors",
|
| 68 |
+
"sec-fetch-site": "cross-site",
|
| 69 |
+
"user-agent": this.userAgent,
|
| 70 |
+
uniqueid: Date.now(),
|
| 71 |
+
verify: token,
|
| 72 |
+
},
|
| 73 |
+
}
|
| 74 |
+
);
|
| 75 |
+
|
| 76 |
+
if (res.data.code !== 200) {
|
| 77 |
+
throw new Error(res.data.msg || "Failed to generate lyrics");
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
const recordId = res.data?.data?.recordId;
|
| 81 |
+
return this.pollGeneratedResult(recordId);
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
pollGeneratedResult(recordId, interval = 5000) {
|
| 85 |
+
return new Promise((resolve, reject) => {
|
| 86 |
+
const url = `https://aiarticle.erweima.ai/api/v1/secondary-page/api/${recordId}`;
|
| 87 |
+
const timer = setInterval(async () => {
|
| 88 |
+
try {
|
| 89 |
+
const { data } = await axios.get(url, {
|
| 90 |
+
headers: {
|
| 91 |
+
authority: "aiarticle.erweima.ai",
|
| 92 |
+
accept: "application/json, text/plain, */*",
|
| 93 |
+
"accept-language": "ms-MY,ms;q=0.9,en-US;q=0.8,en;q=0.7,id;q=0.6",
|
| 94 |
+
origin: "https://www.yeschat.ai",
|
| 95 |
+
referer: "https://www.yeschat.ai/",
|
| 96 |
+
"sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132"',
|
| 97 |
+
"sec-ch-ua-mobile": "?1",
|
| 98 |
+
"sec-ch-ua-platform": '"Android"',
|
| 99 |
+
"sec-fetch-dest": "empty",
|
| 100 |
+
"sec-fetch-mode": "cors",
|
| 101 |
+
"sec-fetch-site": "cross-site",
|
| 102 |
+
"user-agent": this.userAgent,
|
| 103 |
+
},
|
| 104 |
+
});
|
| 105 |
+
|
| 106 |
+
if (data.code !== 200) {
|
| 107 |
+
clearInterval(timer);
|
| 108 |
+
return reject(new Error(data.msg || "Unexpected error"));
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
if (data.data?.failCode && data.data?.failMsg) {
|
| 112 |
+
clearInterval(timer);
|
| 113 |
+
return reject(new Error(data.data.failMsg));
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
if (data.data?.state && data.data.completeData) {
|
| 117 |
+
clearInterval(timer);
|
| 118 |
+
return resolve(JSON.parse(data.data.completeData));
|
| 119 |
+
}
|
| 120 |
+
} catch (err) {
|
| 121 |
+
clearInterval(timer);
|
| 122 |
+
return reject(err);
|
| 123 |
+
}
|
| 124 |
+
}, interval);
|
| 125 |
+
});
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
const handler = async (req, res) => {
|
| 130 |
+
try {
|
| 131 |
+
const { mode, prompt, lyrics, title, style, instrumental } = req.query;
|
| 132 |
+
|
| 133 |
+
if (!mode) {
|
| 134 |
+
return res.status(400).json({
|
| 135 |
+
success: false,
|
| 136 |
+
error: 'Missing required parameter: mode (custom/ai)'
|
| 137 |
+
});
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
const modeNormalized = mode.toLowerCase();
|
| 141 |
+
|
| 142 |
+
if (modeNormalized !== 'custom' && modeNormalized !== 'ai') {
|
| 143 |
+
return res.status(400).json({
|
| 144 |
+
success: false,
|
| 145 |
+
error: 'Invalid mode. Use "custom" for Custom Lyrics or "ai" for AI Lyrics'
|
| 146 |
+
});
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
let finalPrompt;
|
| 150 |
+
let customMode;
|
| 151 |
+
|
| 152 |
+
if (modeNormalized === 'custom') {
|
| 153 |
+
if (!lyrics) {
|
| 154 |
+
return res.status(400).json({
|
| 155 |
+
success: false,
|
| 156 |
+
error: 'Missing required parameter: lyrics (required for Custom Lyrics mode)'
|
| 157 |
+
});
|
| 158 |
+
}
|
| 159 |
+
finalPrompt = lyrics;
|
| 160 |
+
customMode = true;
|
| 161 |
+
} else {
|
| 162 |
+
if (!prompt) {
|
| 163 |
+
return res.status(400).json({
|
| 164 |
+
success: false,
|
| 165 |
+
error: 'Missing required parameter: prompt (required for AI Lyrics mode)'
|
| 166 |
+
});
|
| 167 |
+
}
|
| 168 |
+
finalPrompt = prompt;
|
| 169 |
+
customMode = false;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
const generator = new YesChatMusicGenerator();
|
| 173 |
+
|
| 174 |
+
const result = await generator.generateSongLyrics({
|
| 175 |
+
prompt: finalPrompt,
|
| 176 |
+
title: title || "Tanpa Judul",
|
| 177 |
+
style: style || "Happy",
|
| 178 |
+
instrumental: instrumental === 'true',
|
| 179 |
+
customMode: customMode
|
| 180 |
+
});
|
| 181 |
+
|
| 182 |
+
res.json({
|
| 183 |
+
author: "Herza",
|
| 184 |
+
success: true,
|
| 185 |
+
mode: modeNormalized === 'custom' ? 'Custom Lyrics' : 'AI Lyrics',
|
| 186 |
+
result: result
|
| 187 |
+
});
|
| 188 |
+
|
| 189 |
+
} catch (error) {
|
| 190 |
+
res.status(500).json({
|
| 191 |
+
success: false,
|
| 192 |
+
error: error.message
|
| 193 |
+
});
|
| 194 |
+
}
|
| 195 |
+
};
|
| 196 |
+
|
| 197 |
+
module.exports = {
|
| 198 |
+
name: 'SunoV2 Music Generator',
|
| 199 |
+
type: 'GET',
|
| 200 |
+
routes: ['api/AI/sunov2'],
|
| 201 |
+
tags: ['ai', 'music', 'generator'],
|
| 202 |
+
main: ['AI'],
|
| 203 |
+
limit: 12,
|
| 204 |
+
parameters: ['mode', 'prompt', 'lyrics', 'title', 'style', 'instrumental', 'key'],
|
| 205 |
+
enabled: true,
|
| 206 |
+
handler
|
| 207 |
+
};
|
plugins/sunov3.js
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require("axios");
|
| 2 |
+
const { v4: uuidv4 } = require("uuid");
|
| 3 |
+
|
| 4 |
+
function randomHex(length) {
|
| 5 |
+
const chars = "abcdef0123456789";
|
| 6 |
+
return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join("");
|
| 7 |
+
}
|
| 8 |
+
|
| 9 |
+
function gieneticTrace() {
|
| 10 |
+
return `${randomHex(32)}-${randomHex(16)}`;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
async function login(deviceId) {
|
| 14 |
+
const res = await axios.post(
|
| 15 |
+
"https://api.sunora.mavtao.com/api/auth/login",
|
| 16 |
+
{ device_id: deviceId },
|
| 17 |
+
{
|
| 18 |
+
headers: {
|
| 19 |
+
"user-agent": "Dart/3.4 (gienetic_build)",
|
| 20 |
+
"version": "2.2.2",
|
| 21 |
+
"accept-encoding": "gzip",
|
| 22 |
+
"content-type": "application/json",
|
| 23 |
+
"buildnumber": "105",
|
| 24 |
+
"platform": "android",
|
| 25 |
+
"sentry-trace": gieneticTrace()
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
);
|
| 29 |
+
return res.data?.data?.token || null;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
async function polllll(xAuth, maxAttempts = 30, delayMs = 30000) {
|
| 33 |
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
| 34 |
+
try {
|
| 35 |
+
const res = await axios.get(
|
| 36 |
+
"https://api.sunora.mavtao.com/api/music/music_page?page=1&pagesize=50",
|
| 37 |
+
{
|
| 38 |
+
headers: {
|
| 39 |
+
"user-agent": "Dart/3.4 (gienetic_build)",
|
| 40 |
+
"version": "2.2.2",
|
| 41 |
+
"accept-encoding": "gzip",
|
| 42 |
+
"x-auth": xAuth,
|
| 43 |
+
"buildnumber": "105",
|
| 44 |
+
"platform": "android",
|
| 45 |
+
"sentry-trace": gieneticTrace()
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
);
|
| 49 |
+
|
| 50 |
+
const records = res.data?.data?.records || [];
|
| 51 |
+
const doneSongs = records.filter(r => r.status === "complete");
|
| 52 |
+
|
| 53 |
+
if (doneSongs.length > 0) {
|
| 54 |
+
return doneSongs.map(r => ({
|
| 55 |
+
id: r.song_id,
|
| 56 |
+
title: r.title || "Sniff By: Gienetic",
|
| 57 |
+
tags: r.meta_tags,
|
| 58 |
+
prompt: r.meta_prompt,
|
| 59 |
+
audioUrl: r.audio_url,
|
| 60 |
+
videoUrl: r.video_url,
|
| 61 |
+
imageUrl: r.image_url,
|
| 62 |
+
model: r.model_name
|
| 63 |
+
}));
|
| 64 |
+
}
|
| 65 |
+
} catch (err) {
|
| 66 |
+
console.error("⚠️ Polling error:", err.response?.data || err.message);
|
| 67 |
+
}
|
| 68 |
+
await new Promise(r => setTimeout(r, delayMs));
|
| 69 |
+
}
|
| 70 |
+
return [];
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
async function generateNormal(description) {
|
| 74 |
+
const deviceId = uuidv4();
|
| 75 |
+
const token = await login(deviceId);
|
| 76 |
+
if (!token) throw new Error("⚠️ Error: gagal login (makanya tag author ny kalau recode :v)");
|
| 77 |
+
|
| 78 |
+
await axios.post(
|
| 79 |
+
"https://api.sunora.mavtao.com/api/music/advanced_custom_generate",
|
| 80 |
+
{
|
| 81 |
+
continue_at: null,
|
| 82 |
+
continue_clip_id: null,
|
| 83 |
+
mv: null,
|
| 84 |
+
description,
|
| 85 |
+
title: "",
|
| 86 |
+
mood: "",
|
| 87 |
+
music_style: "",
|
| 88 |
+
instrumental_only: false
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
headers: {
|
| 92 |
+
"user-agent": "Dart/3.4 (gienetic_build)",
|
| 93 |
+
"version": "2.2.2",
|
| 94 |
+
"accept-encoding": "gzip",
|
| 95 |
+
"x-auth": token,
|
| 96 |
+
"content-type": "application/json",
|
| 97 |
+
"buildnumber": "105",
|
| 98 |
+
"platform": "android",
|
| 99 |
+
"sentry-trace": gieneticTrace()
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
);
|
| 103 |
+
|
| 104 |
+
return await polllll(token);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
async function generateCustom({ title, style, lyrics }) {
|
| 108 |
+
const deviceId = uuidv4();
|
| 109 |
+
const token = await login(deviceId);
|
| 110 |
+
if (!token) throw new Error("⚠️ Error: gagal login (makanya tag author ny kalau recode :v)");
|
| 111 |
+
|
| 112 |
+
await axios.post(
|
| 113 |
+
"https://api.sunora.mavtao.com/api/music/custom_generate",
|
| 114 |
+
{
|
| 115 |
+
continue_at: null,
|
| 116 |
+
continue_clip_id: null,
|
| 117 |
+
mv: null,
|
| 118 |
+
prompt: lyrics,
|
| 119 |
+
title,
|
| 120 |
+
tags: style
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
headers: {
|
| 124 |
+
"user-agent": "Dart/3.4 (gienetic_build)",
|
| 125 |
+
"version": "2.2.2",
|
| 126 |
+
"accept-encoding": "gzip",
|
| 127 |
+
"x-auth": token,
|
| 128 |
+
"content-type": "application/json",
|
| 129 |
+
"buildnumber": "105",
|
| 130 |
+
"platform": "android",
|
| 131 |
+
"sentry-trace": gieneticTrace()
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
);
|
| 135 |
+
|
| 136 |
+
return await polllll(token);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
async function generateInstrumental(description) {
|
| 140 |
+
const deviceId = uuidv4();
|
| 141 |
+
const token = await login(deviceId);
|
| 142 |
+
if (!token) throw new Error("⚠️ Error: gagal login (makanya tag author ny kalau recode :v)");
|
| 143 |
+
|
| 144 |
+
await axios.post(
|
| 145 |
+
"https://api.sunora.mavtao.com/api/music/advanced_custom_generate",
|
| 146 |
+
{
|
| 147 |
+
continue_at: null,
|
| 148 |
+
continue_clip_id: null,
|
| 149 |
+
mv: null,
|
| 150 |
+
description,
|
| 151 |
+
title: "",
|
| 152 |
+
mood: "",
|
| 153 |
+
music_style: "",
|
| 154 |
+
instrumental_only: true
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
headers: {
|
| 158 |
+
"user-agent": "Dart/3.4 (gienetic_build)",
|
| 159 |
+
"version": "2.2.2",
|
| 160 |
+
"accept-encoding": "gzip",
|
| 161 |
+
"x-auth": token,
|
| 162 |
+
"content-type": "application/json",
|
| 163 |
+
"buildnumber": "105",
|
| 164 |
+
"platform": "android",
|
| 165 |
+
"sentry-trace": gieneticTrace()
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
);
|
| 169 |
+
|
| 170 |
+
return await polllll(token);
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
const handler = async (req, res) => {
|
| 174 |
+
try {
|
| 175 |
+
const { mode, description, title, style, lyrics } = req.query;
|
| 176 |
+
|
| 177 |
+
if (!mode) {
|
| 178 |
+
return res.status(400).json({
|
| 179 |
+
success: false,
|
| 180 |
+
error: 'Missing required parameter: mode (normal/custom/instrumental)'
|
| 181 |
+
});
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
const modeNormalized = mode.toLowerCase();
|
| 185 |
+
|
| 186 |
+
if (!['normal', 'custom', 'instrumental'].includes(modeNormalized)) {
|
| 187 |
+
return res.status(400).json({
|
| 188 |
+
success: false,
|
| 189 |
+
error: 'Invalid mode. Use "normal", "custom", or "instrumental"'
|
| 190 |
+
});
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
let result;
|
| 194 |
+
|
| 195 |
+
if (modeNormalized === 'normal') {
|
| 196 |
+
if (!description) {
|
| 197 |
+
return res.status(400).json({
|
| 198 |
+
success: false,
|
| 199 |
+
error: 'Missing required parameter: description (required for normal mode)'
|
| 200 |
+
});
|
| 201 |
+
}
|
| 202 |
+
result = await generateNormal(description);
|
| 203 |
+
} else if (modeNormalized === 'custom') {
|
| 204 |
+
if (!title || !style || !lyrics) {
|
| 205 |
+
return res.status(400).json({
|
| 206 |
+
success: false,
|
| 207 |
+
error: 'Missing required parameters: title, style, lyrics (required for custom mode)'
|
| 208 |
+
});
|
| 209 |
+
}
|
| 210 |
+
result = await generateCustom({ title, style, lyrics });
|
| 211 |
+
} else if (modeNormalized === 'instrumental') {
|
| 212 |
+
if (!description) {
|
| 213 |
+
return res.status(400).json({
|
| 214 |
+
success: false,
|
| 215 |
+
error: 'Missing required parameter: description (required for instrumental mode)'
|
| 216 |
+
});
|
| 217 |
+
}
|
| 218 |
+
result = await generateInstrumental(description);
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
if (!result || result.length === 0) {
|
| 222 |
+
return res.status(500).json({
|
| 223 |
+
success: false,
|
| 224 |
+
error: 'Failed to generate music or timeout'
|
| 225 |
+
});
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
res.json({
|
| 229 |
+
author: "Herza",
|
| 230 |
+
success: true,
|
| 231 |
+
mode: modeNormalized,
|
| 232 |
+
result: result
|
| 233 |
+
});
|
| 234 |
+
|
| 235 |
+
} catch (error) {
|
| 236 |
+
res.status(500).json({
|
| 237 |
+
success: false,
|
| 238 |
+
error: error.message
|
| 239 |
+
});
|
| 240 |
+
}
|
| 241 |
+
};
|
| 242 |
+
|
| 243 |
+
module.exports = {
|
| 244 |
+
name: 'Suno V3 Music Generator',
|
| 245 |
+
description: 'Generate music using Suno V3 AI with multiple modes',
|
| 246 |
+
type: 'GET',
|
| 247 |
+
routes: ['api/AI/sunov3'],
|
| 248 |
+
tags: ['ai', 'music', 'suno', 'generator'],
|
| 249 |
+
main: ['AI'],
|
| 250 |
+
parameters: ['mode', 'description', 'title', 'style', 'lyrics', 'key'],
|
| 251 |
+
enabled: true,
|
| 252 |
+
limit: 15,
|
| 253 |
+
handler
|
| 254 |
+
};
|
plugins/terabox.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { url } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!url) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: url'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const match = url.match(/\/s\/([^/?#]+)/);
|
| 15 |
+
if (!match || !match[1]) {
|
| 16 |
+
return res.status(400).json({
|
| 17 |
+
success: false,
|
| 18 |
+
error: 'Invalid URL format'
|
| 19 |
+
});
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
const id = match[1];
|
| 23 |
+
const { data } = await axios.get(`https://tera2.sylyt93.workers.dev/info?s=${id}`);
|
| 24 |
+
|
| 25 |
+
res.json({
|
| 26 |
+
author: "Herza",
|
| 27 |
+
success: data.status === 'ok',
|
| 28 |
+
data: data.status === 'ok' ? {
|
| 29 |
+
file: data.file,
|
| 30 |
+
dlink: data.dlink
|
| 31 |
+
} : {}
|
| 32 |
+
});
|
| 33 |
+
|
| 34 |
+
} catch (error) {
|
| 35 |
+
res.status(500).json({
|
| 36 |
+
success: false,
|
| 37 |
+
error: error.message
|
| 38 |
+
});
|
| 39 |
+
}
|
| 40 |
+
};
|
| 41 |
+
|
| 42 |
+
module.exports = {
|
| 43 |
+
name: 'TeraBox DL',
|
| 44 |
+
description: 'Auto extract ID and get file info from TeraBox URL',
|
| 45 |
+
type: 'GET',
|
| 46 |
+
routes: ['api/download/terabox'],
|
| 47 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 48 |
+
parameters: ['url', 'key'],
|
| 49 |
+
enabled: true,
|
| 50 |
+
main: ['Downloader'],
|
| 51 |
+
handler
|
| 52 |
+
};
|
plugins/text2img.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios')
|
| 2 |
+
const FormData = require('form-data')
|
| 3 |
+
const fetch = require('node-fetch')
|
| 4 |
+
|
| 5 |
+
const handler = async (req, res) => {
|
| 6 |
+
try {
|
| 7 |
+
const { text } = req.query;
|
| 8 |
+
|
| 9 |
+
if (!text) {
|
| 10 |
+
return res.status(400).json({
|
| 11 |
+
success: false,
|
| 12 |
+
error: 'Missing required parameter: text'
|
| 13 |
+
});
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
let result = await axios.get(`https://ab-text-toimgfast.abrahamdw882.workers.dev/?text=${encodeURIComponent(text)}`, {
|
| 17 |
+
responseType: 'arraybuffer'
|
| 18 |
+
})
|
| 19 |
+
|
| 20 |
+
let buffer = Buffer.from(result.data)
|
| 21 |
+
|
| 22 |
+
let form = new FormData()
|
| 23 |
+
form.append('file', buffer, {
|
| 24 |
+
filename: 'image.webp',
|
| 25 |
+
contentType: 'image/webp'
|
| 26 |
+
})
|
| 27 |
+
|
| 28 |
+
let uploadRes = await fetch('https://tmpfiles.org/api/v1/upload', {
|
| 29 |
+
method: 'POST',
|
| 30 |
+
body: form
|
| 31 |
+
})
|
| 32 |
+
|
| 33 |
+
let uploadData = await uploadRes.json()
|
| 34 |
+
let fileUrl = uploadData.data.url.replace('tmpfiles.org/', 'tmpfiles.org/dl/')
|
| 35 |
+
|
| 36 |
+
res.json({
|
| 37 |
+
author: "Herza",
|
| 38 |
+
success: true,
|
| 39 |
+
url: fileUrl
|
| 40 |
+
});
|
| 41 |
+
|
| 42 |
+
} catch (error) {
|
| 43 |
+
res.status(500).json({
|
| 44 |
+
success: false,
|
| 45 |
+
error: error.message
|
| 46 |
+
});
|
| 47 |
+
}
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
module.exports = {
|
| 51 |
+
name: 'Text2IMG AI',
|
| 52 |
+
description: 'Generate Image using OpenAI ChatGPT',
|
| 53 |
+
type: 'GET',
|
| 54 |
+
routes: ['api/AI/text2img'],
|
| 55 |
+
tags: ['ai', 'text2img', 'openai'],
|
| 56 |
+
main: ['AI'],
|
| 57 |
+
parameters: ['text'],
|
| 58 |
+
enabled: true,
|
| 59 |
+
handler
|
| 60 |
+
};
|
plugins/text2video.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const FormData = require('form-data');
|
| 3 |
+
|
| 4 |
+
const aiLabs = {
|
| 5 |
+
api: {
|
| 6 |
+
base: 'https://text2video.aritek.app',
|
| 7 |
+
endpoints: {
|
| 8 |
+
text2img: '/text2img',
|
| 9 |
+
generate: '/txt2videov3',
|
| 10 |
+
video: '/video'
|
| 11 |
+
}
|
| 12 |
+
},
|
| 13 |
+
|
| 14 |
+
headers: {
|
| 15 |
+
'user-agent': 'NB Android/1.0.0',
|
| 16 |
+
'accept-encoding': 'gzip',
|
| 17 |
+
'content-type': 'application/json',
|
| 18 |
+
authorization: ''
|
| 19 |
+
},
|
| 20 |
+
|
| 21 |
+
state: {
|
| 22 |
+
token: null
|
| 23 |
+
},
|
| 24 |
+
|
| 25 |
+
setup: {
|
| 26 |
+
cipher: 'hbMcgZLlzvghRlLbPcTbCpfcQKM0PcU0zhPcTlOFMxBZ1oLmruzlVp9remPgi0QWP0QW',
|
| 27 |
+
shiftValue: 3,
|
| 28 |
+
|
| 29 |
+
dec(text, shift) {
|
| 30 |
+
return [...text].map(c =>
|
| 31 |
+
/[a-z]/.test(c)
|
| 32 |
+
? String.fromCharCode((c.charCodeAt(0) - 97 - shift + 26) % 26 + 97)
|
| 33 |
+
: /[A-Z]/.test(c)
|
| 34 |
+
? String.fromCharCode((c.charCodeAt(0) - 65 - shift + 26) % 26 + 65)
|
| 35 |
+
: c
|
| 36 |
+
).join('');
|
| 37 |
+
},
|
| 38 |
+
|
| 39 |
+
decrypt: async () => {
|
| 40 |
+
if (aiLabs.state.token) return aiLabs.state.token;
|
| 41 |
+
|
| 42 |
+
const input = aiLabs.setup.cipher;
|
| 43 |
+
const shift = aiLabs.setup.shiftValue;
|
| 44 |
+
const decrypted = aiLabs.setup.dec(input, shift);
|
| 45 |
+
|
| 46 |
+
aiLabs.state.token = decrypted;
|
| 47 |
+
aiLabs.headers.authorization = decrypted;
|
| 48 |
+
return decrypted;
|
| 49 |
+
}
|
| 50 |
+
},
|
| 51 |
+
|
| 52 |
+
deviceId() {
|
| 53 |
+
return Array.from({ length: 16 }, () =>
|
| 54 |
+
Math.floor(Math.random() * 16).toString(16)
|
| 55 |
+
).join('');
|
| 56 |
+
},
|
| 57 |
+
|
| 58 |
+
text2img: async (prompt) => {
|
| 59 |
+
if (!prompt?.trim()) {
|
| 60 |
+
return {
|
| 61 |
+
success: false,
|
| 62 |
+
code: 400,
|
| 63 |
+
result: {
|
| 64 |
+
error: 'Yang bener aja anjirr, inputnya kosong begitu 🗿'
|
| 65 |
+
}
|
| 66 |
+
};
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
const token = await aiLabs.setup.decrypt();
|
| 70 |
+
const form = new FormData();
|
| 71 |
+
form.append('prompt', prompt);
|
| 72 |
+
form.append('token', token);
|
| 73 |
+
|
| 74 |
+
try {
|
| 75 |
+
const url = aiLabs.api.base + aiLabs.api.endpoints.text2img;
|
| 76 |
+
const res = await axios.post(url, form, {
|
| 77 |
+
headers: {
|
| 78 |
+
...aiLabs.headers,
|
| 79 |
+
...form.getHeaders()
|
| 80 |
+
}
|
| 81 |
+
});
|
| 82 |
+
|
| 83 |
+
const { code, url: imageUrl } = res.data;
|
| 84 |
+
if (code !== 0 || !imageUrl) {
|
| 85 |
+
return {
|
| 86 |
+
success: false,
|
| 87 |
+
code: res.status,
|
| 88 |
+
result: {
|
| 89 |
+
error: 'Error bree 😂'
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
return {
|
| 95 |
+
success: true,
|
| 96 |
+
code: res.status,
|
| 97 |
+
result: {
|
| 98 |
+
url: imageUrl.trim(),
|
| 99 |
+
prompt
|
| 100 |
+
}
|
| 101 |
+
};
|
| 102 |
+
} catch (err) {
|
| 103 |
+
return {
|
| 104 |
+
success: false,
|
| 105 |
+
code: err.response?.status || 500,
|
| 106 |
+
result: {
|
| 107 |
+
error: err.message || 'Error bree 😂'
|
| 108 |
+
}
|
| 109 |
+
};
|
| 110 |
+
}
|
| 111 |
+
},
|
| 112 |
+
|
| 113 |
+
generate: async ({ prompt = '', type = 'video', isPremium = 1 } = {}) => {
|
| 114 |
+
if (!prompt?.trim() || !/^[a-zA-Z0-9\s.,!?'-]+$/.test(prompt)) {
|
| 115 |
+
return {
|
| 116 |
+
success: false,
|
| 117 |
+
code: 400,
|
| 118 |
+
result: {
|
| 119 |
+
error: 'Promptnya kagak boleh kosong bree.. apalagi ada karakternya aneh begitu :v kagak boleh yak 😂'
|
| 120 |
+
}
|
| 121 |
+
};
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
if (!/^(image|video)$/.test(type)) {
|
| 125 |
+
return {
|
| 126 |
+
success: false,
|
| 127 |
+
code: 400,
|
| 128 |
+
result: {
|
| 129 |
+
error: 'Tipenya kagak valid.. lu bisa pake image atau video yak.. ☺️'
|
| 130 |
+
}
|
| 131 |
+
};
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
if (type === 'image') {
|
| 135 |
+
return await aiLabs.text2img(prompt);
|
| 136 |
+
} else {
|
| 137 |
+
await aiLabs.setup.decrypt();
|
| 138 |
+
const payload = {
|
| 139 |
+
deviceID: aiLabs.deviceId(),
|
| 140 |
+
isPremium,
|
| 141 |
+
prompt,
|
| 142 |
+
used: [],
|
| 143 |
+
versionCode: 59
|
| 144 |
+
};
|
| 145 |
+
|
| 146 |
+
try {
|
| 147 |
+
const url = aiLabs.api.base + aiLabs.api.endpoints.generate;
|
| 148 |
+
const res = await axios.post(url, payload, { headers: aiLabs.headers });
|
| 149 |
+
|
| 150 |
+
const { code, key } = res.data;
|
| 151 |
+
if (code !== 0 || !key || typeof key !== 'string') {
|
| 152 |
+
return {
|
| 153 |
+
success: false,
|
| 154 |
+
code: res.status,
|
| 155 |
+
result: {
|
| 156 |
+
error: 'Heumm.. Gagal bree ngambil Keynya 🫵🏻🐷'
|
| 157 |
+
}
|
| 158 |
+
};
|
| 159 |
+
}
|
| 160 |
+
return await aiLabs.video(key);
|
| 161 |
+
} catch (err) {
|
| 162 |
+
return {
|
| 163 |
+
success: false,
|
| 164 |
+
code: err.response?.status || 500,
|
| 165 |
+
result: {
|
| 166 |
+
error: err.message || 'Error bree... 😂'
|
| 167 |
+
}
|
| 168 |
+
};
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
},
|
| 172 |
+
|
| 173 |
+
video: async (key) => {
|
| 174 |
+
if (!key || typeof key !== 'string') {
|
| 175 |
+
return {
|
| 176 |
+
success: false,
|
| 177 |
+
code: 400,
|
| 178 |
+
result: {
|
| 179 |
+
error: 'Keynya kagak valid bree... 😏😂'
|
| 180 |
+
}
|
| 181 |
+
};
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
await aiLabs.setup.decrypt();
|
| 185 |
+
const payload = { keys: [key] };
|
| 186 |
+
const url = aiLabs.api.base + aiLabs.api.endpoints.video;
|
| 187 |
+
const maxAttempts = 100;
|
| 188 |
+
const delay = 2000;
|
| 189 |
+
let attempt = 0;
|
| 190 |
+
|
| 191 |
+
while (attempt < maxAttempts) {
|
| 192 |
+
attempt++;
|
| 193 |
+
try {
|
| 194 |
+
const res = await axios.post(url, payload, {
|
| 195 |
+
headers: aiLabs.headers,
|
| 196 |
+
timeout: 15000
|
| 197 |
+
});
|
| 198 |
+
|
| 199 |
+
const { code, datas } = res.data;
|
| 200 |
+
if (code === 0 && Array.isArray(datas) && datas.length > 0) {
|
| 201 |
+
const data = datas[0];
|
| 202 |
+
if (!data.url || data.url.trim() === '') {
|
| 203 |
+
await new Promise(r => setTimeout(r, delay));
|
| 204 |
+
continue;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
return {
|
| 208 |
+
success: true,
|
| 209 |
+
code: res.status,
|
| 210 |
+
result: {
|
| 211 |
+
url: data.url.trim(),
|
| 212 |
+
safe: data.safe === 'true',
|
| 213 |
+
key: data.key,
|
| 214 |
+
progress: '100%'
|
| 215 |
+
}
|
| 216 |
+
};
|
| 217 |
+
}
|
| 218 |
+
} catch (err) {
|
| 219 |
+
const retry = ['ECONNRESET', 'ECONNABORTED', 'ETIMEDOUT'].includes(err.code);
|
| 220 |
+
if (retry && attempt < maxAttempts) {
|
| 221 |
+
await new Promise(r => setTimeout(r, delay));
|
| 222 |
+
continue;
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
return {
|
| 226 |
+
success: false,
|
| 227 |
+
code: err.response?.status || 500,
|
| 228 |
+
result: {
|
| 229 |
+
error: 'Error bree...',
|
| 230 |
+
attempt
|
| 231 |
+
}
|
| 232 |
+
};
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
return {
|
| 237 |
+
success: false,
|
| 238 |
+
code: 504,
|
| 239 |
+
result: {
|
| 240 |
+
error: 'Proses videonya kelamaan, keknya lagi ngambek tuh Server AI nya wkwk... ',
|
| 241 |
+
attempt
|
| 242 |
+
}
|
| 243 |
+
};
|
| 244 |
+
}
|
| 245 |
+
};
|
| 246 |
+
|
| 247 |
+
const handler = async (req, res) => {
|
| 248 |
+
try {
|
| 249 |
+
const { prompt } = req.query;
|
| 250 |
+
|
| 251 |
+
if (!prompt) {
|
| 252 |
+
return res.status(400).json({
|
| 253 |
+
success: false,
|
| 254 |
+
error: 'Missing required parameter: prompt'
|
| 255 |
+
});
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
const result = await aiLabs.generate({
|
| 259 |
+
prompt: prompt,
|
| 260 |
+
type: 'video',
|
| 261 |
+
isPremium: 1
|
| 262 |
+
});
|
| 263 |
+
|
| 264 |
+
if (!result.success) {
|
| 265 |
+
return res.status(result.code).json({
|
| 266 |
+
author: "Herza",
|
| 267 |
+
success: false,
|
| 268 |
+
error: result.result.error
|
| 269 |
+
});
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
res.json({
|
| 273 |
+
author: "Herza",
|
| 274 |
+
success: true,
|
| 275 |
+
result: result.result
|
| 276 |
+
});
|
| 277 |
+
|
| 278 |
+
} catch (error) {
|
| 279 |
+
res.status(500).json({
|
| 280 |
+
success: false,
|
| 281 |
+
error: error.message
|
| 282 |
+
});
|
| 283 |
+
}
|
| 284 |
+
};
|
| 285 |
+
|
| 286 |
+
module.exports = {
|
| 287 |
+
name: 'AI Labs Text to Video',
|
| 288 |
+
description: 'Generate video from text prompt using AI Labs',
|
| 289 |
+
type: 'GET',
|
| 290 |
+
routes: ['api/AI/text2video'],
|
| 291 |
+
tags: ['ai', 'video', 'text-to-video', 'generator'],
|
| 292 |
+
main: ['AI'],
|
| 293 |
+
parameters: ['prompt', 'key'],
|
| 294 |
+
enabled: true,
|
| 295 |
+
handler
|
| 296 |
+
};
|
plugins/threads.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function threads(url) {
|
| 4 |
+
try {
|
| 5 |
+
const response = await axios.get('https://api.threadsphotodownloader.com/v2/media', {
|
| 6 |
+
params: {
|
| 7 |
+
url: url
|
| 8 |
+
},
|
| 9 |
+
headers: {
|
| 10 |
+
'Accept': '*/*',
|
| 11 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
| 12 |
+
}
|
| 13 |
+
});
|
| 14 |
+
|
| 15 |
+
const data = response.data;
|
| 16 |
+
|
| 17 |
+
if (!data.image_urls && !data.video_urls) {
|
| 18 |
+
return {
|
| 19 |
+
author: 'Herza',
|
| 20 |
+
status: 400,
|
| 21 |
+
data: {
|
| 22 |
+
error: true,
|
| 23 |
+
message: 'No media found'
|
| 24 |
+
}
|
| 25 |
+
};
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
return {
|
| 29 |
+
author: 'Herza',
|
| 30 |
+
status: 200,
|
| 31 |
+
data: {
|
| 32 |
+
images: data.image_urls || [],
|
| 33 |
+
videos: data.video_urls || []
|
| 34 |
+
}
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
} catch (error) {
|
| 38 |
+
return {
|
| 39 |
+
author: 'Herza',
|
| 40 |
+
status: 500,
|
| 41 |
+
data: {
|
| 42 |
+
error: true,
|
| 43 |
+
message: error.message
|
| 44 |
+
}
|
| 45 |
+
};
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
const handler = async (req, res) => {
|
| 50 |
+
try {
|
| 51 |
+
const { url } = req.query;
|
| 52 |
+
|
| 53 |
+
if (!url) {
|
| 54 |
+
return res.status(400).json({
|
| 55 |
+
success: false,
|
| 56 |
+
error: 'Missing required parameter: url'
|
| 57 |
+
});
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
const result = await threads(url);
|
| 61 |
+
|
| 62 |
+
if (result.status !== 200) {
|
| 63 |
+
return res.status(result.status).json({
|
| 64 |
+
success: false,
|
| 65 |
+
error: result.data.message
|
| 66 |
+
});
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
res.json({
|
| 70 |
+
author: "Herza",
|
| 71 |
+
success: true,
|
| 72 |
+
msg: result.data
|
| 73 |
+
});
|
| 74 |
+
|
| 75 |
+
} catch (error) {
|
| 76 |
+
res.status(500).json({
|
| 77 |
+
success: false,
|
| 78 |
+
error: error.message
|
| 79 |
+
});
|
| 80 |
+
}
|
| 81 |
+
};
|
| 82 |
+
|
| 83 |
+
module.exports = {
|
| 84 |
+
name: 'Threads DL',
|
| 85 |
+
description: 'Download Threads Media',
|
| 86 |
+
type: 'GET',
|
| 87 |
+
routes: ['api/download/threads'],
|
| 88 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 89 |
+
parameters: ['url', 'key'],
|
| 90 |
+
enabled: true,
|
| 91 |
+
main: ['Downloader'],
|
| 92 |
+
handler
|
| 93 |
+
}
|
plugins/tiktok.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const { tiktok } = require('notmebotz-tools');
|
| 2 |
+
|
| 3 |
+
const handler = async (req, res) => {
|
| 4 |
+
try {
|
| 5 |
+
const { url } = req.query;
|
| 6 |
+
|
| 7 |
+
if (!url) {
|
| 8 |
+
return res.status(400).json({
|
| 9 |
+
success: false,
|
| 10 |
+
error: 'Missing required parameter: url'
|
| 11 |
+
});
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
const result = await tiktok(url);
|
| 15 |
+
res.json({
|
| 16 |
+
author: "Herza",
|
| 17 |
+
success: true,
|
| 18 |
+
msg: result.data
|
| 19 |
+
});
|
| 20 |
+
|
| 21 |
+
} catch (error) {
|
| 22 |
+
res.status(500).json({
|
| 23 |
+
success: false,
|
| 24 |
+
error: error.message
|
| 25 |
+
});
|
| 26 |
+
}
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
module.exports = {
|
| 30 |
+
name: 'TikTok DL',
|
| 31 |
+
description: 'Download TikTok Video Without WM',
|
| 32 |
+
type: 'GET',
|
| 33 |
+
routes: ['api/download/tiktok'],
|
| 34 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 35 |
+
parameters: ['url', 'key'],
|
| 36 |
+
enabled: true,
|
| 37 |
+
main: ['Downloader'],
|
| 38 |
+
handler
|
| 39 |
+
}
|
plugins/ttstalk.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const cheerio = require('cheerio');
|
| 3 |
+
const { shannz: cf } = require('bycf');
|
| 4 |
+
|
| 5 |
+
async function getTurnstileToken() {
|
| 6 |
+
try {
|
| 7 |
+
const token = await cf.turnstileMin(
|
| 8 |
+
"https://claptools.com/tiktok-profile-viewer/",
|
| 9 |
+
"0x4AAAAAAA0aU62HwPRV0j1U"
|
| 10 |
+
);
|
| 11 |
+
return token;
|
| 12 |
+
} catch (error) {
|
| 13 |
+
throw new Error("Gagal mendapatkan Turnstile token: " + error.message);
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
async function getNonce() {
|
| 18 |
+
const response = await axios.get('https://claptools.com/tiktok-profile-viewer/', {
|
| 19 |
+
headers: {
|
| 20 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
| 21 |
+
}
|
| 22 |
+
});
|
| 23 |
+
|
| 24 |
+
const $ = cheerio.load(response.data);
|
| 25 |
+
const nonce = $('input[name="tt_nonce"]').val();
|
| 26 |
+
return nonce;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
async function tiktokStalk(username) {
|
| 30 |
+
const token = await getTurnstileToken();
|
| 31 |
+
const nonce = await getNonce();
|
| 32 |
+
|
| 33 |
+
const formData = new URLSearchParams();
|
| 34 |
+
formData.append('username', username);
|
| 35 |
+
formData.append('tt_nonce', nonce);
|
| 36 |
+
formData.append('cf-turnstile-response', token);
|
| 37 |
+
|
| 38 |
+
const response = await axios.post('https://claptools.com/tiktok-profile-viewer/', formData, {
|
| 39 |
+
headers: {
|
| 40 |
+
'Content-Type': 'application/x-www-form-urlencoded',
|
| 41 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 42 |
+
'Referer': 'https://claptools.com/tiktok-profile-viewer/',
|
| 43 |
+
'Origin': 'https://claptools.com'
|
| 44 |
+
}
|
| 45 |
+
});
|
| 46 |
+
|
| 47 |
+
const $ = cheerio.load(response.data);
|
| 48 |
+
|
| 49 |
+
const avatar = $('.profile img').attr('src');
|
| 50 |
+
const fullText = $('.profile-details h2').text().trim();
|
| 51 |
+
const bio = $('.profile-details p').text().trim();
|
| 52 |
+
|
| 53 |
+
const nameMatch = fullText.match(/^(.+?)\s*\(@(.+?)\)$/);
|
| 54 |
+
const nickname = nameMatch ? nameMatch[1].trim() : '';
|
| 55 |
+
const usernameFromPage = nameMatch ? nameMatch[2].trim() : username;
|
| 56 |
+
|
| 57 |
+
const followers = $('.stats .box').eq(0).find('.number').text().trim();
|
| 58 |
+
const likes = $('.stats .box').eq(1).find('.number').text().trim();
|
| 59 |
+
const videos = $('.stats .box').eq(2).find('.number').text().trim();
|
| 60 |
+
|
| 61 |
+
const videoList = [];
|
| 62 |
+
$('.thumb').each((i, elem) => {
|
| 63 |
+
const thumbnail = $(elem).find('img').attr('src');
|
| 64 |
+
if (thumbnail) {
|
| 65 |
+
videoList.push({
|
| 66 |
+
thumbnail: thumbnail
|
| 67 |
+
});
|
| 68 |
+
}
|
| 69 |
+
});
|
| 70 |
+
|
| 71 |
+
return {
|
| 72 |
+
username: usernameFromPage,
|
| 73 |
+
nickname: nickname,
|
| 74 |
+
bio: bio,
|
| 75 |
+
avatar: avatar,
|
| 76 |
+
stats: {
|
| 77 |
+
followers: followers,
|
| 78 |
+
likes: likes,
|
| 79 |
+
videos: videos
|
| 80 |
+
},
|
| 81 |
+
videoList: videoList
|
| 82 |
+
};
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
const handler = async (req, res) => {
|
| 86 |
+
try {
|
| 87 |
+
const { username } = req.query;
|
| 88 |
+
|
| 89 |
+
if (!username) {
|
| 90 |
+
return res.status(400).json({
|
| 91 |
+
success: false,
|
| 92 |
+
error: 'Missing required parameter: username'
|
| 93 |
+
});
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
const usernameRegex = /^[a-zA-Z0-9._]{1,24}$/;
|
| 97 |
+
if (!usernameRegex.test(username)) {
|
| 98 |
+
return res.status(400).json({
|
| 99 |
+
success: false,
|
| 100 |
+
error: 'Invalid username format'
|
| 101 |
+
});
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
const result = await tiktokStalk(username);
|
| 105 |
+
|
| 106 |
+
res.json({
|
| 107 |
+
author: "Herza",
|
| 108 |
+
success: true,
|
| 109 |
+
data: result
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
} catch (error) {
|
| 113 |
+
res.status(500).json({
|
| 114 |
+
author: "Herza",
|
| 115 |
+
success: false,
|
| 116 |
+
error: error.message
|
| 117 |
+
});
|
| 118 |
+
}
|
| 119 |
+
};
|
| 120 |
+
|
| 121 |
+
module.exports = {
|
| 122 |
+
name: 'TikTok Stalk',
|
| 123 |
+
description: 'Get TikTok user profile information including stats and avatar',
|
| 124 |
+
type: 'GET',
|
| 125 |
+
routes: ['api/stalk/tiktok'],
|
| 126 |
+
tags: ['social', 'tiktok', 'stalk', 'profile'],
|
| 127 |
+
parameters: ['username', 'key'],
|
| 128 |
+
enabled: true,
|
| 129 |
+
main: ['Stalk'],
|
| 130 |
+
handler
|
| 131 |
+
};
|
plugins/twitter.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
const cheerio = require('cheerio');
|
| 3 |
+
const crypto = require('crypto');
|
| 4 |
+
|
| 5 |
+
async function twitterDownloader(url) {
|
| 6 |
+
try {
|
| 7 |
+
const urlParams = new URLSearchParams(url.split('?')[1]);
|
| 8 |
+
const tweetUrl = urlParams.get('url') || url;
|
| 9 |
+
const decodedUrl = decodeURIComponent(tweetUrl);
|
| 10 |
+
|
| 11 |
+
const timestamp = Math.floor(Date.now() / 1000);
|
| 12 |
+
const hash = crypto.createHash('md5');
|
| 13 |
+
hash.update(timestamp.toString() + 'ssstwitter');
|
| 14 |
+
const tt = hash.digest('hex');
|
| 15 |
+
|
| 16 |
+
const postData = new URLSearchParams({
|
| 17 |
+
'id': decodedUrl,
|
| 18 |
+
'locale': 'en',
|
| 19 |
+
'tt': tt,
|
| 20 |
+
'ts': timestamp.toString(),
|
| 21 |
+
'source': 'form'
|
| 22 |
+
});
|
| 23 |
+
|
| 24 |
+
const { data: html } = await axios.post('https://ssstwitter.com/', postData, {
|
| 25 |
+
headers: {
|
| 26 |
+
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
| 27 |
+
'HX-Request': 'true',
|
| 28 |
+
'HX-Target': 'target',
|
| 29 |
+
'HX-Current-URL': 'https://ssstwitter.com/en-2',
|
| 30 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
| 31 |
+
'Origin': 'https://ssstwitter.com',
|
| 32 |
+
'Referer': 'https://ssstwitter.com/en-2'
|
| 33 |
+
}
|
| 34 |
+
});
|
| 35 |
+
|
| 36 |
+
const $ = cheerio.load(html);
|
| 37 |
+
const title = $('h2').first().text().trim();
|
| 38 |
+
const downloads = [];
|
| 39 |
+
|
| 40 |
+
$('.download-btn').each((i, elem) => {
|
| 41 |
+
const $elem = $(elem);
|
| 42 |
+
const downloadUrl = $elem.attr('href');
|
| 43 |
+
const qualityText = $elem.find('span').text().trim();
|
| 44 |
+
const quality = qualityText.replace('Download', '').trim();
|
| 45 |
+
|
| 46 |
+
if (downloadUrl && downloadUrl.startsWith('http')) {
|
| 47 |
+
downloads.push({
|
| 48 |
+
quality: quality,
|
| 49 |
+
url: downloadUrl
|
| 50 |
+
});
|
| 51 |
+
}
|
| 52 |
+
});
|
| 53 |
+
|
| 54 |
+
const mediaType = downloads.length > 0 ? 'video' : 'unknown';
|
| 55 |
+
const hdDownload = downloads.find(d => d.quality.includes('HD')) || downloads[0];
|
| 56 |
+
|
| 57 |
+
return {
|
| 58 |
+
title: title || 'Twitter Media',
|
| 59 |
+
mediaType: mediaType,
|
| 60 |
+
downloads: downloads,
|
| 61 |
+
hdUrl: hdDownload ? hdDownload.url : null,
|
| 62 |
+
hdQuality: hdDownload ? hdDownload.quality : null
|
| 63 |
+
};
|
| 64 |
+
|
| 65 |
+
} catch (error) {
|
| 66 |
+
throw new Error(error.message);
|
| 67 |
+
}
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
const handler = async (req, res) => {
|
| 71 |
+
try {
|
| 72 |
+
const { url } = req.query;
|
| 73 |
+
if (!url) {
|
| 74 |
+
return res.status(400).json({
|
| 75 |
+
success: false,
|
| 76 |
+
error: 'Missing required parameter: url'
|
| 77 |
+
});
|
| 78 |
+
}
|
| 79 |
+
const result = await twitterDownloader(url);
|
| 80 |
+
res.json({
|
| 81 |
+
author: "Herza",
|
| 82 |
+
success: true,
|
| 83 |
+
msg: result
|
| 84 |
+
});
|
| 85 |
+
} catch (error) {
|
| 86 |
+
res.status(500).json({
|
| 87 |
+
success: false,
|
| 88 |
+
error: error.message
|
| 89 |
+
});
|
| 90 |
+
}
|
| 91 |
+
};
|
| 92 |
+
|
| 93 |
+
module.exports = {
|
| 94 |
+
name: 'Twitter DL',
|
| 95 |
+
description: 'Download Twitter/X Video and Images',
|
| 96 |
+
type: 'GET',
|
| 97 |
+
routes: ['api/download/twitter'],
|
| 98 |
+
tags: ['downloader', 'tools', 'misc'],
|
| 99 |
+
parameters: ['url', 'key'],
|
| 100 |
+
enabled: true,
|
| 101 |
+
main: ['Downloader'],
|
| 102 |
+
handler
|
| 103 |
+
};
|
plugins/twitters.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
async function twitterStalk(username) {
|
| 4 |
+
try {
|
| 5 |
+
const profileResponse = await axios.get(
|
| 6 |
+
`https://www.archivlyx.com/api/x/user?username=${username}`,
|
| 7 |
+
{
|
| 8 |
+
headers: {
|
| 9 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 10 |
+
'Accept': 'application/json'
|
| 11 |
+
}
|
| 12 |
+
}
|
| 13 |
+
);
|
| 14 |
+
|
| 15 |
+
if (!profileResponse.data.success) {
|
| 16 |
+
throw new Error('Failed to fetch profile data');
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
const profile = profileResponse.data.data;
|
| 20 |
+
|
| 21 |
+
const tweetsResponse = await axios.get(
|
| 22 |
+
`https://www.archivlyx.com/api/x/user-tweets?user=${profile.restId}&cursor=`,
|
| 23 |
+
{
|
| 24 |
+
headers: {
|
| 25 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
| 26 |
+
'Accept': 'application/json'
|
| 27 |
+
}
|
| 28 |
+
}
|
| 29 |
+
);
|
| 30 |
+
|
| 31 |
+
if (!tweetsResponse.data.success) {
|
| 32 |
+
throw new Error('Failed to fetch tweets data');
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
const tweetsData = tweetsResponse.data.data;
|
| 36 |
+
|
| 37 |
+
return {
|
| 38 |
+
profile: {
|
| 39 |
+
display_name: profile.displayName,
|
| 40 |
+
handle: profile.handle,
|
| 41 |
+
bio: profile.bio,
|
| 42 |
+
avatar: profile.avatar,
|
| 43 |
+
banner: profile.banner || null,
|
| 44 |
+
is_verified: profile.isVerified,
|
| 45 |
+
is_protected: profile.protected,
|
| 46 |
+
rest_id: profile.restId,
|
| 47 |
+
stats: {
|
| 48 |
+
tweets: profile.tweetsCount,
|
| 49 |
+
followers: profile.followersCount,
|
| 50 |
+
following: profile.followingCount
|
| 51 |
+
},
|
| 52 |
+
website: profile.website || null,
|
| 53 |
+
location: profile.location || null,
|
| 54 |
+
join_date: profile.joinDate
|
| 55 |
+
},
|
| 56 |
+
tweets: tweetsData.tweets.map(tweet => ({
|
| 57 |
+
id: tweet.id,
|
| 58 |
+
text: tweet.text,
|
| 59 |
+
created_at: tweet.createdAt,
|
| 60 |
+
author: {
|
| 61 |
+
id: tweet.author.id,
|
| 62 |
+
display_name: tweet.author.displayName,
|
| 63 |
+
handle: tweet.author.handle,
|
| 64 |
+
avatar: tweet.author.avatar,
|
| 65 |
+
banner: tweet.author.bannerProfile || null,
|
| 66 |
+
is_verified: tweet.author.isVerified
|
| 67 |
+
},
|
| 68 |
+
stats: {
|
| 69 |
+
likes: tweet.stats.likes,
|
| 70 |
+
retweets: tweet.stats.retweets,
|
| 71 |
+
replies: tweet.stats.replies,
|
| 72 |
+
quotes: tweet.stats.quotes,
|
| 73 |
+
views: tweet.stats.views,
|
| 74 |
+
bookmarks: tweet.stats.bookmarks
|
| 75 |
+
},
|
| 76 |
+
media: tweet.media.map(m => ({
|
| 77 |
+
type: m.type,
|
| 78 |
+
url: m.url,
|
| 79 |
+
media_key: m.mediaKey,
|
| 80 |
+
video_url: m.videoUrl || null
|
| 81 |
+
})),
|
| 82 |
+
is_quote: tweet.isQuote,
|
| 83 |
+
is_retweet: tweet.isRetweet,
|
| 84 |
+
quoted_tweet: tweet.quotedTweet,
|
| 85 |
+
retweeted_tweet: tweet.retweetedTweet
|
| 86 |
+
})),
|
| 87 |
+
pagination: {
|
| 88 |
+
next_cursor: tweetsData.pagination.nextCursor,
|
| 89 |
+
prev_cursor: tweetsData.pagination.prevCursor,
|
| 90 |
+
has_more: tweetsData.pagination.hasMore
|
| 91 |
+
}
|
| 92 |
+
};
|
| 93 |
+
} catch (error) {
|
| 94 |
+
if (error.response) {
|
| 95 |
+
throw new Error(`API Error: ${error.response.status} - ${error.response.statusText}`);
|
| 96 |
+
}
|
| 97 |
+
throw new Error(`Failed to fetch Twitter data: ${error.message}`);
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
const handler = async (req, res) => {
|
| 102 |
+
try {
|
| 103 |
+
const { username } = req.query;
|
| 104 |
+
|
| 105 |
+
if (!username) {
|
| 106 |
+
return res.status(400).json({
|
| 107 |
+
success: false,
|
| 108 |
+
error: 'Missing required parameter: username'
|
| 109 |
+
});
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
const usernameRegex = /^[a-zA-Z0-9_]{1,15}$/;
|
| 113 |
+
if (!usernameRegex.test(username)) {
|
| 114 |
+
return res.status(400).json({
|
| 115 |
+
success: false,
|
| 116 |
+
error: 'Invalid username format'
|
| 117 |
+
});
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
const result = await twitterStalk(username);
|
| 121 |
+
|
| 122 |
+
res.json({
|
| 123 |
+
author: "Herza",
|
| 124 |
+
success: true,
|
| 125 |
+
data: result
|
| 126 |
+
});
|
| 127 |
+
|
| 128 |
+
} catch (error) {
|
| 129 |
+
res.status(500).json({
|
| 130 |
+
author: "Herza",
|
| 131 |
+
success: false,
|
| 132 |
+
error: error.message
|
| 133 |
+
});
|
| 134 |
+
}
|
| 135 |
+
};
|
| 136 |
+
|
| 137 |
+
module.exports = {
|
| 138 |
+
name: 'Twitter Stalk',
|
| 139 |
+
description: 'Get Twitter/X user profile information including stats, bio, and recent tweets',
|
| 140 |
+
type: 'GET',
|
| 141 |
+
routes: ['api/stalk/twitter'],
|
| 142 |
+
tags: ['social', 'twitter', 'x', 'stalk', 'profile'],
|
| 143 |
+
parameters: ['username', 'key'],
|
| 144 |
+
enabled: true,
|
| 145 |
+
main: ['Stalk'],
|
| 146 |
+
handler
|
| 147 |
+
};
|
plugins/upscale.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const fs = require('fs');
|
| 2 |
+
const path = require('path');
|
| 3 |
+
const axios = require('axios');
|
| 4 |
+
const https = require('https');
|
| 5 |
+
const FormData = require('form-data');
|
| 6 |
+
|
| 7 |
+
const UPLOAD_URL = 'https://api.unblurimage.ai/api/common/upload/upload-image';
|
| 8 |
+
const CREATE_JOB_URL = 'https://api.unblurimage.ai/api/imgupscaler/v1/ai-image-upscaler-v2/create-job';
|
| 9 |
+
const PRODUCT_SERIAL = '79661c82d918475e7458944c2f66857e';
|
| 10 |
+
const TMP_DIR = '/tmp/upscaler';
|
| 11 |
+
|
| 12 |
+
const axiosInstance = axios.create({
|
| 13 |
+
timeout: 60000,
|
| 14 |
+
httpsAgent: new https.Agent({
|
| 15 |
+
rejectUnauthorized: false,
|
| 16 |
+
}),
|
| 17 |
+
});
|
| 18 |
+
|
| 19 |
+
function ensureTmpDir() {
|
| 20 |
+
if (!fs.existsSync(TMP_DIR)) {
|
| 21 |
+
fs.mkdirSync(TMP_DIR, { recursive: true });
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
async function downloadImage(imageUrl) {
|
| 26 |
+
const response = await axiosInstance.get(imageUrl, {
|
| 27 |
+
responseType: 'arraybuffer',
|
| 28 |
+
});
|
| 29 |
+
return Buffer.from(response.data);
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
function saveImageToTmp(imageBuffer) {
|
| 33 |
+
ensureTmpDir();
|
| 34 |
+
const fileName = `image_${Date.now()}_${Math.random().toString(36).substr(2, 9)}.jpg`;
|
| 35 |
+
const filePath = path.join(TMP_DIR, fileName);
|
| 36 |
+
fs.writeFileSync(filePath, imageBuffer);
|
| 37 |
+
return filePath;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
function deleteFileAfterDelay(filePath, delayMs = 10000) {
|
| 41 |
+
setTimeout(() => {
|
| 42 |
+
try {
|
| 43 |
+
if (fs.existsSync(filePath)) {
|
| 44 |
+
fs.unlinkSync(filePath);
|
| 45 |
+
}
|
| 46 |
+
} catch (error) {
|
| 47 |
+
console.error(`Failed to delete file ${filePath}:`, error.message);
|
| 48 |
+
}
|
| 49 |
+
}, delayMs);
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
async function uploadImage(filePath) {
|
| 53 |
+
const imageBuffer = fs.readFileSync(filePath);
|
| 54 |
+
const fileName = path.basename(filePath);
|
| 55 |
+
const contentType = 'image/jpeg';
|
| 56 |
+
|
| 57 |
+
const form = new FormData();
|
| 58 |
+
form.append('file_name', fileName);
|
| 59 |
+
form.append('file', imageBuffer, fileName);
|
| 60 |
+
|
| 61 |
+
const uploadResponse = await axiosInstance.post(UPLOAD_URL, form, {
|
| 62 |
+
headers: {
|
| 63 |
+
...form.getHeaders(),
|
| 64 |
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36',
|
| 65 |
+
},
|
| 66 |
+
});
|
| 67 |
+
|
| 68 |
+
if (uploadResponse.data.code !== 100000) {
|
| 69 |
+
throw new Error(`Upload failed: ${uploadResponse.data.message.en}`);
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
const uploadUrl = uploadResponse.data.result.url;
|
| 73 |
+
|
| 74 |
+
await axiosInstance.put(uploadUrl, imageBuffer, {
|
| 75 |
+
headers: {
|
| 76 |
+
'Content-Type': contentType,
|
| 77 |
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36',
|
| 78 |
+
},
|
| 79 |
+
});
|
| 80 |
+
|
| 81 |
+
return {
|
| 82 |
+
url: uploadUrl.split('?')[0],
|
| 83 |
+
};
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
async function createJob(imageUrl, upscaleLevel) {
|
| 87 |
+
const form = new FormData();
|
| 88 |
+
form.append('original_image_url', imageUrl);
|
| 89 |
+
form.append('upscale_type', upscaleLevel.toString());
|
| 90 |
+
|
| 91 |
+
const response = await axiosInstance.post(CREATE_JOB_URL, form, {
|
| 92 |
+
headers: {
|
| 93 |
+
...form.getHeaders(),
|
| 94 |
+
'Product-Serial': PRODUCT_SERIAL,
|
| 95 |
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36',
|
| 96 |
+
},
|
| 97 |
+
});
|
| 98 |
+
|
| 99 |
+
if (response.data.code !== 100000) {
|
| 100 |
+
throw new Error(`Job creation failed: ${response.data.message.en}`);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
return response.data.result;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
async function upscaleImage(imageUrl, scaleNumber) {
|
| 107 |
+
let tmpFilePath = null;
|
| 108 |
+
|
| 109 |
+
try {
|
| 110 |
+
if (!imageUrl) {
|
| 111 |
+
throw new Error('Image URL is required');
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
if (![2, 4, 8, 16].includes(scaleNumber)) {
|
| 115 |
+
throw new Error('Scale number must be 2, 4, 8, or 16');
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
const imageBuffer = await downloadImage(imageUrl);
|
| 119 |
+
tmpFilePath = saveImageToTmp(imageBuffer);
|
| 120 |
+
|
| 121 |
+
const uploadResult = await uploadImage(tmpFilePath);
|
| 122 |
+
const result = await createJob(uploadResult.url, scaleNumber);
|
| 123 |
+
|
| 124 |
+
deleteFileAfterDelay(tmpFilePath, 10000);
|
| 125 |
+
|
| 126 |
+
return result;
|
| 127 |
+
} catch (error) {
|
| 128 |
+
if (tmpFilePath && fs.existsSync(tmpFilePath)) {
|
| 129 |
+
fs.unlinkSync(tmpFilePath);
|
| 130 |
+
}
|
| 131 |
+
throw error;
|
| 132 |
+
}
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
const handler = async (req, res) => {
|
| 136 |
+
try {
|
| 137 |
+
const { image_url, scale, key } = req.query;
|
| 138 |
+
|
| 139 |
+
if (!image_url) {
|
| 140 |
+
return res.status(400).json({
|
| 141 |
+
success: false,
|
| 142 |
+
error: 'Missing required parameter: image_url'
|
| 143 |
+
});
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
if (!scale) {
|
| 147 |
+
return res.status(400).json({
|
| 148 |
+
success: false,
|
| 149 |
+
error: 'Missing required parameter: scale'
|
| 150 |
+
});
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
const scaleNum = parseInt(scale);
|
| 154 |
+
if (![2, 4, 8, 16].includes(scaleNum)) {
|
| 155 |
+
return res.status(400).json({
|
| 156 |
+
success: false,
|
| 157 |
+
error: 'Scale must be 2, 4, 8, or 16'
|
| 158 |
+
});
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
const result = await upscaleImage(image_url, scaleNum);
|
| 162 |
+
|
| 163 |
+
return res.json({
|
| 164 |
+
author: "Herza",
|
| 165 |
+
success: true,
|
| 166 |
+
data: result
|
| 167 |
+
});
|
| 168 |
+
|
| 169 |
+
} catch (error) {
|
| 170 |
+
res.status(500).json({
|
| 171 |
+
success: false,
|
| 172 |
+
error: error.message,
|
| 173 |
+
timestamp: new Date().toISOString()
|
| 174 |
+
});
|
| 175 |
+
}
|
| 176 |
+
};
|
| 177 |
+
|
| 178 |
+
module.exports = {
|
| 179 |
+
name: 'Image Upscaler',
|
| 180 |
+
description: 'Upscale images to 2x, 4x, 8x, or 16x resolution',
|
| 181 |
+
type: 'GET',
|
| 182 |
+
routes: ['api/tools/upscale'],
|
| 183 |
+
tags: ['image', 'upscale', 'enhancement'],
|
| 184 |
+
parameters: ['image_url', 'scale', 'key'],
|
| 185 |
+
limit: 5,
|
| 186 |
+
enabled: true,
|
| 187 |
+
main: ['tools'],
|
| 188 |
+
handler
|
| 189 |
+
};
|