Ini adalah kode sumber dari proyek saat ini. Gunakan ini sebagai konteks untuk melakukan perubahan yang diminta.
// FILE: vercel.json
{}
---
// FILE: tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./public/**/*.html",
],
theme: {
extend: {},
},
plugins: [],
}
---
// FILE: server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const hostname = '0.0.0.0';
const port = parseInt(process.env.PORT, 10) || 3000;
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer(async (req, res) => {
try {
const parsedUrl = parse(req.url, true);
await handle(req, res, parsedUrl);
} catch (err) {
console.error('Error occurred handling', req.url, err);
res.statusCode = 500;
res.end('Internal Server Error');
}
}).listen(port, (err) => {
if (err) throw err;
console.log(`> PoP API Server ready on port ${port}`);
});
});
---
// FILE: postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
---
// FILE: package.json
{
"name": "NextA-API",
"version": "1.0.0",
"description": "Proyek API Publik modular dengan fitur Fast Update via AI - Next.js Version.",
"scripts": {
"dev": "next dev -p 8080",
"build": "next build",
"build:full": "node scripts/generate-docs.js && next build",
"vercel:build": "node scripts/generate-docs.js && next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"axios": "^1.7.2",
"axios-cookiejar-support": "^5.0.0",
"cheerio": "^1.0.0-rc.12",
"cloudscraper": "^4.6.0",
"crypto-js": "^4.2.0",
"fast-xml-parser": "^4.3.2",
"ffmpeg-static": "^5.2.0",
"form-data": "^4.0.0",
"fs-extra": "^11.2.0",
"glob": "^10.5.0",
"mime-types": "^2.1.35",
"next": "14.2.3",
"nprogress": "^0.2.0",
"pg": "^8.11.5",
"qs": "^6.11.0",
"react": "^18",
"react-dom": "^18",
"react-markdown": "^9.0.1",
"react-virtuoso": "^4.7.11",
"remark-gfm": "^4.0.0",
"tough-cookie": "^4.1.3",
"uuid": "^9.0.1",
"openai": "^4.0.0"
},
"devDependencies": {
"autoprefixer": "^10.4.19",
"eslint": "^8",
"eslint-config-next": "14.2.3",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.4"
}
}
---
// FILE: next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
experimental: {
serverComponentsExternalPackages: ['ffmpeg-static'],
outputFileTracingIncludes: {
'/api/chess/stockfish': ['./lib/stockfish/**/*'],
'app/api/chess/stockfish/route': ['./lib/stockfish/**/*'],
'/api/**': ['./lib/stockfish/**/*'],
},
},
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'avatars.githubusercontent.com' },
{ protocol: 'https', hostname: 'images.unsplash.com' },
{ protocol: 'https', hostname: 'cdn.pixabay.com' },
{ protocol: 'https', hostname: 'i.pinimg.com' },
{ protocol: 'https', hostname: 'raw.githubusercontent.com' },
{ protocol: 'https', hostname: 'api.dicebear.com' },
{ protocol: 'https', hostname: 'picoclaw.io' },
],
},
async headers() {
return [
{
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT,OPTIONS" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization, x-api-key" },
{ key: "Contact", value: "https://t.me/puruboy_hub" }
]
},
{
source: "/v1/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT,OPTIONS" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization, x-api-key" }
]
}
]
},
async rewrites() {
return [
{ source: '/v1/chat/completions', destination: '/api/v1/chat/completions' },
{ source: '/v1/models', destination: '/api/v1/models' },
{ source: '/chat/completions', destination: '/api/v1/chat/completions' },
{ source: '/models', destination: '/api/v1/models' },
{ source: '/admin', destination: '/admin.html' },
{ source: '/fastupdate', destination: '/fastupdate.html' },
{ source: '/download', destination: '/api/fastupdate/download' },
{ source: '/update', destination: '/api/fastupdate/update' },
{ source: '/favicon.ico', destination: '/favicon.jpg' },
];
},
};
module.exports = nextConfig;
---
// FILE: middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
const response = NextResponse.next();
// CORS Headers untukรองรับทุกโดเมน (Support all domains)
response.headers.set('Access-Control-Allow-Origin', '*');
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
// Return 200 for OPTIONS preflight
if (request.method === 'OPTIONS') {
return new NextResponse(null, {
status: 200,
headers: response.headers,
});
}
return response;
}
export const config = {
matcher: '/api/:path*',
};
---
// FILE: instrumentation.js
/**
* Instrumentation — Next.js server-side initialization
* Auto-load error monitor untuk global error catching
*/
export async function register() {
// Only run on server
if (typeof window !== 'undefined') return;
try {
const { reportError } = await import('./lib/errorLogger');
// Unhandled Promise rejections
process.on('unhandledRejection', (reason) => {
const error = reason instanceof Error ? reason : new Error(String(reason));
reportError(error, {
endpoint: 'GLOBAL/unhandledRejection',
method: 'PROMISE',
});
});
// Uncaught exceptions
process.on('uncaughtException', (error) => {
reportError(error, {
endpoint: 'GLOBAL/uncaughtException',
method: 'UNCAUGHT',
});
});
console.log('[Instrumentation] Error monitor registered ✅');
} catch (err) {
console.error('[Instrumentation] Gagal register error monitor:', err.message);
}
}
---
// FILE: git-push.js
const { execSync } = require('child_process');
const fs = require('fs');
const dir = '/root/.picoclaw/workspace/na-api';
const memoryRaw = fs.readFileSync('/root/.picoclaw/workspace/memory/MEMORY.md', 'utf8');
const tokenMatch = memoryRaw.match(/\| github_token_na_api \| (.+?) \|/);
const token = tokenMatch ? tokenMatch[1] : null;
if (!token) { console.error('Token not found'); process.exit(1); }
execSync('git add -A', { cwd: dir });
execSync('git -c user.name=picoclaw -c user.email=picoclaw@users.noreply.github.com commit -m "feat: tambah endpoint loadtest stockfish untuk debugging"', { cwd: dir });
execSync(`git remote set-url origin "https://picoclaw:${token}@github.com/purujawa06-bot/Na-api.git"`, { cwd: dir });
execSync('git push origin main', { cwd: dir, stdio: 'inherit' });
execSync('git remote set-url origin https://github.com/purujawa06-bot/Na-api.git', { cwd: dir });
console.log('Push selesai!');
---
// FILE: api-key.js
const decode = keys => keys.map(key => Buffer.from(key, "base64").toString("utf8"));
const geminiList = ["QUl6YVN5RGtha2QtMWNiR3FlU1Y2eHJ3WTk4Q0o4SVF5LUpqeUgw", "QUl6YVN5Q2dTVmc4Mms1aUt2Tng2LTNEUmFCSE5Ham5CbGNxaTJZ", "QUl6YVN5Q1dlZUVPVHlqT2Vwc0kyTjg0SDRDMUd4bDlwWk45X3Zr", "QUl6YVN5RGQzM0VBejJXR3BqdkM4R0xJV09sNFJFRXRQSWJCVjBz", "QUl6YVN5QW92M2ZZV0hOejNGaWpQaVNFRG81MnJrTFlBWWsxaEFz", "QUl6YVN5Q2JJVXhPZUVmWl90ajhEbk1BYWhmNG9pNXBuTVh6OXRr", "QUl6YVN5QnlSSjk5eEhkV2ozWFl6YmdZQUFkbTRDUUF6NzBUYXBj", "QUl6YVN5RExyU2FoV3I0WWFWS3l0MmdUbmtwSTBiSUZPVkVQVjdZ", "QUl6YVN5Q0Q0YV9hc2NVcGd4UGREQ0hWa0pteXk2cExROFd6bkJJ", "QUl6YVN5QklMVUtWcDNBaGR4aVM3RmtjUFFGZlM4R0d0YWJZLW40", "QUl6YVN5QkpXbUdPZGV5SHNPZWpEbkF1RVprTVRVRHYwSUVqYXZB", "QUl6YVN5QWU2NVRfZVZvZ1RQOVB6WUpTcUR0VzYzeTBFbHJNdTlZ", "QUl6YVN5QUhsNzlucXZJOFRCN1BaQTZpdXg1TmY2WUlYejFGUzJz", "QUl6YVN5QnFUdmczZ1ZDY0RBNEI1bTJmbXAxc2p6U1U5ZXd5Qzlj", "QUl6YVN5Q0RzQzg1dUJpTzY2M01MbWZZRFc3LVBaVEh6V25BaG84", "QUl6YVN5Q0o5RDk5LV9Mc0ZmbnlPYmlfelNZZ0ZqRmxjS1FPaXY4", "QUl6YVN5Q0M0dTBtcEUzcjJKb0lEZmNSOE03V21IQVdBRXlOQlhV", "QUl6YVN5Qm5KWTNGM0dnVVNiN05lN2VYblhQYXg2V0pmTlI4cG04", "QUl6YVN5RFEwcDZqUkQzb1R1UlNVbFRyZVdFdTZtODNRZVc4RFJN", "QUl6YVN5QlJrTmVCOFE3aWtET0tScTN2bEl6WVJfWVVhYzgxWU9r", "QUl6YVN5Q2l5ZzUzT2p2RldCQkFtblR4bXJmbmduMV90SE5QYmVj", "QUl6YVN5QXRZZXVTZzFISlJTM1dRcHJRbkh6bFFlMUN6azJzUGtZ", "QUl6YVN5RFJRTkxZMDhZWXV5eHB2ZC11a2QyM2ItbEluUHZPNkJB", "QUl6YVN5QU1qTThXQVFsMnduNDBmQVRlY2lfWmhtbVFhVGN6TFV3", "QUl6YVN5QTIwUFpTZFNuSm56SGF1VmRib1RJS3p1UlNYb0tvR1RN", "QUl6YVN5Q2tGUjFIT3RRbURMTU9FNHBYdnpOR0RSNC1uaVBrbHE0", "QUl6YVN5RGdncTl4X1cwaldnenloSzRWa1BTZXlHU2lwaEtlU3Mw", "QUl6YVN5Q2RoZHNNYnJJa0M4RzVvQ0xFVXRBVXlkdmlvZ3hiRUFr", "QUl6YVN5QUFSQXpOM0kyQTRVOVU5b3ctT0h5QXRMc0VheUF4cTJj", "QUl6YVN5QmZOV0JKcGFhMkRZVnR0dXlFWlo2NWtXYnY0ZFdkMFJn", "QUl6YVN5Qk82Vi0tWHNXMGthYU1rV0Z3b3ljVVBrMGNNX3lvMktJ", "QUl6YVN5QmVNdll4Y1lPaVJwdlphQUNLVG02N1Jjc1lhRzNra0dV", "QUl6YVN5RGV6eURNbVhMWlV3MzBDZGZBd3hsVG9BS3djLXN2U1lN"];
const groqList = ["Z3NrX0hoR0dQaGVmZmd5RDFHeEJzRU8xV0dkeWIzRllZWUU3Tjg1amtqRWNzMnd0blY0VkZUdno", "Z3NrX1RhN1BrblAzRXVTd2ZkQm5ub1RTV0dkeWIzRlluTWQ0anNraDBBOGZNaVo5cjZJWjlsV0o", "Z3NrX21CVkdUeGVHVkNycnZSQ1g5aDB1V0dkeWIzRlllQ2hSU1B1SGllamdYcUhmRFFnclo4WVc", "Z3NrX20yY2ZxWHdWMHB1UXFmU05XSGQyV0dkeWIzRllDRGIxQWZ0NjZHV254WHR3SEtzOGozYzA"];
const openaiList = ["QmVhcmVyIHNrLXByb2otOFdQY3V1RDJKOTFHTk8xN0RrWUlscnVHNF9oeHNlZjd6NHo2VEdGdkZQdFVmRV9nV1haLXVsclg2bVdBZUNhNGUyVEJtYjdPNktUM0JsYmtGSlRaakNCXzdUbUhvMzR3WkVrb0RsXzNrd3hGd21ibVRoSXg2X2pqWFkyV2k5VnVKUmFzS20tSXJhRWc1RTFQRi1GMG9JZU5nbGNB", "QmVhcmVyIHNrLU9VOEM4ZFl1eVZUUWRuVG9qVnRtV3lleU5rUUlNd1drRnpsajc3a3JZcVQzQmxia0ZKazZycW54U0lqa0lUT1VpLWxCTG9DejhseHpQT203cmZzZFFHMTZ2OUVB", "QmVhcmVyIHNrLWdoVWwxR2xrUGdHRTJtZFI3MkRQVDNCbGJrRkpHMUhXMFE5VGRnVnlrSnVBTDNYUw", "QmVhcmVyIHNrLXByb2otQ0Q4c1c1NXY3WjZQTXY0d0E5X1VsRWV5OV9YYmljLU5JLURYWUJWRnZkc1BBTHRQZFdOU3ZZa2hqSllNTGlLUUpyMnBIZ3l0dmRUM0JsYmtGSklzNlNLWkxIRGRIR21GbkVhenp1SWM4U0dmY3hlSjNEOFNnSTFqeEY5R2UzWHVHOG1lb3l4UUdxNU1SczNJMjBGclktMF9DME1B", "QmVhcmVyIHNrLXByb2otOVNod202WG15NXRiWl9FY0M1Vm4xYW95NkUxQ1dRWENKVlRmSzktS0tQYXE5NUVVZnAyMWhGOUlhaGhxNkM1eXQzendYazFZMFRUM0JsYmtGSmNQS1psRkd3Wlk3WVl4WElPcjJLaUZqT0VaX0lmSElMVjRwMzhoTEdxWi1hMm01VzlRcmhKR05LYW4zczFpQjdiZkt3V0Z4ZWtB", "QmVhcmVyIHNrLXByb2otcFVGT0Q3S1lhTlBvTkV5czBDdTZCNjRmYThHemVFQVctWjdHT0JGdERFeEFzM2ZzT1huY0hlUmpYaThxYTRKMkx4OGw3TWt3enZUM0JsYmtGSjU1MExFZlBLSmdvUVhHSU1QZnVzbmR3SUNIZUUyNFFVTEdWZG9mR3l1NU5JRlJ2M1c2eGY3MDNZWmVHd24xMnlNRFZwdll3V0VB", "QmVhcmVyIHNrLXByb2otZVRjMjhsMkdlZDQ3djFjWUxBLUQ2UFdWSXlZRXd5Q3RZOEtYeHhfRnBVMV9MM1l2Tk1nSWJyQnZYNDVnRnVyMUdoall0NWl1dGNUM0JsYmtGSjZfT2dvbE5iUWh4Mk1vVl9NeWs1ZkVkV2c2dHkyYVBzRmJ3LW5SQVJYSXROWUpBeTZyYURiVUNaVndOcUxGNmpNdGpWeThkRThB", "QmVhcmVyIHNrLXByb2otM0VlcFphWTZaeGF0YXZoRm0xdndoV3lLRHJmV3ZBM3NaVXF5OWgxZFVFbE44UlBCRFBHdFZLTDllaXlJM0hXblE5M0hSeDJQSUFUM0JsYmtGSkFjbFpINWhpd2pSMjBYNHVqTlhMTk5TSjVQZVo4UzdyREdGaDVBZVlQZEYyZ2Z2bTFMLUpFaGprTnRuVC14dzlCOGpJLVFrRDBB", "QmVhcmVyIHNrLXByb2otajBFMWU4UEVqSklTc0YwNmp3RXpYTnV5MEhmaDZUOFhHTWVCNS1ITVhkaHRESXZVQlA0SDdJQUw3endFTDRSekZsTjM0eTZOYmlUM0JsYmtGSkdhYk84QW9kQWxHVjVhUk5pRXl6SHBVZ3NLSk8yZ1VJbXFISE9GNnRXU0JCaHhMUUNUWGVYM2xlc0NCRmZ3Qm4wbkMzNnRPdFlB", "QmVhcmVyIHNrLXByb2otOTNMbDBVYnRpNUNsSkJ0bGhOX3lPZkxhdEttcExOTzZYQ0JUaUVtY2tlRlJSTjltMkhDaGdWTjRUWFA4RC1hSXJpM211cXg0LWRUM0JsYmtGSmlOaWVaYXlyanVRcmdyUkFENmVEbW5scl9BVTg4RFNUeHJwMEYwMzdVQlRWRkpoR0w5SjRhS1VtZER6blkwUTFVSTZCX0E3QW9B", "QmVhcmVyIHNrLXByb2otd3JKYTZITlVCMElOajR3d0tlS1hVZ0lsT0dwUjRtUzdxbmotWUJqRktpOXRQWXFXY3hyOTREVklGaU1hUmtHcVhhZUFnLXRXbnJUM0JsYmtGSnI5UFNjQU0wNS1SU2ZMN05ldXZYYWJZVlc1ZDY0WDlvdEM1MlZWbF9RX1Nzay1nSmtEYW96M011WjZUUnBBYkNIdEZueEdzWFlB", "QmVhcmVyIHNrLXByb2otajBFMWU4UEVqSklTc0YwNmp3RXpYTnV5MEhmaDZUOFhHTWVCNS1ITVhkaHRESXZVQlA0SDdJQUw3endFTDRSekZsTjM0eTZOYmlUM0JsYmtGSkdhYk84QW9kQWxHVjVhUk5pRXl6SHBVZ3NLSk8yZ1VJbXFISE9GNnRXU0JCaHhMUUNUWGVYM2xlc0NCRmZ3Qm4wbkMzNnRPdFlBUQ", "QmVhcmVyIHNrLXByb2otdnNUdmJRWnE2Rk5HaEcwZTI2d01idWpEaGl4RWl0bkFOaUc2YjBwdWlDQ24weUJnTGNUX1VwdW1xQnNEUlRRNi1CVGw2VTl3Q2FUM0JsYmtGSndwakFpSHk1c1pWSnUyVC13WG95R19NazhhbFJKSi1HRXVEeGtqS19JWF9FcFpTSWl2Nk01b3A4SGJnVmNoVEVEb0Nfc3Q4QTRB", "QmVhcmVyIHNrLXByb2otWXRCVkVjUzBEOWF5TnJkZy1CZUZCNHkzUWQ2dk9pLVROQ2E4dVdYZm9sSXNIb0Ffcy1WemFhVU9rRlZBbmR6aFVJUThuUGtnbWxUM0JsYmtGSkppWUJHTEZLRy1WOGowd1BfX094a1FveHV2SEVPTFhNVVJ5Q2hBWlhHVU1Ja2V2d21VMGYySzZZNFl5UkhvQ241WVZncUtFZ3NB", "QmVhcmVyIHNrLXByb2otVUxrNHhxQWsyZnBRc1FVWGtUcU4zT09VYURsV0VqQlI1aUZwZDRfX3Vpc3ctdTdpMldaQXFWdzN2di02RWhkM2lfX3hGWVJqS2FUM0JsYmtGSmYydy10b2dLQlRJQ0xiNGZ1MDVOdm1HUGhOaktvc0tWXzFlUGhUU25LWHZYQkJ0TTBqZ2N6eVdEd2NDTEx6X3BzbWRyQ2YwRjRB", "QmVhcmVyIHNrLXByb2otVGd1MG9HTFBCLTZUd0tzWG0wOUhDNzlzVVFEUUdzQVAyTEtXTVVyWC1mdUVwS0dzMkFfdEM3QktSZkhuc0VWV0JUN044UG10VXRUM0JsYmtGSjU3Y3R3c0hNRW1LSXFtS0ZCOVlKNHFJZlMyMHgxVWF0N2tkc3J1UXZybjhaTFRYNGNsOE4yMUdGVl9Sc2M3RmhiTXFvYnhRYTBB", "QmVhcmVyIHNrLXByb2otY0p6SmptSTBRNFBYSHhueUIzNTJGaFdGVVI3Z2hFUS1ReEVBOVNVT2dIeklsZjRFRlVSVnZERDVDVUZUV1N1Mk41SHhsbDczaURUM0JsYmtGSktRT2dTaTh5cGNyUkJlSDQyY0lQclRmQ0Q2Um5HUDZTSlRzTXlRUWE0TTRFN09ob3RocUpYTnVjeTg0Uk5uVklNMFk4dzdaVlVB"];
const threezeroList = ["QmVhcmVyIGMyc3ROMUkxTlRZNU1IaFZWMnRSWVZsVWRrNVhZMWN4WkdKSE1FMDJhM1ZtWkc5UVFtaHFhbkZ5UkVwUlEzUkJaR2RX", "QmVhcmVyIGMyc3RXVnBvYWs5cE5UbDBNVk52Tm5WV1MxUkZTRTk1Wm5obU1YTldla2w2WkhwaFNUZzVVbmRJUWs1SGJrWkhTVVZ3", "QmVhcmVyIGMyc3RaV1IwTVVsQloyaHlRVTlUV2xWUVV6bDRWelJUYUcxVE5XNTRiV2xEYm1GalFYRlpRemMyVm5KMlEzSkJlbWM1", "QmVhcmVyIGVkdDFJQWdockFPU1pVUFM5eFc0U2htUzVueG1pQ25hY0FxWUM3NlZydkNyQXpnOQ", "QmVhcmVyIHNrLVQ1VkFEWGJkUDhudExUYlAxYmE1aUhYMmlxVnhiWDNneWxjUm91RTBucjNmWEM0MQ", "QmVhcmVyIHNrLWIwNWJRMTM1UzB0eHdqU2lJQ09tVGZUM1preGpYRWx2UFFUN3dkcnhEMG8yM0VnYQ", "QmVhcmVyIHNrLWpsczRBYVZCR29lMUd3WkQ2NHFaQTFxeUtUTjFNUEhhNE5tdkgxY1Q2OHo3SzFaeg", "QmVhcmVyIHNrLXh3Y1VxbTBMblI1UTlncE9HT1owWFY3amdjSDdZcDZkbzBHbUhSeVhHZGdYOGhwZg", "QmVhcmVyIHNrLWlQY0hzTDdtSmRnUlZSR1Fqb0dSQlFVZTBEdVdnajBRRHdSeWhpR1J5cGZpeWhndQ"];
const deepseekList = ["QmVhcmVyIHNrLTI1YTA1NWYzMWI1ZTRlMGQ5ZjBlYjVkOWZjYWM2NGZj", "QmVhcmVyIHNrLWRiNjU4NWUzMDcxZjQzYTJiZWMxY2YwMzRlNjdhOWI4"];
const runpodList = ["SzlWUE5HNUNBMzNaM1FTU0kwQ1hURDJPSzVYRTNPOUREVkZDNFlCQQ", "TlU0SVlBUzREMEY4Q1ZCU0kyNlI1TlUyMUUwSFc3MzdHUEowN1dBTQ", "cnBhX1VaRjFQREpITlUyQjdBNlNRMlNKMkVNT1k0WUJCWE40QjFKS1dTMklndjZhZWI"];
const runwareList = ["SVJPeEtUQUFCcXZFUlNCdEk0aEpmRWxwY0hvWWt0OHc"];
const segmindList = ["SVJPeEtUQUFCcXZFUlNCdEk0aEpmRWxwY0hvWWt0OHc"];
const perplexityList = ["cHBseC1kN205aTAwNHVKN1JYc2l4Mjg0N2JhRVd6UWVHT0VRS3lwQUNiWGcyR1ZCTFQxZVQ", "cHBseC1yZmVMMTVYMlhmdmE3S1pGZHZnaXBaQ2VTWWprMVNodlNtTU9uTHlzTk8zQ3pYWHM", "cHBseC1hQzhYODdjbmVsRVVGeEVKU0l5ZFB6Y09oNG1sRDladTF6cWxsWGlGcUtNZ2cyWFM", "cHBseC1GNTFHdUxHTUxLSWZ5c1hwREhSdEhpZVZaaHdNVW5ZTk1HdmRtdWNMSEx3cE5Gaks", "cHBseC1MT0JYU0VmTnNXNDFNZUxYUE8wZkJvOEJCbFdES2dzYTZhbUpuVHJMZmNSVFFxcFo", "cHBseC1nV2NMemFrQjZ2RFhUWU9IMVFSZXhMSUg3TWQ4emFUa2d4czAxYWQ1dlRNcktxMVk", "cHBseC1hZjMzRzdJWloyRGYzSTJpdTRZQ003NHJ5NktaM241cWtXSk0zZnM4Sk44aFV1T1U", "cHBseC1VVFBOejhqQUJwdFF3dDd2bHhDcU9LREV1bFM3YzBMNk9JZFBEajBZc0V3SFgwQzQ"];
const falList = ["YTlkNjcyYTAtMGUxMC00ZGFhLTlkYjItODE0ZjZhNzFkNzAwOmIxOWI2ODRiMTUzMGVhODAxMGQ0N2ZjNDAzODkxODg0", "OGI0YjNmYmMtMGZhZi00ZDFhLWE0N2YtNjlhZTlkNTBiM2Q0Ojc0MmI2NzdlZGI3NzJiMDM1N2Q1NzY2MDg0ZGNkMzBk", "YThhMTZhOTctNjE4MC00YjMwLWIyOWQtZGJiNTE3NTAzOGViOmQzMmVmYzE1OWQ3NjI3Y2I2MTZmOWU5NDIxMDhhNWNk", "NGQ2M2ViMDYtZDUzZi00Y2JmLTg0NjgtNjMxODI5YTZjMzYxOmMyMjQ5ZmYzOTE3MzE0ZDdjMGFjMTQxNzhkZDQ5NmI1"];
const kieList = ["MzJjZDliZTk0YzcxYTE1M2RiNjE2ZTQyMGQ1ODI3OGQ"];
const accuList = ["ZWtoQTVQeFBDbTNLZ05JbUdjWHRqVUpxUmQ0UnQzQ2I", "NDY2YTRhOTVlMmE5NDgzZThmM2ZjMjJkOWJiMjM5NWY", "ZGUxMzkyMGY1NzRkNDIwOTg0ZDMwODBiMWZhNjEzMmI"];
const fireList = ["ZndfM1pRTVh3RHdxM2paODg0SnkyQUVyZGl5"];
const replicateList = ["cjhfNzBDU3hLNjZ3WkV4eEVFZUJkUlVIRzd1MUZYWUhZVDQwbVRkRQ", "cjhfMFFWUTg2cUF6eTJVNzl6c2g5MmJ1NmpDZ0lxdFhZajF4cXE5NQ", "cjhfUkNwT2lORFRiS3Q2OERUbXVCVXZvVzNZTGZCY255dDExeDNXOQ", "cjhfVDBJZHRjYXNCeWV2VGtXNzhqVlE3cDZJbVA2YUN6TTA0MTh4Yg", "cjhfQ2hmekVWWExvem8yRTZzU0N6REtoQlZjVkM0MUVzWTJFZHludg", "cjhfWEJsUlNqZERkRm9xTXJpbzZuV3EyNGhUU0tTYm92WjFPSkFkdw", "cjhfM3U5T3dZbmozMGZ0bWpCT044MmlMbTZzc2pJeWRZVzIySFpZOA", "cjhfUld5YVVtbnQzYXdsSEFrU2tSYnFJemVoRERDeGZhZzFDTEtlUg"];
const giphyList = ["clVNRDFoZFB1WFpHbzY1SWE1OHd4VnpYWVM4SU5SQ1g", "U2RYNjBlVGR5dmRvMGFBeUpNUTV1ODdRaDdtVHo3Ykc"];
const telegramList = ["ODU4NzY2MDU0ODpBQUhMU3hrM2FWeUdoaFFVTEZNVEN0Yl8teWhSUmI1Mi1VWQ", "ODUwNzk2MjI2MDpBQUhhUlhrbkl2YkVJTHpFZ2RLNHJKMHJSY01OeVYzcTJOWQ", "NzU1OTUyMTY0MDpBQUhWOThyZ0NCb2FxWkw2QTZ5UFlETTltcllZV2lkeVlPdw", "Njg3NTcwNDM2NTpBQUgxZ2J0NVVpNUxRVjJYdklQc1pncmJsVTlPZEJqRTBUYw", "NzU4NDM4NjQzODpBQUVsVHlXZVItWVlTYXVHd2w4SDRsQXlhdTVrb3dMa1AzNA", "NzU3NzI5NjEyNzpBQUZLVzdhV3ktbTE3SzdFamotdDJTSFZfVVdTOGhqR0EyNA"];
const pixabayList = ["NDI1NDU2OTEtZDNmNGI4NzdlNDIwZWQyYWFkYzk2MTJmMw", "NzU4MDk4OTg2NDpBQUhTM0dOT0VOTEhzLXk5eElVdWhzS2RtSUY3UVpmMmQ4MA"];
const unsplashList = ["THZNS2tYYnkwRkRpU092bVBpUjJLVEhoOEpXcm55cWZvT1UyTzdLYWdsNA"];
const tmdbList = ["MTY5MGM2NzFmYjY2MjdlODUyMjAwM2JlNDM3ZDRlYWY"];
const ocrList = ["aGVsbG93b3JsZA", "ZGYwMTI3OTVhZDg4OTU3", "Szg3NDIwNjE3ODg4OTU3", "NGIxODg2NWQ1NDg4OTU3", "Szg1Nzk3MDU1MDg4OTU3", "SzgzMzE3MzEzNTg4OTU3"];
const poyoList = ["c2stbGVfVVcwaFpmVnNSMTFjSS1Oa1BZUEJrcXhEblF0SHF2ZHlESjg5SHNJYVo5OVJ1MmFkR2MwRTUyODRMRWY"];
const openrouterList = ["c2stb3ItdjEtZGM4Y2UzZTUzNGQ1NzNjNzU2OGY0MDlkYjFjMTU2MDQ0ZTE4MDEyYTY4MTU0MDZiZGMzMDZjOWE4ZDNjN2I2Mw", "c2stb3ItdjEtZmU3YTg1ZDhhODcyMGNlMmY2ZTU4ZjY3Y2M0MTkzY2U4NGEyNWYzZWIxODFkZjk4YzljNWJkN2JmMWJjYThkOA", "c2stb3ItdjEtYjAzMGUzYzNkMTQ2N2MxODcxOGQyM2UzODdkYWViNTMzNjE0ZjcxMjc4NTM1N2U2MTQzN2RkYmNjZGUzOGY3OQ", "c2stb3ItdjEtNThkNDRhYjhhMzc3NjkzMTQ5NmFhMmI1ODBjMTU0NWQ2YjBjZDI5MWZjZWMzZWY1YmQyNmQ3NzJkZjhhM2Q3ZA", "c2stb3ItdjEtZjQ4YjZjODg4NTJkZWU5YjlkYjE1ZmZiMTI2MDZjMGJiNWJmYTMzYzkyNWYyNzNhMzY3MjY1NjcyNjVkZDAwYQ", "c2stb3ItdjEtMjgxOTE1YTQzYjA4Yzc3OTJhNGI4ZDc5NDlhYmM2MzNjYjE4MmUyZmQzMjdmYTc4N2NiMmM2YzY3MGNjMjNhZQ", "c2stb3ItdjEtNzM4MjRkMGQ0OWJlNmIzYWQ3OGZjMGMxZWExYTM5YWY2MmUxNjFlOTIyNWU3Mzk2ODI4ZDIwODcxZGVhODY5Nw", "c2stb3ItdjEtNzA4NTlmNWJkYmFhNDIwODc3NDFhMTc5M2Y0ZDM4MmMyZjMwYzQwMzRjMjgzNjkzZjRkM2Q3YWMyOTViZGQ0ZA", "c2stb3ItdjEtMzI2ZDgxOTBhNjNmMjAyNmRmY2MwMTc5YmM5N2QwODhjZDZkNzU4YjJjNDViNmRhZDgyN2FlNzE3MzE1NjRiYw", "c2stb3ItdjEtMDNkZDU0ZjgxMzBmYzNkZDlkYTkzYTc1ZDAyZDg2OTU4NjdjZTM0NWM1OWViNGY1OTQ2N2ZlY2UyZmQ4ZGQ4ZQ", "c2stb3ItdjEtMWE4MWZjODgyNjc2YjhhYjY0YjQzNjM3MTU1MzllZTZjZDEyZGE5NGQxN2UxODZlNzViMzQxZDY5MThiYWU1Mg", "c2stb3ItdjEtZTI1ZGNhODg1YmE3Y2RjZTliM2Q4NmY4NWFjNjE1YzY5MDE0YzgxYjhmMjk3YzJmZGE4YmZiZjY2Mjc2NmJkNg", "c2stb3ItdjEtOTYyZjdmNmYzNDEzMjUyODY1ZjI4YWQ5NmY5ZGVkNjk4ZDE0NzVlMjIzMzRlNTIyYzMyMWMzNjEyZDdiMTY4OQ", "c2stb3ItdjEtMWYwYTMyMTlhNGU4MTIzMGJmMmRkYzM3NTE0MTBjZjI2ZTk1MTI3ZTM0NDMxMjgyNzEzMjljYTU3NDZiOTUzNQ", "c2stb3ItdjEtOTdmNmE2MWM4MGI5YTQzZTBmNDhmMWVhODQyM2QwYjczMzU5OWMwOWZhZTBmYzFlYTJkNGI2ZTg0NjU0ZDU5Yg", "c2stb3ItdjEtNTg4ZmQ0MTExOWNhYmJmODZmY2MxZjY2MzdiNDQ4ZTYxZmIyM2RkNjZjNDgyM2UzNGU4NDYzN2ExYThmNGRiMw", "c2stb3ItdjEtOTYwMzlhZjJlN2E0YmUwZmE4ZDBhMWJmOWQ5NTk1MjE2YmI1ZWVkODE4MGVhY2MxMmExNDUzN2M4ZDZmZjg2YQ", "c2stb3ItdjEtNTA4NDYzYjdiZDE0OTcxYzU4OTc1OTNiNzY4NmRkYjFjMjk4OTk3YmY5NWM0ZjY1ZTFlODQ1NzIzYWFlN2JhMA", "c2stb3ItdjEtNmVkNDNkNTk0NTVjYzVjZGI5ZTQ4MzVhOWNjMWQ2NTdhZTA0MTI1OTBiYjE3NWJkYThhZGZjN2U2ZTQ3NTlhNw", "c2stb3ItdjEtNzFiN2NmYjcxNTE5OGNiMjk3ODI2ODc0Y2E3MTNlNTQ2MGY3MzM4OWUwMmUzZjQ3NzA5N2QzNjY3ZDdiYjhjZA", "c2stb3ItdjEtM2I5NjQ0OTJjNzA0NmJiZDM3YzhmZWEyNDNmZjEzYjhkZjJhOTQyZjlhMjFjMGFiYmNlMWU5ZjhiOGIzYzE4Zg", "c2stb3ItdjEtMTJhZWU4MzNjNDBhYjZjNDJiYjA3NTZhMGE5ODkzNTFkOTkyZGU4MDJkMDk2N2JiMzkxNDI0ZTY2ZTVmYWQxOQ", "c2stb3ItdjEtN2Q0ZDJiMDg3MzBiYjJmMWVlYjg5NTE2NjgzZjgwNTY5ZWU5NDhjYWZmZTZkYTU2MGFiN2RkNTAzMGYzYjcxMQ", "c2stb3ItdjEtZmM2MmQ1MWYxNDViNzk0MzFiOTI2YzdlNTM2ZTQyZWY2ZGNlOGZhYWViY2Q2MzUzMjI0ZmIxMGE1N2ExZDJmOQ", "c2stb3ItdjEtYzg1OTY3OGE3ZDBjMWQ5NWVhOTdlM2EyNjU4NTY5OTkxNmI3MzBjMjZhYmJiZjFiYjM5MGQ1NTEzMzU0YTQzNg", "c2stb3ItdjEtZDUwZjBjN2VlOWFlM2QwYWM3NjUyNGU0YzY0NTI1MjRiZmM0NGY3OTM1NGQ0ZjAyYjExOGFhYjIwYjlkNjViYw", "c2stb3ItdjEtMzhkNTQ3ZDgyNGY3YjQ1MDhiNzQzMDkzN2IzN2Y4N2M2N2VhNWQ5NzIzOGIwYzA0NDg4OGNkMmJkM2MyYmE2Nw", "c2stb3ItdjEtZDc2OGQwZjhiNjU2YWU4NzQyMmQ3NDViOWEzOTEzYzUzYzNjZWM0MDZjODNmOWI2Mjg1NWNlNTFhMzZmMzM2OQ", "c2stb3ItdjEtY2FhMDUyZjcwNjA3MTY3MWM2ZDI3MDhkNDNhNzM1NGYyODAwOGZlNmE3Yzg5OTE2YmRmMzcwNGYwMTA0MTM5Zg", "c2stb3ItdjEtZGJmMjk0NGMxYWMyZDdmNGNhYTA4ODA0ODVmMTNjMWUxNTlmOWJhYTBiYzQ4NTU3Y2I1OTJjMDZlMDliMzliNQ", "c2stb3ItdjEtYzZkMTUxMjU4ZTZhM2NiZTY0ODljOWIzYjdjZmJhMDM2ZmRiYmZhYjk3YWU2MWJjZWE3NWFmNTdlODRhZWE0MA", "c2stb3ItdjEtMTkyZGY2YmU5MjgxNTAzNmNjNGI4ZmIzMmUwNmM1NzNiY2VmOWNhZGQwOTZiYWUxMjM0MGFlNjAyYWJhN2ZhMg", "c2stb3ItdjEtYmJkZTJhMmY3ZWY1NTBhNTA0YTcwOTQ1NzY0M2IxN2RiY2YzZDg5ZTQxYzQ1YjdmMzQ3YzljMmM3NzUxM2U4Yw", "c2stb3ItdjEtNGJlYzUwNmZhMzY1MmE4MGI2ZDJiMzQ2YjdiZmQwMDY3M2Y1MjhhOGJkNGE2NzdhYTYzNTQ2NTMyZTQ0YjA0Mw", "c2stb3ItdjEtZmNiYjM0YmE3MzQxMzJiYzMxMTEzZWUyYTBlYjhhZTg4NTVjNGQzNzBlMTkxNjI3MGQ4MmI5ZDI5NzY3YzdlNQ", "c2stb3ItdjEtYzEyMDZkY2Y3NTliYWEyNzYwN2Y4YzU0YTZkOWExN2NkNWRlMDQ2Y2Y2ZDY0NWJiMDIxZGNmZWE5NzE2ZDUyMg", "c2stb3ItdjEtNzZkYzkwZDQxMzE2YzMxNjIxNDJiY2Y2MzBiZjFmMTg3MDAzMjEwMmQ4MjJiYzEwZTJlYjkzMzU4OGFiNDg4Mg", "c2stb3ItdjEtODhmOGNhNTgzMmUxNmY5NjNkNGUyMTQyMDZmODhjZjg4OGRmNDU1NGJmMWUwZmY3ZGVlZjlmYjdiMTFjNTI2ZQ", "c2stb3ItdjEtN2RiYTNmNzVjYjE1ZjU5YjIzMDJhMTAxYWEyYTZjZWU1ZDg0OTdmZTk3NGYxZmQwMzM0ZTM5ZTA4OGU3YmJiNA", "c2stb3ItdjEtNGVmZDVkOGY0ZTlhYWUxZTI2ZjcwYjVlY2Y5ZThjZjZhYmJlMGU0ODRlOWE2N2UwOTZjYTAzMDZjZTk0N2M1Yg", "c2stb3ItdjEtYmEwMzUwYzRjYTU3OWVkOGJiNDZlNGQyZmU2Zjk5NDA0MzBmNGFhNDU5ZGFjMTMwNjgzMWFlZjRmY2UwZjRmNg", "c2stb3ItdjEtYmY1MTI0ODkxOTI1YzM0OTA0ZTdhOGJiZmM5OWVkY2NhYTQ0MzIyM2ZhNGQzMTUxOGEzZjRjODIzNjZmNzFmYw", "c2stb3ItdjEtYzdlMTBkMmJhMWVhN2JjZWJjODBhNDlkZmM4YzRjOWI3MWI0YWVjMmRmYTU4YWU0ZWRmMGY5YjEwM2VlNGUwNw", "c2stb3ItdjEtMzc0ODc5ZDQ0NTExYjBkYTFkNzRjZjA0MTM3MGVkNjIyMTcxMDBmMDY2ODc2ZTYxMDQ3Nzg4YzRiNTQzYzJmMA", "c2stb3ItdjEtNzk5NmM5NGI3OTljYTgzNjI4YzUzY2QwOGI3MzBjMmIxY2RlMGYzNWMxZmUwZmQ5OTcxNjNmNWYyYjYyYjVlNQ", "c2stb3ItdjEtMWQwMGNmOWE2ODE2YTBjYjJmNDMzYzM5ZmM1ZDliNGFhZDU0MGJjODFkNDkzODA2MDVkYjlhZTI5YjI2YmVmZg", "c2stb3ItdjEtYzZhMGZjYTBhNWNhMmNmODFlNmQ4YmQ3OWJiODA2MzEzNTEzOTM4OTcwMWU3NWRkMmU5N2I0Mzk1ZWYxZGNlYg", "c2stb3ItdjEtODNiNzcyODM2MDViNjgzMDcwMzBjOGFhNDM2NzFjYzEyYzAyMmE4OGQ0NTI0YTJiYjY2OGNkM2FhMDcyZTI5OQ", "c2stb3ItdjEtMmQzMjUyNTg3ZGI4MmNlYzVlNjcyMzIxMDVlMzk0Y2Y2MzgyMWJlZmZjMGI1YWMzZThhMjZiMDc1YzU0MTJhMQ"];
const apiKey = {
gemini: decode(geminiList),
groq: decode(groqList),
openai: decode(openaiList),
threezero: decode(threezeroList),
deepseek: decode(deepseekList),
fal: decode(falList),
kie: decode(kieList),
accu: decode(accuList),
fire: decode(fireList),
replicate: decode(replicateList),
giphy: decode(giphyList),
pixabay: decode(pixabayList),
unsplash: decode(unsplashList),
tmdb: decode(tmdbList),
ocr: decode(ocrList),
poyo: decode(poyoList),
openrouter: decode(openrouterList),
perplexity: decode(perplexityList),
runpod: decode(runpodList),
runware: decode(runwareList),
segmind: decode(segmindList),
telegram: decode(telegramList)
};
export default apiKey;
---
// FILE: scripts\rebuild-docs.js
const { scanDocs } = require('/root/.picoclaw/workspace/Na-api/lib/docsService');
const path = require('path');
const fse = require('fs-extra');
scanDocs().then(async (spec) => {
const outputPath = '/root/.picoclaw/workspace/Na-api/public/docs.json';
await fse.ensureDir(path.dirname(outputPath));
await fse.writeJson(outputPath, spec, { spaces: 2 });
console.log('✅ docs.json regenerated successfully!');
console.log('📊 Categories:', Object.keys(spec).length);
// Show gemini-v3 entry
for (const [cat, eps] of Object.entries(spec)) {
for (const ep of eps) {
if (ep.path && ep.path.includes('gemini-v3')) {
console.log('\n=== Gemini V3 Docs Entry ===');
console.log(JSON.stringify(ep, null, 2));
}
}
}
}).catch(e => console.error('❌ Error:', e));
Updated `vercel:build` script in `Na-api/package.json` ✅
---
// FILE: scripts\patch-routes.js
#!/usr/bin/env node
/**
* Patch Routes — Auto-inject errorLogger ke semua API route files
*
* Cara pakai: node scripts/patch-routes.js
*/
const fs = require('fs');
const path = require('path');
const API_DIR = path.join(__dirname, '..', 'app', 'api');
/**
* Hitung jumlah "../" untuk import dari route.js ke lib/errorLogger
* Formula: jumlah folder dari 'app/api/' ke file + 2 (untuk app/ dan api/)
*/
function getImportDepth(routePath) {
// routePath relative to API_DIR, misal: "search/youtube/route.js" atau "blogs/route.js"
const normalized = routePath.replace(/\\/g, '/');
const parts = normalized.split('/');
// parts = ["search", "youtube", "route.js"]
// jumlah folder (exclude route.js) = parts.length - 1
const folderCount = parts.length - 1; // exclude route.js
return folderCount + 2; // +2 untuk app/ dan api/
}
function getImportPath(routePath) {
const depth = getImportDepth(routePath);
return '../'.repeat(depth) + 'lib/errorLogger';
}
/**
* Dapatkan nama endpoint dari path relatif
*/
function getEndpointName(routePath) {
let name = '/' + routePath.replace(/\/route\.js$/, '');
// Convert [param] ke :param
name = name.replace(/\[(.+?)\]/g, ':$1');
return name;
}
async function patchFile(filePath) {
let content = fs.readFileSync(filePath, 'utf-8');
const original = content;
// Skip if already patched
if (content.includes("from '") && content.includes("errorLogger")) {
console.log(` ⏭️ Already patched: ${path.relative(API_DIR, filePath)}`);
return false;
}
const relPath = path.relative(API_DIR, filePath);
const importPath = getImportPath(relPath);
const endpointName = getEndpointName(relPath);
const importLine = `import { reportError } from '${importPath}';`;
// 1. Add import after the last import statement
const lines = content.split('\n');
let lastImportIdx = -1;
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim().startsWith('import ')) {
lastImportIdx = i;
}
}
if (lastImportIdx >= 0) {
lines.splice(lastImportIdx + 1, 0, importLine);
} else {
lines.unshift(importLine);
}
content = lines.join('\n');
// 2. Find all catch blocks and inject reportError
// We'll find patterns like: catch (error) { ... return NextResponse.json ...
// And inject reportError right after the opening brace
let result = '';
let remaining = content;
let catchCount = 0;
while (remaining.length > 0) {
const catchMatch = remaining.match(/catch\s*\(\s*(\w+)\s*\)\s*\{/);
if (!catchMatch) {
result += remaining;
break;
}
const catchVar = catchMatch[1];
const beforeCatch = remaining.substring(0, catchMatch.index);
// Find the HTTP method for this catch block (look backwards)
const beforeText = beforeCatch;
const methodRegex = /export\s+async\s+function\s+(GET|POST|PUT|DELETE|PATCH)\s*\(/g;
let methodMatch;
let method = 'UNKNOWN';
while ((methodMatch = methodRegex.exec(beforeText)) !== null) {
method = methodMatch[1];
}
// Count braces from catch { to find the matching }
let braceCount = 1;
let pos = catchMatch.index + catchMatch[0].length;
while (braceCount > 0 && pos < remaining.length) {
if (remaining[pos] === '{') braceCount++;
else if (remaining[pos] === '}') braceCount--;
pos++;
}
const catchBlockEnd = pos - 1; // position of the closing }
const catchBlockContent = remaining.substring(catchMatch.index + catchMatch[0].length, catchBlockEnd);
// Build the modified catch block
const reportCall = `\n // Auto-report error ke Telegram\n reportError(${catchVar}, { endpoint: '${endpointName}', method: '${method}' }).catch(() => {});\n`;
const newCatchBlock = `catch (${catchVar}) {${reportCall}${catchBlockContent}}`;
result += beforeCatch + newCatchBlock;
remaining = remaining.substring(catchBlockEnd + 1);
catchCount++;
}
content = result;
// 3. Write if changed
if (content !== original) {
fs.writeFileSync(filePath, content, 'utf-8');
// Get method names
const methods = [];
const methodNames = content.match(/export\s+async\s+function\s+(GET|POST|PUT|DELETE|PATCH)/g);
if (methodNames) {
methodNames.forEach(m => {
const match = m.match(/(GET|POST|PUT|DELETE|PATCH)/);
if (match) methods.push(match[1]);
});
}
console.log(` ✅ [${methods.join(',')}] ${relPath}`);
return true;
}
console.log(` ⚠️ No changes: ${relPath}`);
return false;
}
async function main() {
console.log('🔧 Na-api Error Logger Patcher\n');
console.log(`📁 API Directory: ${API_DIR}\n`);
// Find all route.js files
const routeFiles = [];
function walkDir(dir) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
walkDir(fullPath);
} else if (entry.name === 'route.js') {
routeFiles.push(fullPath);
}
}
}
walkDir(API_DIR);
console.log(`📦 Found ${routeFiles.length} route files\n`);
let patched = 0;
let skipped = 0;
for (const filePath of routeFiles) {
try {
const changed = await patchFile(filePath);
if (changed) patched++;
else skipped++;
} catch (err) {
console.error(` ❌ Error: ${path.relative(API_DIR, filePath)} - ${err.message}`);
}
}
console.log(`\n✨ Done! ${patched} files patched, ${skipped} files skipped.`);
}
main().catch(console.error);
---
// FILE: scripts\generate-docs.js
const { scanDocs } = require('../lib/docsService');
const fse = require('fs-extra');
const path = require('path');
(async () => {
console.log('🚀 Starting API Documentation Generation...');
try {
const spec = await scanDocs();
// Output ke folder public agar bisa diakses/dibaca di runtime production
const outputPath = path.join(process.cwd(), 'public', 'docs.json');
await fse.ensureDir(path.dirname(outputPath));
await fse.writeJson(outputPath, spec, { spaces: 2 });
console.log(`✅ Success! docs.json generated at: ${outputPath}`);
console.log(`📊 Stats: Found ${Object.keys(spec).length} categories.`);
} catch (err) {
console.error('❌ Failed to generate docs:', err);
process.exit(1);
}
})();
---
// FILE: scratch\test-working-ai.js
const { askGPT } = require('../lib/letmegpt');
const { chat: chatGeminiV2 } = require('../lib/geminiV2');
(async () => {
console.log('Testing LetMeGPT...');
try {
const res1 = await askGPT('ขอโค้ด Python ลบไฟล์');
console.log('✅ LetMeGPT response:', res1.answer.substring(0, 100));
} catch (e) {
console.error('❌ LetMeGPT error:', e.message);
}
console.log('\nTesting Gemini V2...');
try {
const res2 = await chatGeminiV2('ขอโค้ด Python ลบไฟล์');
console.log('✅ Gemini V2 response:', typeof res2 === 'string' ? res2.substring(0, 100) : res2);
} catch (e) {
console.error('❌ Gemini V2 error:', e.message);
}
})();
---
// FILE: scratch\test-tools-routes.js
const axios = require('axios');
const BASE_URL = 'http://localhost:8080';
const endpoints = [
{ name: 'Brat Generator', path: '/api/tools/brat', body: { text: 'Hello World' } },
{ name: 'Quran API', path: '/api/tools/quran?surah=1' },
{ name: 'Sholat Prayer Schedule', path: '/api/tools/sholat?kota=Jakarta' },
{ name: 'MLBB Stalker', path: '/api/tools/mlbb?userId=123456&zoneId=1234' },
{ name: 'Preview Upload', path: '/api/tools/preview-upload', body: { html: '
Test
', filename: 'test' } },
{ name: 'Audio Edit', path: '/api/tools/audioedit', body: { url: 'https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4', effect: 'bass' } },
{ name: 'MP4 to MP3', path: '/api/tools/mp4tomp3', body: { url: 'https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4' } },
{ name: 'Remove Background V2', path: '/api/tools/removebg-v2', body: { url: 'https://puruboy-api.vercel.app/favicon.jpg' } },
{ name: 'Ghibli Style Filter', path: '/api/tools/ghibli', body: { url: 'https://puruboy-api.vercel.app/favicon.jpg' } },
{ name: 'Unblur Image', path: '/api/tools/unblur', body: { url: 'https://puruboy-api.vercel.app/favicon.jpg' } },
{ name: 'Image Upscale', path: '/api/tools/upscale', body: { url: 'https://puruboy-api.vercel.app/favicon.jpg' } },
{ name: 'Image Reviva', path: '/api/tools/reviva', body: { url: 'https://puruboy-api.vercel.app/favicon.jpg' } },
{ name: 'Audio to Text', path: '/api/tools/audio2text', body: { url: 'https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4' } },
];
async function testEndpoint(ep) {
const start = Date.now();
try {
let resp;
if (ep.body) {
resp = await axios.post(BASE_URL + ep.path, ep.body, { timeout: 15000 });
} else {
resp = await axios.get(BASE_URL + ep.path, { timeout: 15000 });
}
const elapsed = Date.now() - start;
let sample = typeof resp.data === 'string' ? resp.data.substring(0, 150) : JSON.stringify(resp.data).substring(0, 150);
return `[PASS] ${ep.name} (${elapsed}ms) - Status: ${resp.status}\n Response: ${sample}`;
} catch (err) {
const elapsed = Date.now() - start;
const status = err.response?.status || 'ERR';
const msg = err.response?.data?.error || (typeof err.response?.data === 'string' ? err.response.data.substring(0, 100) : err.message);
return `[FAIL] ${ep.name} (${elapsed}ms) - Status: ${status}\n Error: ${msg}`;
}
}
async function runParallel() {
console.log('=== PARALLEL TOOLS ENDPOINTS TEST ===\n');
const results = await Promise.all(endpoints.map(testEndpoint));
results.forEach(res => {
console.log(res);
console.log('--------------------------------------------------');
});
}
runParallel();
---
// FILE: scratch\test-routes.js
const chatbotchatappController = require('../lib/controllers/ai/chatbotchatapp');
const { chatDeepSeekV4 } = require('../lib/deepseek-v4');
(async () => {
console.log('Testing chatbotchatapp...');
try {
const res1 = await chatbotchatappController({ body: { message: 'halo' } });
console.log('✅ chatbotchatapp success:', res1);
} catch (e) {
console.error('❌ chatbotchatapp error:', e.message);
}
console.log('\nTesting deepseek-v4...');
try {
const res2 = await chatDeepSeekV4('halo');
console.log('✅ deepseek-v4 success:', res2);
} catch (e) {
console.error('❌ deepseek-v4 error:', e.message);
}
})();
---
// FILE: scratch\test-pollinations.js
const axios = require('axios');
async function testPollinations(prompt) {
try {
const res = await axios.post('https://text.pollinations.ai/', {
messages: [
{ role: 'user', content: prompt }
],
model: 'openai'
}, { timeout: 15000 });
console.log('✅ Pollinations response:', typeof res.data === 'string' ? res.data.substring(0, 100) : res.data);
} catch (e) {
console.error('❌ Pollinations error:', e.message);
}
}
testPollinations('สวัสดี คุณเป็นใคร');
---
// FILE: scratch\test-poll-get.js
const axios = require('axios');
async function testPollGet(prompt) {
try {
const res = await axios.get(`https://text.pollinations.ai/${encodeURIComponent(prompt)}`, { timeout: 15000 });
return typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
} catch (e) {
return 'Error: ' + e.message;
}
}
(async () => {
const ans = await testPollGet('ขอโค้ด Python ลบไฟล์ในโฟลเดอร์');
console.log('✅ Pollinations GET response:', ans.substring(0, 150));
})();
---
// FILE: scratch\test-openai-poll.js
const axios = require('axios');
async function testPoll(prompt) {
try {
const res = await axios.post('https://text.pollinations.ai/', {
messages: [{ role: 'user', content: prompt }]
}, { timeout: 25000 });
return typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
} catch (e) {
return 'Error: ' + e.message;
}
}
(async () => {
const text = await testPoll('ขอโค้ด Python ลบไฟล์ในโฟลเดอร์');
console.log('✅ Pollinations response:', text.substring(0, 150));
})();
---
// FILE: scratch\test-new-ai.js
const blackboxController = require('../lib/controllers/ai/blackbox');
const llamacoderController = require('../lib/controllers/ai/llamacoder');
(async () => {
console.log('Testing blackbox...');
try {
const res1 = await blackboxController({ body: { prompt: 'สวัสดี ขอโค้ด Hello World JavaScript' } });
console.log('✅ blackbox result:', typeof res1.result.answer === 'string' ? res1.result.answer.substring(0, 120) : res1.result);
} catch (e) {
console.error('❌ blackbox error:', e.message);
}
console.log('\nTesting llamacoder...');
try {
const res2 = await llamacoderController({ body: { prompt: 'สวัสดี ขอโค้ด Hello World Python', model: 1 } });
console.log('✅ llamacoder result:', typeof res2.result.answer === 'string' ? res2.result.answer.substring(0, 120) : res2.result);
} catch (e) {
console.error('❌ llamacoder error:', e.message);
}
})();
---
// FILE: scratch\test-new-ai-fix.js
const axios = require('axios');
async function testPollinationsCode(prompt, model = 'openai') {
try {
const res = await axios.post('https://text.pollinations.ai/', {
messages: [{ role: 'user', content: prompt }],
model: model
}, { timeout: 25000 });
return typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
} catch (e) {
return 'Error: ' + e.message;
}
}
(async () => {
console.log('Testing Pollinations Qwen Coder...');
const ans1 = await testPollinationsCode('ขอโค้ด Python ลบไฟล์ในโฟลเดอร์', 'qwen');
console.log('✅ Qwen Coder:', ans1.substring(0, 150));
console.log('\nTesting Pollinations DeepSeek Coder...');
const ans2 = await testPollinationsCode('ขอโค้ด JavaScript คำนวณวันที่', 'deepseek');
console.log('✅ DeepSeek Coder:', ans2.substring(0, 150));
})();
---
// FILE: scratch\test-live-qwen38.js
const axios = require('axios');
(async () => {
console.log('Testing live endpoint for qwen-3.8-max...');
try {
const res = await axios.post('https://allapi.getth.xyz/api/v1/chat/completions', {
model: 'qwen-3.8-max',
messages: [{ role: 'user', content: 'สวัสดี แนะนำตัวสั้นๆ ว่าคุณคือใคร' }]
}, { timeout: 25000 });
console.log('✅ Response Status:', res.status);
console.log('✅ Response Data:', JSON.stringify(res.data, null, 2));
} catch (e) {
console.error('❌ Live test error:', e.response?.data || e.message);
}
})();
---
// FILE: scratch\test-live-codex.js
const axios = require('axios');
(async () => {
console.log('Testing live endpoint for model: codex ...');
try {
const res = await axios.post('https://allapi.getth.xyz/api/v1/chat/completions', {
model: 'codex',
messages: [{ role: 'user', content: 'เขียนฟังก์ชัน JavaScript คํานวณ Fibonacci และอธิบายสั้นๆ' }]
}, { timeout: 25000 });
console.log('✅ Response Status:', res.status);
console.log('✅ Response Data:', JSON.stringify(res.data, null, 2));
} catch (e) {
console.error('❌ Live test error:', e.response?.data || e.message);
}
})();
---
// FILE: scratch\test-global-anime.js
const axios = require('axios');
async function testConsumet() {
const providers = [
'https://consumet-api-clone.vercel.app/anime/gogoanime/naruto',
'https://api.consumet.org/anime/gogoanime/naruto',
'https://consumet-api-clone.vercel.app/anime/zoro/naruto'
];
for (const url of providers) {
try {
console.log('Testing provider:', url);
const res = await axios.get(url, { timeout: 8000 });
console.log('PASS:', JSON.stringify(res.data).substring(0, 200));
return;
} catch (e) {
console.log('FAIL:', e.message);
}
}
}
testConsumet();
---
// FILE: scratch\test-docs.js
const { getDocsSpec } = require('../lib/docsService');
(async () => {
try {
const spec = await getDocsSpec();
const categories = Object.keys(spec);
let total = 0;
categories.forEach(cat => {
total += spec[cat].length;
});
console.log(`✅ Loaded ${categories.length} categories with total ${total} endpoints.`);
} catch (e) {
console.error('❌ Error testing docsSpec:', e);
}
})();
---
// FILE: scratch\test-codex-speed.js
const axios = require('axios');
(async () => {
console.log('⚡ [Live Test] กำลังยิง Request ทดสอบความเร็วโมเดล codex...');
const startTime = Date.now();
try {
const res = await axios.post('https://allapi.getth.xyz/api/v1/chat/completions', {
model: 'codex',
messages: [{ role: 'user', content: 'สวัสดี แนะนำตัวสั้นๆ และเขียนฟังก์ชันคำนวณบวกเลข 2 จำนวนในภาษา JavaScript' }]
}, { timeout: 25000 });
const duration = ((Date.now() - startTime) / 1000).toFixed(2);
console.log(`✅ [HTTP Status]: ${res.status}`);
console.log(`⏱️ [เวลาที่ใช้ประมวลผล]: ${duration} วินาที`);
console.log(`🤖 [ข้อความตอบกลับจาก codex]:\n${res.data.choices[0].message.content}`);
} catch (e) {
console.error('❌ Test error:', e.response?.data || e.message);
}
})();
---
// FILE: scratch\test-anilist.js
const axios = require('axios');
async function testAniList() {
try {
const res = await axios.post('https://graphql.anilist.co', {
query: `
query ($search: String) {
Page(page: 1, perPage: 5) {
media(search: $search, type: ANIME) {
id
title {
romaji
english
native
}
coverImage {
extraLarge
large
}
episodes
status
genres
averageScore
description
}
}
}
`,
variables: { search: 'One Piece' }
});
console.log('ANILIST SUCCESS:', JSON.stringify(res.data.data.Page.media[0], null, 2));
} catch (e) {
console.log('ANILIST ERR:', e.message);
}
}
testAniList();
---
// FILE: scratch\test-all-system-apis.js
const axios = require('axios');
const BASE = 'http://localhost:8080';
const categories = [
{
name: 'AI Endpoints',
items: [
{ name: 'DeepSeek V4/R1', path: '/api/ai/deepseek', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'Google Gemini V1', path: '/api/ai/gemini', body: { prompt: 'สวัสดี Gemini' } },
{ name: 'Google Gemini V2', path: '/api/ai/gemini-v2', body: { prompt: 'สวัสดี Gemini V2' } },
{ name: 'Google Gemini V3', path: '/api/ai/gemini-v3', body: { contents: [{ role: 'user', parts: [{ text: 'สวัสดี' }] }] } },
{ name: 'Grok-4 Fast', path: '/api/ai/grok', body: { message: 'สวัสดี Grok' } },
{ name: 'Monica AI', path: '/api/ai/monica', body: { prompt: 'สวัสดี โมนิกา' } },
{ name: 'TranslApp AI', path: '/api/ai/translapp', body: { text: 'Hello', module: 'TRANSLATE', to: 'Thai' } },
{ name: 'ChatbotChatApp', path: '/api/ai/chatbotchatapp', body: { message: 'สวัสดี' } },
{ name: 'Tsundere AI', path: '/api/ai/tsundere', body: { text: 'สวัสดี' } },
]
},
{
name: 'Anime Endpoints',
items: [
{ name: 'Global Multi-Lang Search', path: '/api/anime/global/search?q=Naruto' },
{ name: 'Global Trending Anime', path: '/api/anime/global/trending' },
{ name: 'MAL Search Anime', path: '/api/anime/mal/search?q=One%20Piece' },
{ name: 'MAL Ongoing Anime', path: '/api/anime/mal/ongoing' },
{ name: 'Samehadaku Home', path: '/api/anime/samehadaku/home' },
{ name: 'Oploverz Home', path: '/api/anime/oploverz/home' },
{ name: 'Anichin Home (Donghua)', path: '/api/anime/anichin/home' },
{ name: 'Komiku Manga Search', path: '/api/anime/komiku/search?q=Solo%20Leveling' }
]
},
{
name: 'Tools Endpoints',
items: [
{ name: 'Brat Generator', path: '/api/tools/brat', body: { text: 'PuruBoy API' } },
{ name: 'Quran Surah API', path: '/api/tools/quran?surah=1' },
{ name: 'Sholat Prayer Schedule', path: '/api/tools/sholat?kota=Jakarta' },
{ name: 'Preview HTML Upload', path: '/api/tools/preview-upload', body: { html: 'PuruBoy API
' } },
{ name: 'MLBB Stalker', path: '/api/tools/mlbb?userId=123456&zoneId=1234' },
{ name: 'Audio Edit Filter', path: '/api/tools/audioedit', body: { url: 'https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4', effect: 'bass' } },
{ name: 'MP4 to MP3 Convert', path: '/api/tools/mp4tomp3', body: { url: 'https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4' } }
]
},
{
name: 'Search & Media Endpoints',
items: [
{ name: 'Pinterest Search', path: '/api/search/pinterest?q=Anime%20Wallpaper' },
{ name: 'Lyrics Search', path: '/api/search/lyrics?q=Unravel' },
{ name: 'Google Suggest', path: '/api/search/suggest?q=Nextjs' },
{ name: 'SoundCloud Search', path: '/api/search/soundcloud?q=Alan%20Walker' }
]
}
];
async function runFullSystemTest() {
console.log('====================================================');
console.log('🚀 SYSTEM-WIDE INTEGRATION TEST (ALL API CATEGORIES)');
console.log('====================================================\n');
let total = 0;
let passed = 0;
for (const cat of categories) {
console.log(`\n📌 CATEGORY: ${cat.name}`);
console.log('----------------------------------------------------');
for (const item of cat.items) {
total++;
const start = Date.now();
try {
let resp;
if (item.body) {
resp = await axios.post(BASE + item.path, item.body, { timeout: 15000 });
} else {
resp = await axios.get(BASE + item.path, { timeout: 15000 });
}
const elapsed = Date.now() - start;
passed++;
let sample = typeof resp.data === 'string' ? resp.data.substring(0, 100) : JSON.stringify(resp.data).substring(0, 100);
console.log(` ✅ [PASS] ${item.name} (${elapsed}ms) - Status: ${resp.status}\n Response: ${sample}`);
} catch (err) {
const elapsed = Date.now() - start;
const status = err.response?.status || 'ERR';
const msg = err.response?.data?.error || (typeof err.response?.data === 'string' ? err.response.data.substring(0, 80) : err.message);
console.log(` ❌ [FAIL] ${item.name} (${elapsed}ms) - Status: ${status}\n Error: ${msg}`);
}
}
}
console.log('\n====================================================');
console.log(`📊 FINAL TEST SUMMARY: ${passed}/${total} API ENDPOINTS PASSED SUCCESSFUL (${Math.round((passed/total)*100)}%)`);
console.log('====================================================\n');
}
runFullSystemTest();
---
// FILE: scratch\test-ai-routes.js
const axios = require('axios');
const BASE_URL = 'http://localhost:8080';
const endpoints = [
{ name: 'DeepSeek (V4/R1)', path: '/api/ai/deepseek', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'Gemini V1', path: '/api/ai/gemini', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'Gemini V2', path: '/api/ai/gemini-v2', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'Gemini V3', path: '/api/ai/gemini-v3', body: { contents: [{ role: 'user', parts: [{ text: 'สวัสดี คุณคือใคร' }] }] } },
{ name: 'Grok AI', path: '/api/ai/grok', body: { message: 'สวัสดี คุณคือใคร' } },
{ name: 'Flux Image', path: '/api/ai/flux', body: { prompt: 'แมวน่ารักในหมวกพ่อมด' } },
{ name: 'Flux V2 Image', path: '/api/ai/flux-v2', body: { prompt: 'แมวน่ารักในหมวกพ่อมด' } },
{ name: 'LetMeGPT', path: '/api/ai/letmegpt', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'Monica AI', path: '/api/ai/monica', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'NoteGPT', path: '/api/ai/notegpt', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'QuillBot', path: '/api/ai/quillbot', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'ScreenApp Vision', path: '/api/ai/screenapp', body: { url: 'https://puruboy-api.vercel.app/favicon.jpg', question: 'อธิบายรูปภาพนี้เป็นภาษาไทย' } },
{ name: 'Svara TTS', path: '/api/ai/svara', body: { text: 'สวัสดี ยินดีต้อนรับสู่ระบบ API', voice: 'bella' } },
{ name: 'Tsundere AI', path: '/api/ai/tsundere', body: { text: 'สวัสดี' } },
{ name: 'Unlimited AI', path: '/api/ai/unlimited', body: { prompt: 'สวัสดี คุณคือใคร' } },
{ name: 'ChatbotChatApp', path: '/api/ai/chatbotchatapp', body: { message: 'สวัสดี คุณคือใคร' } },
{ name: 'ChatEspanyol', path: '/api/ai/chatespanyol', body: { message: 'สวัสดี คุณคือใคร' } },
{ name: 'Dracin AI', path: '/api/ai/dracin', body: { prompt: 'สวัสดี ยินดีต้อนรับสู่โลกอนิเมะ' } },
{ name: 'TranslApp AI', path: '/api/ai/translapp', body: { text: 'Hello world', module: 'TRANSLATE', to: 'Thai' } },
];
async function testEndpoint(ep) {
const start = Date.now();
try {
const resp = await axios.post(BASE_URL + ep.path, ep.body, { timeout: 12000 });
const elapsed = Date.now() - start;
let sample = typeof resp.data === 'string' ? resp.data.substring(0, 150) : JSON.stringify(resp.data).substring(0, 150);
return `[PASS] ${ep.name} (${elapsed}ms) - Status: ${resp.status}\n Response: ${sample}`;
} catch (errPost) {
try {
const respGet = await axios.get(BASE_URL + ep.path + '?prompt=สวัสดี&text=สวัสดี&message=สวัสดี', { timeout: 12000 });
const elapsed = Date.now() - start;
let sample = typeof respGet.data === 'string' ? respGet.data.substring(0, 150) : JSON.stringify(respGet.data).substring(0, 150);
return `[PASS] ${ep.name} (GET ${elapsed}ms) - Status: ${respGet.status}\n Response: ${sample}`;
} catch (errGet) {
const elapsed = Date.now() - start;
const status = errPost.response?.status || errGet.response?.status || 'ERR';
const msg = errPost.response?.data?.error || (typeof errPost.response?.data === 'string' ? errPost.response.data.substring(0, 80) : errPost.message);
return `[FAIL] ${ep.name} (${elapsed}ms) - Status: ${status}\n Error: ${msg}`;
}
}
}
async function runParallel() {
console.log('=== PARALLEL AI ENDPOINTS TEST (THAI MESSAGES) ===\n');
const results = await Promise.all(endpoints.map(testEndpoint));
results.forEach(res => {
console.log(res);
console.log('--------------------------------------------------');
});
}
runParallel();
---
// FILE: public\manifest.json
{
"name": "PuruBoy API",
"short_name": "PuruBoy API",
"description": "Platform REST API gratis untuk developer Indonesia dengan fitur AI, Downloader, Anime, dan Tools.",
"start_url": "/",
"display": "standalone",
"background_color": "#09090b",
"theme_color": "#ec4899",
"icons": [
{
"src": "/favicon.jpg",
"sizes": "192x192",
"type": "image/jpeg"
},
{
"src": "/favicon.jpg",
"sizes": "512x512",
"type": "image/jpeg"
}
],
"categories": ["developer tools", "web services", "api"],
"lang": "id",
"orientation": "any"
}
---
// FILE: public\google41f3f05fef8cd977.html
google-site-verification: google41f3f05fef8cd977.html
---
// FILE: public\fastupdate.html
System Updater
Fast Update
AI-Powered Code Implementation
Context Extraction
Download the latest source code to give full context to the AI.
Download Context
Prompt Generation
Apply Changes
---
// FILE: public\docs.json
{
"ai": [
{
"title": "Blackbox AI Coding Assistant",
"summary": "สนทนากับ Blackbox AI VscodeAgent",
"description": "สนทนาและขอความช่วยเหลือด้านการเขียนโค้ด วิเคราะห์บั๊ก และเขียนฟังก์ชันโปรแกรมด้วย Blackbox AI",
"method": "POST",
"path": "/api/ai/blackbox",
"responseType": "json",
"example": "async function chatBlackbox() {\n const res = await fetch('/api/ai/blackbox', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"เขียนฟังก์ชัน JWT verify ใน Node.js\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "คำสั่งหรือคำถามเกี่ยวกับการเขียนโปรแกรม",
"required": true
}
]
},
{
"title": "ChatBotChatApp AI",
"summary": "สนทนากับ AI ผ่าน ChatBotChatApp Engine",
"description": "สนทนากับ AI หลากหลายโมเดล (GPT, DeepSeek R1/V3, Qwen, Mistral) ตอบคำถามภาษาไทยและประมวลผลคำสั่งได้อย่างมีประสิทธิภาพ",
"method": "POST",
"path": "/api/ai/chatbotchatapp",
"responseType": "json",
"example": "async function chat() {\n const res = await fetch('/api/ai/chatbotchatapp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"message\": \"สวัสดี มีอะไรแนะนำวันนี้ไหม\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "message",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือคำสั่งภาษาไทยสำหรับ AI",
"required": true
},
{
"name": "model",
"in": "body",
"type": "string",
"description": "เลือกรุ่นโมเดล AI (auto, gpt5, gpt_oss, deepseek_r1, deepseek_v3, qwen_35, mistral_large3, pixtral, devstral2)",
"required": false
}
]
},
{
"title": "Chat Espanyol AI",
"summary": "สนทนากับ ChatEspanyol AI (รองรับหลายภาษา)",
"description": "สนทนากับ AI สนับสนุนการรักษาสถานะบทสนทนาแบบต่อเนื่องด้วย sessionId และ conversationUuid",
"method": "POST",
"path": "/api/ai/chatespanyol",
"responseType": "json",
"example": "async function chat() {\n const response = await fetch('/api/ai/chatespanyol', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"message\": \"สวัสดี มีอะไรแนะนำในการท่องเที่ยวไหม\" \n })\n });\n const data = await response.json();\n console.log(data);\n }",
"params": [
{
"name": "message",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือคำสั่งภาษาไทยสำหรับ AI",
"required": true
},
{
"name": "sessionId",
"in": "body",
"type": "string",
"description": "Session ID สำหรับรักษาบริบทบทสนทนาต่อเนื่อง (ตัวเลือก)",
"required": false
},
{
"name": "conversationUuid",
"in": "body",
"type": "string",
"description": "UUID บทสนทนา (ตัวเลือก)",
"required": false
}
]
},
{
"title": "DeepSeek V4 / R1 AI Chat",
"summary": "สนทนากับ DeepSeek V4 Flash / DeepSeek R1 Engine",
"description": "สนทนากับ DeepSeek AI โมเดลเวอร์ชันใหม่ล่าสุด (DeepSeek-V4 Flash / DeepSeek-R1 Reasoning / DeepSeek-V3) ตอบคำถามเป็นภาษาไทย วิเคราะห์โค้ด และคิดเชิงเหตุผลได้อย่างแม่นยำ",
"method": "POST",
"path": "/api/ai/deepseek",
"responseType": "json",
"example": "fetch('/api/ai/deepseek', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n prompt: 'อธิบายทฤษฎีสัมพัทธภาพแบบเข้าใจง่ายภาษาไทย',\n model: 'deepseek/deepseek-r1'\n })\n }).then(res => res.json()).then(console.log);",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือคำสั่งภาษาไทยสำหรับ AI (พารามิเตอร์หลัก)",
"required": true
},
{
"name": "model",
"in": "body",
"type": "string",
"description": "รุ่นโมเดลที่ต้องการใช้งาน: 'deepseek/deepseek-v4-flash' (ค่าเริ่มต้น), 'deepseek/deepseek-r1', หรือ 'deepseek/deepseek-v3.2'",
"required": false
}
]
},
{
"title": "DeepSeek V4 - Free AI Chat",
"summary": "Chat AI gratis via deep-seek.ai (proxy OpenRouter).",
"description": "Mengirim pesan ke DeepSeek AI secara gratis melalui deep-seek.ai. Mendukung model DeepSeek V4 Flash, R1, dan V3. Semua response menggunakan SSE (Server-Sent Events) dengan reasoning visible.",
"method": "POST",
"path": "/api/ai/deepseek/v4",
"responseType": "json",
"example": "fetch('https://allapi.getth.xyz/api/ai/deepseek/v4', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n message: 'Buatkan saya kalkulator sederhana di Python',\n model: 'deepseek/deepseek-v4-flash',\n history: []\n })\n }).then(res => res.json()).then(console.log);",
"params": [
{
"name": "message",
"in": "body",
"type": "string",
"description": "Pesan untuk AI (wajib).",
"required": true
},
{
"name": "model",
"in": "body",
"type": "string",
"description": "Model yang digunakan. (opsional)",
"required": false,
"choices": [
{
"value": "deepseek/deepseek-v4-flash",
"label": "DeepSeek V4 Flash (Cepat & Efisien)"
},
{
"value": "deepseek/deepseek-r1",
"label": "DeepSeek R1 (Reasoning Mendalam)"
},
{
"value": "deepseek/deepseek-v3.2",
"label": "DeepSeek V3 (Balanced)"
}
]
},
{
"name": "history",
"in": "body",
"type": "array",
"description": "Riwayat percakapan [{role, content}] (opsional)",
"required": false
}
]
},
{
"title": "Dracin TTS (SSE)",
"summary": "AI Voice gaya Drama China (Dracin) dengan SSE fakta unik.",
"description": "Mengubah teks menjadi suara dengan nada ala narator drama China. Menggunakan SSE (Server-Sent Events) untuk mengirim fakta unik random selama proses generating audio.",
"method": "POST",
"path": "/api/ai/dracin",
"responseType": "json",
"example": "// Contoh request\n const res = await fetch('/api/ai/dracin', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n \"text\": \"Halo, selamat datang di dunia drama China.\",\n \"music\": true,\n \"speed\": 1.0,\n \"volume\": 0.3\n })\n });\n // Response berupa SSE Stream:\n // event: status { \"message\": \"Memproses teks menjadi suara...\" }\n // event: fact { \"fact\": \"Kumis kucing...\" }\n // event: status { \"message\": \"Mengupload audio...\" }\n // event: result { \"success\": true, \"result\": { \"text\": \"...\", \"audio\": \"...\" } }",
"params": [
{
"name": "text",
"in": "body",
"type": "string",
"description": "Teks yang akan diubah menjadi suara.",
"required": true
},
{
"name": "music",
"in": "body",
"type": "boolean",
"description": "Menggunakan musik latar? Default: true.",
"required": false
},
{
"name": "speed",
"in": "body",
"type": "number",
"description": "Kecepatan bicara (0.5 - 2.0). Default: 1.0.",
"required": false
},
{
"name": "volume",
"in": "body",
"type": "number",
"description": "Volume musik latar (0.1 - 1.0). Default: 0.3.",
"required": false
}
]
},
{
"title": "Flux V2 - Image Generator",
"summary": "Generate Gambar Flux (HF Space).",
"description": "Menghasilkan gambar menggunakan model FLUX Pro dari HF Space (llamameta-fake-flux-pro-unlimited). Gratis tanpa API key, menggunakan antrian Gradio. Endpoint ini menggunakan Server-Sent Events (SSE).",
"method": "POST",
"path": "/api/ai/flux-v2",
"responseType": "json",
"example": "// Contoh penggunaan (Membaca stream SSE di client)\n async function generateImage() {\n const response = await fetch('/api/ai/flux-v2', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"prompt\": \"Kucing lucu pakai topi, realistik\",\n \"model\": \"turbo\"\n })\n });\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n \n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const text = decoder.decode(value);\n console.log(\"Stream:\", text);\n \n if(text.includes('[true]')) {\n const resultUrl = text.replace('[true]', '').trim();\n console.log(\"Result JSON URL:\", resultUrl);\n // fetch(resultUrl).then(res => res.json()).then(console.log);\n }\n }\n }\n \n generateImage();",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "Deskripsi gambar yang ingin dibuat (wajib).",
"required": true
},
{
"name": "model",
"in": "body",
"type": "string",
"description": "Model yang digunakan. (opsional)",
"required": false,
"choices": [
{
"value": "turbo",
"label": "Turbo (Cepat)"
},
{
"value": "standard",
"label": "Standard (Detail)"
},
{
"value": "hd",
"label": "HD (High Quality)"
}
]
}
]
},
{
"title": "Gemini AI Chat V1",
"summary": "สนทนากับ Google Gemini AI",
"description": "ส่งข้อความคำถามภาษาไทยเพื่อสนทนาและขอความช่วยเหลือจาก Google Gemini AI",
"method": "POST",
"path": "/api/ai/gemini",
"responseType": "json",
"example": "async function chatGemini() {\n const response = await fetch('/api/ai/gemini', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"สวัสดี Gemini มีอะไรแนะนำสำหรับการเรียนเขียนโปรแกรมไหม\" })\n });\n \n const data = await response.json();\n console.log(data);\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือคำสั่งภาษาไทยสำหรับ Gemini",
"required": true
}
]
},
{
"title": "Gemini AI V2 Chat",
"summary": "สนทนากับ Google Gemini AI V2 (BatchEngine)",
"description": "สนทนาภาษาไทยกับ Google Gemini V2 เสถียรสูง เหมาะสำหรับคำถามทั่วไป และการวิเคราะห์คำตอบ",
"method": "POST",
"path": "/api/ai/gemini-v2",
"responseType": "json",
"example": "async function chatGeminiV2() {\n const response = await fetch('/api/ai/gemini-v2', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"สวัสดี Gemini V2 ช่วยเขียนโครงสร้าง HTML5 ให้หน่อย\" })\n });\n \n const data = await response.json();\n console.log(data);\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "ข้อความคำถามภาษาไทยสำหรับ Gemini V2",
"required": true
}
]
},
{
"title": "Gemini AI V3",
"summary": "Chat via Google Gemini (Hybrid V2+V1 Fallback) — format payload standar Gemini API.",
"description": "Menerima format payload standar Google Gemini API dan mengembalikan response JSON murni dari Gemini SDK. Menggabungkan metode V2 (BatchExecute) dan V1 (StreamGenerate) dengan fallback otomatis. Maksimal 3 kali percobaan. Response adalah data ASLI dari Gemini (raw JSON SDK), bukan wrapper buatan.",
"method": "POST",
"path": "/api/ai/gemini-v3",
"responseType": "json",
"example": "# RAW Format — Langsung executable via curl:\n curl -X POST \"https://allapi.getth.xyz/api/ai/gemini-v3\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"contents\": [\n {\n \"role\": \"user\",\n \"parts\": [\n { \"text\": \"Halo! Siapa presiden Indonesia pertama?\" }\n ]\n }\n ],\n \"systemInstruction\": {\n \"parts\": [\n { \"text\": \"Kamu adalah asisten AI yang cerdas, ramah, dan menjawab dengan singkat.\" }\n ]\n },\n \"generationConfig\": {\n \"temperature\": 0.7,\n \"topP\": 0.9,\n \"topK\": 40\n }\n }'",
"params": [
{
"name": "contents",
"in": "body",
"type": "Array",
"description": "Array of content objects (role + parts). Riwayat percakapan. Minimal 1 item.",
"required": true
},
{
"name": "systemInstruction",
"in": "body",
"type": "Object",
"description": "System instruction untuk mengatur perilaku AI. Berisi `parts` array.",
"required": false
},
{
"name": "generationConfig",
"in": "body",
"type": "Object",
"description": "Konfigurasi generation (temperature, topP, topK, dll).",
"required": false
}
],
"guide": "## Format Payload (RAW — Standar Gemini API)\n \n Kirim payload **RAW JSON** langsung ke endpoint. Contoh siap eksekusi:\n \n ### 🔹 Single-turn (pertanyaan tunggal)\n \n ```bash\n curl -X POST \"https://allapi.getth.xyz/api/ai/gemini-v3\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"contents\": [\n {\n \"role\": \"user\",\n \"parts\": [\n { \"text\": \"Halo! Siapa presiden Indonesia pertama?\" }\n ]\n }\n ],\n \"systemInstruction\": {\n \"parts\": [\n { \"text\": \"Kamu adalah asisten AI yang cerdas, ramah, dan menjawab dengan singkat.\" }\n ]\n },\n \"generationConfig\": {\n \"temperature\": 0.7,\n \"topP\": 0.9,\n \"topK\": 40\n }\n }'\n ```\n \n ### 🔹 Multi-turn (percakapan dengan konteks)\n \n ```bash\n curl -X POST \"https://allapi.getth.xyz/api/ai/gemini-v3\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"contents\": [\n { \"role\": \"user\", \"parts\": [{ \"text\": \"Halo, nama saya Budi\" }] },\n { \"role\": \"model\", \"parts\": [{ \"text\": \"Halo Budi! Ada yang bisa saya bantu?\" }] },\n { \"role\": \"user\", \"parts\": [{ \"text\": \"Siapa nama saya?\" }] }\n ],\n \"generationConfig\": {\n \"temperature\": 0.3\n }\n }'\n ```\n \n ---\n \n ## ⚡ RAW Internal RPC Payload (batchexecute)\n \n Di belakang layar, endpoint ini mengirim request ke Google Gemini via protokol **batchexecute** dengan format RAW berikut:\n \n ```\n POST https://gemini.google.com/_/BardChatUi/data/batchexecute\n Content-Type: application/x-www-form-urlencoded;charset=UTF-8\n \n f.req=[[[\"q4uTj\",\"[null,\\\"{\\\\\\\"contents\\\\\\\":[...]}\\\",1,\\\"caea8d35955a\\\"]\",null,\"generic\"]]]&at=\n ```\n \n ### Struktur RPC Array:\n \n | Level | Data | Keterangan |\n |-------|------|------------|\n | 1 | `f.req` | Array RPC eksternal (`[[[\"q4uTj\", ...]]]`) |\n | 2 | `q4uTj` | Method identifier untuk Gemini chat |\n | 3 | Inner array | `[null, stringifiedRequestBody, 1, \"caea8d35955a\"]` |\n | 4 | `at` | Token `SNlM0e` (kosong/tidak diperlukan) |\n \n ---\n \n ## Response Format (RAW Gemini SDK)\n \n Response adalah **JSON murni dari Gemini SDK** — bukan wrapper buatan. Contoh:\n \n ```json\n {\n \"candidates\": [\n {\n \"content\": {\n \"parts\": [\n { \"text\": \"Presiden pertama Indonesia adalah Ir. Soekarno.\" }\n ],\n \"role\": \"model\"\n },\n \"finishReason\": \"STOP\",\n \"index\": 0,\n \"safetyRatings\": [\n { \"category\": \"HARM_CATEGORY_HARASSMENT\", \"probability\": \"NEGLIGIBLE\" },\n { \"category\": \"HARM_CATEGORY_HATE_SPEECH\", \"probability\": \"NEGLIGIBLE\" }\n ]\n }\n ],\n \"usageMetadata\": {\n \"promptTokenCount\": 15,\n \"candidatesTokenCount\": 25,\n \"totalTokenCount\": 40\n }\n }\n ```\n \n ## Catatan Penting\n \n - **Field `contents` wajib** diisi minimal 1 item dengan `role: \"user\"`.\n - **Format sudah standar Gemini API** — bisa pakai SDK Google langsung.\n - **Auto retry** 3x dengan fallback V2 → V1 → V2 jika salah satu metode gagal.\n - **Tidak perlu API key** — gratis."
},
{
"title": "Grok-4 Fast AI Chat",
"summary": "สนทนากับ Grok-4 Fast AI",
"description": "สนทนากับโมเดล Grok-4 Fast ตอบสนองรวดเร็วทันใจ รองรับการถามตอบภาษาไทย ความรู้ทั่วไป และข่าวสาร",
"method": "POST",
"path": "/api/ai/grok",
"responseType": "json",
"example": "async function chatGrok() {\n const response = await fetch('/api/ai/grok', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"message\": \"สวัสดี Grok ใครคือผู้คิดค้นภาษา JavaScript\" \n })\n });\n \n const data = await response.json();\n console.log(data);\n }",
"params": [
{
"name": "message",
"in": "body",
"type": "string",
"description": "ข้อความคำถามภาษาไทยที่ต้องการถาม Grok AI",
"required": true
}
]
},
{
"title": "LetMeGPT AI Chat",
"summary": "สนทนากับ LetMeGPT AI",
"description": "สนทนากับโมเดล LetMeGPT ตอบคำถามความรู้ทั่วไป ตอบกลับรวดเร็ว",
"method": "POST",
"path": "/api/ai/letmegpt",
"responseType": "json",
"example": "async function chat() {\n const res = await fetch('/api/ai/letmegpt', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"message\": \"สวัสดี คุณคือใคร\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "message",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือคำสั่งภาษาไทยสำหรับ AI",
"required": true
}
]
},
{
"title": "Llama & Qwen Coder AI (Smart Dual-Engine Edition)",
"summary": "สนทนากับ Qwen 3.8 Max, Qwen 2.5 Coder 32B, CodeX, Llama 3.1 405B & DeepSeek V3 AI",
"description": "ระบบประมวลผลคู่: Auto-Detect สั่งเขียนโค้ดด่วน (ตอบไวใน 1 วินาที) หรือวิเคราะห์บั๊กเชิงลึก (ตอบละเอียดเต็มรูปแบบ)",
"method": "POST",
"path": "/api/ai/llamacoder",
"responseType": "json",
"example": "async function chatLlamaCoder() {\n const res = await fetch('/api/ai/llamacoder', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"เขียนระบบยืนยันตัวตนด้วย Next.js App Router และ JWT แบบเต็มไฟล์\", \"model\": \"qwen-3.8-max\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "คำถาม คำสั่ง หรือโค้ดภาษาไทยที่ต้องการตรวจบั๊กและเขียนใหม่เต็มระบบ",
"required": true
},
{
"name": "messages",
"in": "body",
"type": "array",
"description": "ประวัติการสนทนาสำหรับ Cursor IDE / Hermes IDE / Multi-Turn Chat",
"required": false
},
{
"name": "model",
"in": "body",
"type": "string|number",
"description": "1: Qwen2.5-Coder-32B, 2: Llama-3.1-405B, 3: Llama-3.3-70B, 4: DeepSeek-V3, 5: Qwen-3.8-Max, 6: Qwen-3",
"required": false
}
]
},
{
"title": "Monica AI Chat",
"summary": "สนทนากับ Monica AI Assistant",
"description": "สนทนากับ Monica AI Assistant ตอบคำถามภาษาไทย พร้อมข้อเสนอแนะคำถามถัดไป (Follow-up suggestions)",
"method": "POST",
"path": "/api/ai/monica",
"responseType": "json",
"example": "fetch('/api/ai/monica', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"สวัสดี โมนิกา มีคำแนะนำในการดูแลสุขภาพอย่างไรบ้าง\" })\n }).then(res => res.json()).then(console.log);",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "ข้อความคำถามภาษาไทยสำหรับ Monica AI",
"required": true
}
]
},
{
"title": "NoteGPT Multi-Model AI Chat",
"summary": "สนทนากับ NoteGPT Multi-Model AI (Gemini, DeepSeek, GPT)",
"description": "สนทนาภาษาไทยกับโมเดล AI ผ่าน NoteGPT รองรับโหมด Deep Think (Reasoning คิดเชิงลึก) และการเลือกโมเดล (Gemini, DeepSeek R1, GPT)",
"method": "POST",
"path": "/api/ai/notegpt",
"responseType": "json",
"example": "async function askNoteGPT() {\n const response = await fetch('/api/ai/notegpt', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"prompt\": \"อธิบายการทำงานของ Quantum Computer แบบเข้าใจง่าย\",\n \"model\": \"TA/deepseek-ai/DeepSeek-R1\",\n \"chat_mode\": \"deep_think\"\n })\n });\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n \n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const text = decoder.decode(value);\n console.log(text);\n }\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือคำสั่งภาษาไทยสำหรับ AI",
"required": true
},
{
"name": "model",
"in": "body",
"type": "string",
"description": "เลือกรุ่นโมเดล: 'gemini-3-flash-preview' (ค่าเริ่มต้น), 'TA/deepseek-ai/DeepSeek-R1', 'gpt-5-mini'",
"required": false
},
{
"name": "chat_mode",
"in": "body",
"type": "string",
"description": "โหมดบทสนทนา: 'standard' (ค่าเริ่มต้น), 'deep_think', 'guided_learning'",
"required": false
}
]
},
{
"title": "QuillBot AI Chat & Paraphraser",
"summary": "สนทนาและเรียบเรียงข้อความกับ QuillBot AI",
"description": "สนทนากับโมเดล QuillBot AI สำหรับการตอบคำถามภาษาไทย การเรียบเรียงข้อความ (Paraphrase) และการค้นคว้าข้อมูล",
"method": "POST",
"path": "/api/ai/quillbot",
"responseType": "json",
"example": "async function askQuillbot() {\n const response = await fetch('/api/ai/quillbot', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"message\": \"สวัสดี ช่วยเรียบเรียงข้อความนี้ให้สละสลวยยิ่งขึ้น\"\n })\n });\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n \n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const text = decoder.decode(value);\n console.log(text);\n }\n }",
"params": [
{
"name": "message",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือข้อความภาษาไทยที่ต้องการเรียบเรียง",
"required": true
}
]
},
{
"title": "ScreenApp Vision",
"summary": "AI Image Analysis (Gemini).",
"description": "Menganalisis gambar dan menjawab pertanyaan terkait gambar tersebut menggunakan model Gemini 2.0 Flash via ScreenApp proxy. Mendukung analisis visual yang detail.",
"method": "POST",
"path": "/api/ai/screenapp",
"responseType": "json",
"example": "async function askImage() {\n const res = await fetch('/api/ai/screenapp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n \"url\": \"https://puruboy-api.vercel.app/favicon.jpg\",\n \"question\": \"Jelaskan gambar ini dengan detail\"\n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik gambar yang akan dianalisis.",
"required": true
},
{
"name": "question",
"in": "body",
"type": "string",
"description": "Pertanyaan tentang gambar tersebut.",
"required": true
}
]
},
{
"title": "Svara TTS",
"summary": "Membuat audio dari teks (TTS) dengan Svara AI.",
"description": "Menghasilkan file audio dari teks yang diberikan menggunakan berbagai pilihan suara. Credit: Daffa dari nbscript.",
"method": "POST",
"path": "/api/ai/svara",
"responseType": "json",
"example": "// Contoh penggunaan\n async function generateSpeech() {\n try {\n const response = await fetch('/api/ai/svara', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"text\": \"Halo, selamat datang di NextA API.\",\n \"voice\": \"bella\" \n })\n });\n \n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error(\"Gagal melakukan permintaan:\", error.message);\n }\n }",
"params": [
{
"name": "text",
"in": "body",
"type": "string",
"description": "Teks yang akan diubah menjadi suara (maksimal 300 karakter).",
"required": true
},
{
"name": "voice",
"in": "body",
"type": "string",
"description": "Nama suara yang akan digunakan. Contoh: 'bella', 'adam', 'arjun'.",
"required": true
}
]
},
{
"title": "Translapp AI",
"summary": "AI Text Processing dengan Translapp.",
"description": "Memproses teks dengan berbagai modul AI seperti ringkasan, parafrase, terjemahan, penyesuaian nada, dll.",
"method": "POST",
"path": "/api/ai/translapp",
"responseType": "json",
"example": "async function processText() {\n try {\n const response = await fetch('/api/ai/translapp', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"text\": \"Hello, how are you?\",\n \"module\": \"TRANSLATE\", \n \"to\": \"jawa\"\n })\n });\n \n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Error:', error);\n }\n }\n \n processText();",
"params": [
{
"name": "text",
"in": "body",
"type": "string",
"description": "Teks yang akan diproses.",
"required": true
},
{
"name": "module",
"in": "body",
"type": "string",
"description": "Modul pemrosesan: SUMMARIZE, PARAPHRASE, EXPAND, TONE, TRANSLATE, REPLY, GRAMMAR.",
"required": true
},
{
"name": "to",
"in": "body",
"type": "string",
"description": "Parameter tambahan tergantung modul (bahasa target untuk TRANSLATE, nada untuk TONE, dll).",
"required": false
},
{
"name": "customTone",
"in": "body",
"type": "string",
"description": "Nada kustom jika memilih TONE dengan opsi \"Other\".",
"required": false
}
]
},
{
"title": "Tsundere AI Voice & TTS",
"summary": "สร้างเสียงและข้อความ AI สไตล์ซึนเดเระ (Tsundere)",
"description": "แปลงข้อความให้เป็นเสียงและบทสนทนาสไตล์ซึนเดเระ ส่งคืนทั้งข้อความและ URL ไฟล์เสียง Audio MP3",
"method": "POST",
"path": "/api/ai/tsundere",
"responseType": "json",
"example": "async function speakTsundere() {\n const res = await fetch('/api/ai/tsundere', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"text\": \"สวัสดี ไม่ได้ตั้งใจจะทักทายหรอกนะ!\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "text",
"in": "body",
"type": "string",
"description": "ข้อความภาษาไทยที่ต้องการเปลี่ยนเป็นเสียงซึนเดเระ",
"required": true
}
]
},
{
"title": "Unlimited AI Chat",
"summary": "สนทนากับ Unlimited AI Chat (Reasoning)",
"description": "สนทนาตอบคำถามภาษาไทยกับ Unlimited AI ประมวลผลรวดเร็ว ไม่จำกัดจำนวนครั้ง",
"method": "POST",
"path": "/api/ai/unlimited",
"responseType": "json",
"example": "async function chat() {\n const response = await fetch('/api/ai/unlimited', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"prompt\": \"แต่งนิทานสั้นๆ ให้ฟังหน่อย\"\n })\n });\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n \n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const text = decoder.decode(value);\n console.log(text);\n }\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "ข้อความคำถามหรือสั่งการภาษาไทยสำหรับ AI",
"required": true
}
]
}
],
"anime": [
{
"title": "Anichin Detail",
"summary": "Detail Donghua Anichin.",
"description": "Mengambil informasi lengkap seri donghua dari Anichin, termasuk sinopsis, genre, link batch, dan daftar episode.",
"method": "GET",
"path": "/api/anime/anichin/detail",
"responseType": "json",
"example": "async function getDetail() {\n const res = await fetch('/api/anime/anichin/detail?url=/seri/battle-through-the-heavens-season-5/');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "Path atau URL donghua (contoh: /seri/battle-through-the-heavens-season-5/).",
"required": true
}
]
},
{
"title": "Anichin By Genre",
"summary": "Donghua By Genre.",
"description": "Mengambil daftar donghua berdasarkan slug genre tertentu dari Anichin. Mendukung pagination.",
"method": "GET",
"path": "/api/anime/anichin/genre",
"responseType": "json",
"example": "async function getByGenre() {\n const res = await fetch('/api/anime/anichin/genre?slug=fantasy');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "slug",
"in": "query",
"type": "string",
"description": "Slug genre (contoh: \"fantasy\", \"action\").",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
}
]
},
{
"title": "Anichin Genre List",
"summary": "Daftar Genre Anichin.",
"description": "Mengambil daftar semua genre donghua yang tersedia di Anichin beserta slug-nya.",
"method": "GET",
"path": "/api/anime/anichin/genres",
"responseType": "json",
"example": "async function getGenres() {\n const res = await fetch('/api/anime/anichin/genres');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Anichin Home",
"summary": "Beranda Anichin.",
"description": "Mengambil data dari halaman utama Anichin, mencakup featured slider, populer hari ini, rilis terbaru, dan update sidebar.",
"method": "GET",
"path": "/api/anime/anichin/home",
"responseType": "json",
"example": "async function getHome() {\n const res = await fetch('/api/anime/anichin/home');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Anichin Schedule",
"summary": "Jadwal Rilis Anichin.",
"description": "Mengambil jadwal rilis donghua mingguan di Anichin.",
"method": "GET",
"path": "/api/anime/anichin/schedule",
"responseType": "json",
"example": "async function getSchedule() {\n const res = await fetch('/api/anime/anichin/schedule');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Anichin Search",
"summary": "Pencarian Anichin.",
"description": "Mencari seri donghua di Anichin berdasarkan kata kunci.",
"method": "GET",
"path": "/api/anime/anichin/search",
"responseType": "json",
"example": "async function search() {\n const res = await fetch('/api/anime/anichin/search?q=Btth');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (contoh: \"Btth\").",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
}
]
},
{
"title": "Anichin Stream",
"summary": "Link Streaming Anichin.",
"description": "Mengekstrak link streaming (iframe), link download per resolusi, dan navigasi (prev/next) episode dari Anichin.",
"method": "GET",
"path": "/api/anime/anichin/stream",
"responseType": "json",
"example": "async function getStream() {\n const res = await fetch('/api/anime/anichin/stream?url=/battle-through-the-heavens-season-5-episode-01-subtitle-indonesia/');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "Path atau URL episode (contoh: /battle-through-the-heavens-season-5-episode-01-subtitle-indonesia/).",
"required": true
}
]
},
{
"title": "Global Multi-Language Anime Search",
"summary": "ค้นหาอนิเมะหลายภาษา (English, Japanese, Thai, Spanish, French, etc.)",
"description": "ค้นหาข้อมูลอนิเมะจากฐานข้อมูลระดับโลก (AniList GraphQL + Kitsu Engine) รองรับชื่อภาษาไทย อังกฤษ ญี่ปุ่น และภาษาอื่นๆ ทั่วโลก พร้อมข้อมูล Trailer YouTube, รูปภาพหน้าปก HD, ประเภท, รายชื่อตอน, คะแนนวิจารณ์ และเรื่องย่อ",
"method": "GET",
"path": "/api/anime/global/search",
"responseType": "json",
"example": "// ตัวอย่างการค้นหาอนิเมะภาษาไทย/อังกฤษ\n fetch('/api/anime/global/search?q=Demon Slayer')\n .then(res => res.json())\n .then(data => console.log(data));",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "ชื่ออนิเมะภาษาไทย/อังกฤษ/ญี่ปุ่น ที่ต้องการค้นหา",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "หน้าผลลัพธ์ (Default: 1)",
"required": false
},
{
"name": "limit",
"in": "query",
"type": "number",
"description": "จำนวนรายการต่อหน้า (Default: 20)",
"required": false
}
]
},
{
"title": "Global Trending Anime",
"summary": "ดึงอันดับอนิเมะฮิตติดเทรนด์ระดับโลกหลายภาษา",
"description": "ดึงรายการอนิเมะที่กำลังเป็นกระแสยอดนิยมติดเทรนด์ระดับโลก รวบรวมข้อมูลชื่อเรื่องภาษาไทย อังกฤษ ญี่ปุ่น รูปภาพ HD เรื่องย่อ คะแนนรีวิว และตัวอย่างวิดีโอ Trailer",
"method": "GET",
"path": "/api/anime/global/trending",
"responseType": "json",
"example": "fetch('/api/anime/global/trending')\n .then(res => res.json())\n .then(data => console.log(data));",
"params": [
{
"name": "page",
"in": "query",
"type": "number",
"description": "หน้าผลลัพธ์ (Default: 1)",
"required": false
},
{
"name": "limit",
"in": "query",
"type": "number",
"description": "จำนวนรายการต่อหน้า (Default: 20)",
"required": false
}
]
},
{
"title": "Komiku Detail",
"summary": "Detail Komik.",
"description": "Mengambil informasi detail dan daftar chapter dari komik tertentu.",
"method": "GET",
"path": "/api/anime/komiku/detail",
"responseType": "json",
"example": "async function getDetail() {\n const res = await fetch('/api/anime/komiku/detail?url=https://komiku.org/manga/solo-leveling-id/');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Komik (contoh: https://komiku.org/manga/solo-leveling-id/).",
"required": true
}
]
},
{
"title": "Komiku Home",
"summary": "Update Terbaru Komiku.",
"description": "Mengambil daftar update manga/manhwa/manhua terbaru dari Komiku.",
"method": "GET",
"path": "/api/anime/komiku/home",
"responseType": "json",
"example": "async function getUpdates() {\n const res = await fetch('/api/anime/komiku/home');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Komiku Image Proxy",
"summary": "Proxy gambar komiku behind Cloudflare.",
"description": "Mengambil gambar dari CDN Komiku via server-side (cloudscraper) biar client gak kena CF block.",
"method": "GET",
"path": "/api/anime/komiku/image-proxy",
"responseType": "json",
"example": "async function getImage() {\\r const res = await fetch('/api/anime/komiku/image-proxy?url=https://img.komiku.org/upload5/solo-leveling-ragnarok/68/2026-01-08/1_a1bc02.webp');\\r const blob = await res.blob();\\r console.log('Image fetched, size:', blob.size);\\r }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL gambar asli dari komiku.",
"required": true
}
]
},
{
"title": "Komiku Populer",
"summary": "Daftar Komik Populer.",
"description": "Mengambil daftar komik paling populer/hot dari Komiku. Mendukung paginasi melalui parameter page.",
"method": "GET",
"path": "/api/anime/komiku/popular",
"responseType": "json",
"example": "async function getPopular() {\n const res = await fetch('/api/anime/komiku/popular?page=1');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
}
]
},
{
"title": "Komiku Read",
"summary": "Baca Chapter Komik.",
"description": "Mengambil daftar gambar dari chapter tertentu.",
"method": "GET",
"path": "/api/anime/komiku/read",
"responseType": "json",
"example": "async function readChapter() {\n const res = await fetch('/api/anime/komiku/read?url=https://komiku.org/solo-leveling-ragnarok-chapter-68/');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Chapter (contoh: https://komiku.org/solo-leveling-ragnarok-chapter-68/).",
"required": true
}
]
},
{
"title": "Komiku Search",
"summary": "Pencarian Komik.",
"description": "Mencari komik di Komiku berdasarkan kata kunci.",
"method": "GET",
"path": "/api/anime/komiku/search",
"responseType": "json",
"example": "async function searchKomik() {\n const res = await fetch('/api/anime/komiku/search?q=Solo Leveling');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (contoh: \"Solo Leveling\").",
"required": true
}
]
},
{
"title": "MAL Genre",
"summary": "MyAnimeList Genre Search.",
"description": "Mencari anime berdasarkan ID Genre di MyAnimeList. ID Genre bisa didapatkan dari dokumentasi Jikan atau MAL (misal: 1 = Action).",
"method": "GET",
"path": "/api/anime/mal/genre",
"responseType": "json",
"example": "async function getByGenre() {\n const res = await fetch('/api/anime/mal/genre?genreId=1');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "genreId",
"in": "query",
"type": "number",
"description": "ID Genre (contoh: 1 untuk Action, 2 untuk Adventure).",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
},
{
"name": "limit",
"in": "query",
"type": "number",
"description": "Jumlah item per halaman (default: 10).",
"required": false
}
]
},
{
"title": "MAL Ongoing",
"summary": "MyAnimeList Ongoing Anime.",
"description": "Mengambil daftar anime yang sedang tayang (Season Now) dari MyAnimeList via Jikan API.",
"method": "GET",
"path": "/api/anime/mal/ongoing",
"responseType": "json",
"example": "async function getOngoing() {\n const res = await fetch('/api/anime/mal/ongoing?page=1');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
},
{
"name": "limit",
"in": "query",
"type": "number",
"description": "Jumlah item per halaman (default: 10).",
"required": false
}
]
},
{
"title": "MAL Popular",
"summary": "MyAnimeList Popular Anime.",
"description": "Mengambil daftar anime populer (Top Anime) dari MyAnimeList via Jikan API.",
"method": "GET",
"path": "/api/anime/mal/popular",
"responseType": "json",
"example": "async function getPopular() {\n const res = await fetch('/api/anime/mal/popular?page=1');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
},
{
"name": "limit",
"in": "query",
"type": "number",
"description": "Jumlah item per halaman (default: 10).",
"required": false
}
]
},
{
"title": "MAL Search",
"summary": "MyAnimeList Search.",
"description": "Mencari anime di MyAnimeList berdasarkan kata kunci.",
"method": "GET",
"path": "/api/anime/mal/search",
"responseType": "json",
"example": "async function searchMAL() {\n const res = await fetch('/api/anime/mal/search?q=Naruto');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian.",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman (default: 1).",
"required": false
},
{
"name": "limit",
"in": "query",
"type": "number",
"description": "Jumlah item per halaman (default: 10).",
"required": false
}
]
},
{
"title": "Oploverz Detail",
"summary": "Oploverz Anime Detail.",
"description": "Mengambil informasi detail anime Oploverz berdasarkan URL atau Path. Termasuk daftar episode dengan link yang disesuaikan ke API.",
"method": "GET",
"path": "/api/anime/oploverz/detail",
"responseType": "json",
"example": "async function getDetail() {\n // Gunakan path relatif (lebih stabil) atau full URL\n const res = await fetch('/api/anime/oploverz/detail?url=/series/spy-x-family-s3');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Oploverz (original link) atau Path (contoh: /series/spy-x-family-s3).",
"required": true
}
]
},
{
"title": "Oploverz Home",
"summary": "Oploverz Home.",
"description": "Mengambil data halaman utama Oploverz, termasuk Carousel, Trending, Rilis Terbaru, dan Tambahan Baru. Link yang dihasilkan telah disesuaikan agar mengarah kembali ke API ini.",
"method": "GET",
"path": "/api/anime/oploverz/home",
"responseType": "json",
"example": "async function getHome() {\n const res = await fetch('/api/anime/oploverz/home');\n const data = await res.json();\n console.log(data);\n }\n \n getHome();",
"params": []
},
{
"title": "Oploverz Schedule",
"summary": "Jadwal Rilis Anime.",
"description": "Mengambil jadwal rilis anime mingguan dari Oploverz.",
"method": "GET",
"path": "/api/anime/oploverz/schedule",
"responseType": "json",
"example": "async function getSchedule() {\n const res = await fetch('/api/anime/oploverz/schedule');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Oploverz Search",
"summary": "Oploverz Search.",
"description": "Mencari anime di Oploverz berdasarkan kata kunci menggunakan API backend resmi mereka.",
"method": "GET",
"path": "/api/anime/oploverz/search",
"responseType": "json",
"example": "async function search() {\n const res = await fetch('/api/anime/oploverz/search?q=Naruto');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (contoh: \"Naruto\").",
"required": true
}
]
},
{
"title": "Oploverz Stream",
"summary": "Oploverz Stream & Download.",
"description": "Mengambil link streaming dan download untuk episode anime Oploverz berdasarkan URL atau Path.",
"method": "GET",
"path": "/api/anime/oploverz/stream",
"responseType": "json",
"example": "async function getStream() {\n // Gunakan path relatif\n const res = await fetch('/api/anime/oploverz/stream?url=/series/spy-x-family-s3/episode/1');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Episode Oploverz atau Path (contoh: /series/spy-x-family-s3/episode/1).",
"required": true
}
]
},
{
"title": "Samehadaku Detail",
"summary": "Detail Anime Samehadaku.",
"description": "Mengambil informasi detail anime Samehadaku berdasarkan URL atau Path. Mengembalikan metadata, sinopsis, daftar genre, rekomendasi, dan list episode.",
"method": "GET",
"path": "/api/anime/samehadaku/detail",
"responseType": "json",
"example": "async function getDetail() {\n const res = await fetch('/api/anime/samehadaku/detail?url=/anime/golden-kamuy-final-season/');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Samehadaku (original link) atau Path relatif.",
"required": true
}
]
},
{
"title": "Samehadaku Embed URL",
"summary": "Get Embed Iframe URL.",
"description": "Mengambil link embed video (iframe) asli dari Samehadaku berdasarkan data post, nume, dan type.",
"method": "GET",
"path": "/api/anime/samehadaku/embed",
"responseType": "json",
"example": "async function getEmbed() {\n const res = await fetch('/api/anime/samehadaku/embed?post=47702&nume=2&type=schtml');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "post",
"in": "query",
"type": "string",
"description": "ID Post episode.",
"required": true
},
{
"name": "nume",
"in": "query",
"type": "string",
"description": "Nomor server (nume).",
"required": true
},
{
"name": "type",
"in": "query",
"type": "string",
"description": "Tipe embed (misal: schtml).",
"required": true
},
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL halaman episode sebagai referer (opsional).",
"required": false
}
]
},
{
"title": "Samehadaku Home",
"summary": "Beranda Samehadaku.",
"description": "Mengambil data dari halaman utama Samehadaku, mencakup anime Top 10 minggu ini, update episode terbaru, dan daftar project movies. Link sudah di-proxy ke API ini.",
"method": "GET",
"path": "/api/anime/samehadaku/home",
"responseType": "json",
"example": "async function getHome() {\n const res = await fetch('/api/anime/samehadaku/home');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Samehadaku Anime List",
"summary": "Daftar Semua Anime.",
"description": "Mengambil halaman daftar anime terbaru di Samehadaku. Mendukung paginasi dan mengembalikan meta pagination untuk request halaman selanjutnya.",
"method": "GET",
"path": "/api/anime/samehadaku/list",
"responseType": "json",
"example": "async function getList() {\n const res = await fetch('/api/anime/samehadaku/list?page=1');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "page",
"in": "query",
"type": "number",
"description": "Nomor halaman yang ingin diambil (default: 1).",
"required": false
}
]
},
{
"title": "Samehadaku Schedule",
"summary": "Jadwal Rilis Mingguan.",
"description": "Mengambil jadwal rilis anime mingguan (Senin - Minggu) dengan menembak API internal Samehadaku secara langsung. Data yang dihasilkan lebih lengkap dan cepat.",
"method": "GET",
"path": "/api/anime/samehadaku/schedule",
"responseType": "json",
"example": "async function getSchedule() {\n const res = await fetch('/api/anime/samehadaku/schedule');\n const data = await res.json();\n console.log(data);\n }",
"params": []
},
{
"title": "Samehadaku Search",
"summary": "Pencarian Anime Samehadaku.",
"description": "Mencari judul anime di Samehadaku. Mengembalikan daftar anime relevan lengkap dengan skor, status, dan genre yang diekstrak dari meta tooltip.",
"method": "GET",
"path": "/api/anime/samehadaku/search",
"responseType": "json",
"example": "async function search() {\n const res = await fetch('/api/anime/samehadaku/search?q=Boruto');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (contoh: \"Boruto\").",
"required": true
}
]
},
{
"title": "Samehadaku Stream",
"summary": "Streaming & Download Samehadaku.",
"description": "Mengambil data episode lengkap dari Samehadaku berdasarkan URL. Otomatis melakukan bypass AJAX untuk mendapatkan URL embed iframe server streaming, dan mengambil daftar link download file asli.",
"method": "GET",
"path": "/api/anime/samehadaku/stream",
"responseType": "json",
"example": "async function getStream() {\n const res = await fetch('/api/anime/samehadaku/stream?url=/golden-kamuy-final-season-episode-1/');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Episode Samehadaku atau Path relatif.",
"required": true
}
]
}
],
"chart": [
{
"title": "Billboard Indonesia Chart",
"summary": "Mendapatkan chart musik Indonesia terbaru dari Billboard",
"description": "Mengambil data 30 lagu terpopuler di Indonesia dari Billboard Indonesia Songs chart (Hot Week)",
"method": "GET",
"path": "/api/chart/billboard",
"responseType": "json",
"example": "// Request\n GET /api/chart/billboard\n // Response\n {\n \"success\": true,\n \"author\": \"PuruBoy\",\n \"result\": [\n {\n \"rank\": 1,\n \"title\": \"Example Song\",\n \"artist\": \"Example Artist\",\n \"lastWeek\": \"1\",\n \"peakPos\": \"1\",\n \"weeksOnChart\": \"10\",\n \"image\": \"https://...\"\n }\n ]\n }",
"params": []
},
{
"title": "TikTok Indonesia Chart",
"summary": "Mendapatkan 30 lagu trending TikTok Indonesia dari Soundcharts",
"description": "Mengambil data chart TikTok Indonesia terbaru dari Soundcharts.com. Menampilkan 30 lagu terpopuler minggu ini dengan posisi, judul, dan artis.",
"method": "GET",
"path": "/api/chart/tiktok",
"responseType": "json",
"example": "// Request\n GET /api/chart/tiktok\n // Response\n {\n \"success\": true,\n \"author\": \"PuruBoy\",\n \"result\": [\n {\n \"position\": 1,\n \"title\": \"DJ LIA ADE NONA MAKIN\",\n \"artist\": \"DJ Alexandre Da Gloria\",\n \"songId\": \"50d47f08-f5fe-4cce-be21-09e1934648d9\"\n }\n ]\n }",
"params": []
}
],
"downloader": [
{
"title": "Facebook Downloader",
"summary": "Download video Facebook (Reel/Watch/Video/Share).",
"description": "Mendownload video Facebook menggunakan Embed Plugin Facebook + fallback fsave.io. Mendukung format Reel, Watch, Video, dan Share. Menghasilkan link HD, SD, thumbnail, subtitles, dan daftar kualitas video.",
"method": "POST",
"path": "/api/downloader/fb",
"responseType": "json",
"example": "async function downloadFB() {\n try {\n const response = await fetch('/api/downloader/fb', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://www.facebook.com/reel/2195585950845288\" \n })\n });\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Error:', error.message);\n }\n }\n \n downloadFB();",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL lengkap video Facebook (reel, watch, videos, share).",
"required": true
}
]
},
{
"title": "Facebook DL",
"summary": "Download video Facebook.",
"description": "Mengunduh video dari Facebook menggunakan layanan fsave.io. Mengembalikan thumbnail dan link download video dalam kualitas SD dan HD.",
"method": "POST",
"path": "/api/downloader/fbdl",
"responseType": "json",
"example": "async function downloadFB() {\n try {\n const response = await fetch('/api/downloader/fbdl', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://www.facebook.com/reel/861262849136029/\" \n })\n });\n \n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Error:', error.message);\n }\n }\n \n downloadFB();",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL lengkap dari video Facebook yang ingin diunduh.",
"required": true
}
]
},
{
"title": "Instagram Downloader",
"summary": "Download Instagram Media (Reels/Photo/Carousel) + Metadata.",
"description": "Mengunduh konten Instagram (Video Reels, Foto, Carousel) lengkap dengan metadata seperti caption, author, thumbnail, dan link download.",
"method": "POST",
"path": "/api/downloader/instagram",
"responseType": "json",
"example": "async function downloadIg() {\n const res = await fetch('/api/downloader/instagram', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://www.instagram.com/reel/DV5hrHUEg4U/\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL media Instagram.",
"required": true
}
]
},
{
"title": "Savetube (YouTube DL)",
"summary": "Mendownload video/audio YouTube dengan cepat menggunakan Savetube API.",
"description": "Mendukung berbagai format kualitas video dan audio dari YouTube. Cukup kirim URL video, dan dapatkan link download langsung beserta metadata seperti judul, thumbnail, durasi, dan format yang tersedia.",
"method": "POST",
"path": "/api/downloader/savetube",
"responseType": "json",
"example": "// Contoh penggunaan\n async function downloadYouTube() {\n try {\n const response = await fetch('/api/downloader/savetube', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\", \"quality\": \"720\" })\n });\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Error:', error.message);\n }\n }\n downloadYouTube();",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL lengkap video YouTube yang ingin diunduh.",
"required": true
},
{
"name": "quality",
"in": "body",
"type": "string",
"description": "Kualitas video/audio yang diinginkan. Jika tidak diisi, akan mengembalikan semua format yang tersedia.",
"required": false,
"choices": [
{
"value": "360",
"label": "360p Video"
},
{
"value": "480",
"label": "480p Video"
},
{
"value": "720",
"label": "720p Video (HD)"
},
{
"value": "1080",
"label": "1080p Video (Full HD)"
},
{
"value": "128",
"label": "128kbps Audio"
}
]
},
{
"name": "type",
"in": "body",
"type": "string",
"description": "Tipe unduhan.",
"required": false,
"choices": [
{
"value": "video",
"label": "Format video (default)"
},
{
"value": "audio",
"label": "Format audio saja"
}
]
}
]
},
{
"title": "Snaptik TikTok DL",
"summary": "Unduh Video TikTok (Snaptik).",
"description": "Mengunduh video TikTok tanpa watermark menggunakan scraping Snaptik.app. Mendukung berbagai link unduhan termasuk HD.",
"method": "POST",
"path": "/api/downloader/snaptik",
"responseType": "json",
"example": "async function download() {\n const res = await fetch('/api/downloader/snaptik', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://www.tiktok.com/@brilionet/video/7483341650115267847\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL video TikTok.",
"required": true
}
]
},
{
"title": "SoundCloud DL V2",
"summary": "SoundCloud Downloader V2 (Direct).",
"description": "Mengunduh lagu dari SoundCloud menggunakan metode direct scraping (Client ID Extraction). Lebih stabil dan cepat.",
"method": "POST",
"path": "/api/downloader/soundcloud-v2",
"responseType": "json",
"example": "async function downloadSC() {\n const res = await fetch('/api/downloader/soundcloud-v2', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://soundcloud.com/tyo-rizki-413604039/dj-ya-odna-x-the-drum-breakbeat-andra-fvnky-rmx\" \n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL lagu SoundCloud yang valid.",
"required": true
}
]
},
{
"title": "Spotify Downloader V2",
"summary": "Spotify to MP3 via savevideoraw.",
"description": "Mengunduh lagu dari Spotify dan mengubahnya menjadi format MP3 menggunakan API savevideoraw.com. Tanpa login, gratis, cepat.",
"method": "POST",
"path": "/api/downloader/spotify-v2",
"responseType": "json",
"example": "async function dlSpotifyV2() {\n const res = await fetch('/api/downloader/spotify-v2', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n \"url\": \"https://open.spotify.com/intl-id/track/0d9Odqdel9VeeDEYuPjm6x\"\n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL Track Spotify (contoh: https://open.spotify.com/intl-id/track/... atau https://open.spotify.com/track/...).",
"required": true
}
]
},
{
"title": "TikTok DL",
"summary": "Mengunduh video TikTok tanpa watermark.",
"description": "Memproses URL video TikTok dan mengembalikan informasi video beserta link unduhan langsung (tanpa watermark) dan link audio dalam format JSON.",
"method": "POST",
"path": "/api/downloader/tiktok",
"responseType": "json",
"example": "// Contoh penggunaan\n async function downloadTikTok() {\n try {\n const response = await fetch('/api/downloader/tiktok', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n // PENTING: Gunakan format JSON valid (key dengan kutip ganda) agar Auto Fill berfungsi\n body: JSON.stringify({ \"url\": \"https://www.tiktok.com/@brilionet/video/7483341650115267847\" })\n });\n \n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Error:', error.message);\n }\n }\n \n downloadTikTok();",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL lengkap dari video TikTok yang ingin diunduh.",
"required": true
}
]
},
{
"title": "TikTok DL V2",
"summary": "TikTok Downloader (TikDownloader.io).",
"description": "Mengunduh video TikTok tanpa watermark atau slide foto menggunakan provider TikDownloader.io. Credit: Yabes.",
"method": "POST",
"path": "/api/downloader/tiktok-v2",
"responseType": "json",
"example": "async function download() {\n const res = await fetch('/api/downloader/tiktok-v2', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://www.tiktok.com/@alenkainventra/video/7351044913112321288\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL video TikTok.",
"required": true
}
]
},
{
"title": "X Downloader",
"summary": "X/Twitter Video Downloader.",
"description": "Mengunduh video dari platform X (Twitter) menggunakan layanan xsaver.io. Mengembalikan judul video dan daftar link download kualitas yang tersedia.",
"method": "POST",
"path": "/api/downloader/x",
"responseType": "json",
"example": "async function downloadX() {\n const res = await fetch('/api/downloader/x', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://x.com/elsyandria/status/1218385778880831488\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL video X/Twitter yang ingin diunduh.",
"required": true
}
]
},
{
"title": "YouTube DL",
"summary": "YouTube Downloader (YTDown).",
"description": "Mengunduh video dan audio dari YouTube menggunakan layanan YTDown. Mendukung berbagai resolusi (hingga 1080p FHD).",
"method": "POST",
"path": "/api/downloader/youtube",
"responseType": "json",
"example": "async function dl() {\n const res = await fetch('/api/downloader/youtube', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://www.youtube.com/watch?v=Fmf-G9fpwto\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL video YouTube yang valid.",
"required": true
}
]
},
{
"title": "YouTube Downloader",
"summary": "Download video YouTube menggunakan YoutubeSave.io.",
"description": "Mendownload video dan audio dari YouTube menggunakan layanan YoutubeSave.io. Mendukung berbagai resolusi (1080p, 720p, 480p, 360p, MP3 Audio). Mengembalikan metadata lengkap termasuk judul, thumbnail, durasi, dan link download untuk semua format yang tersedia.",
"method": "POST",
"path": "/api/downloader/youtube",
"responseType": "json",
"example": "async function downloadVideo() {\n try {\n const res = await fetch('/api/downloader/youtube', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' })\n });\n const data = await res.json();\n console.log(JSON.stringify(data, null, 2));\n } catch (err) {\n console.error('Error:', err.message);\n }\n }\n downloadVideo();",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL lengkap video YouTube yang ingin diunduh (wajib).",
"required": true
}
]
},
{
"title": "YTMP3 Audio",
"summary": "YouTube to MP3.",
"description": "Mengonversi dan mengunduh audio YouTube dalam format MP3 menggunakan layanan YTMP3.mobi.",
"method": "POST",
"path": "/api/downloader/ytmp3",
"responseType": "json",
"example": "async function downloadMp3() {\n const res = await fetch('/api/downloader/ytmp3', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL Video YouTube yang ingin diunduh.",
"required": true
}
]
}
],
"main": [
{
"title": "Server Ping",
"summary": "Memeriksa status server.",
"description": "Endpoint ini mengembalikan status sukses beserta timestamp untuk memverifikasi bahwa server aktif dan merespons.",
"method": "GET",
"path": "/api/main/ping",
"responseType": "json",
"params": [
{
"name": "echo",
"in": "query",
"type": "string",
"description": "Teks opsional yang akan dikembalikan dalam respons.",
"required": false
}
]
}
],
"meme": [
{
"title": "Lahelu Feed",
"summary": "Get Fresh Memes.",
"description": "Mengambil feed meme terbaru (Fresh) dari Lahelu. Mendukung paginasi menggunakan cursor.",
"method": "GET",
"path": "/api/meme/lahelu",
"responseType": "json",
"example": "async function getMemes() {\n const res = await fetch('/api/meme/lahelu');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "page",
"in": "query",
"type": "number",
"description": "Cursor halaman (integer). Default: 0. Gunakan 'nextCursor' dari respons sebelumnya untuk halaman berikutnya.",
"required": false
}
]
},
{
"title": "Ubur Ubur",
"summary": "Generator Video Meme.",
"description": "Membuat video meme promosi/lucu dengan latar belakang kustom, karakter manusia, dan teks. Endpoint ini menggunakan Server-Sent Events (SSE) karena proses rendering video membutuhkan waktu. Hasil akhir diunggah ke penyimpanan sementara.",
"method": "POST",
"path": "/api/meme/uburubur",
"responseType": "json",
"example": "async function generateMeme() {\n const res = await fetch('/api/meme/uburubur', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n \"bgUrl\": \"https://www.puruboy.kozow.com/favicon.jpg\",\n \"humanUrl\": \"https://png.pngtree.com/png-clipart/20240412/original/pngtree-prabowo-subianto-png-image_14789437.png\",\n \"brand\": \"INFO PENTING\",\n \"title\": \"UBUR UBUR\",\n \"slogan\": \"Ikan hiu makan tomat.\",\n \"promo\": \"Makan nasi | Rp5.000\\nMakan angin | Gratis\",\n \"wm\": \"@PuruBoy-API\"\n })\n });\n \n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n console.log(decoder.decode(value));\n }\n }",
"params": [
{
"name": "bgUrl",
"in": "body",
"type": "string",
"description": "URL gambar background.",
"required": true
},
{
"name": "humanUrl",
"in": "body",
"type": "string",
"description": "URL gambar karakter manusia (transparan disarankan).",
"required": true
},
{
"name": "brand",
"in": "body",
"type": "string",
"description": "Teks brand/merk (atas).",
"required": true
},
{
"name": "title",
"in": "body",
"type": "string",
"description": "Judul utama.",
"required": true
},
{
"name": "slogan",
"in": "body",
"type": "string",
"description": "Slogan di bawah judul.",
"required": true
},
{
"name": "promo",
"in": "body",
"type": "string",
"description": "Detail teks/daftar harga (mendukung newline).",
"required": true
},
{
"name": "wm",
"in": "body",
"type": "string",
"description": "Teks watermark (kanan bawah).",
"required": true
}
]
}
],
"play": [
{
"title": "SoundCloud Play",
"summary": "Play SoundCloud Audio.",
"description": "Mencari lagu di SoundCloud, memfilter durasi (1-10 menit), dan mengambil URL download langsung. Menggabungkan fungsi pencarian dan pengunduhan dalam satu request untuk mendapatkan audio yang bisa diputar/diunduh.",
"method": "GET",
"path": "/api/play/soundcloud",
"responseType": "json",
"example": "async function play() {\n const res = await fetch('/api/play/soundcloud?q=dj+ya+odna');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Judul lagu atau kata kunci pencarian.",
"required": true
}
]
}
],
"search": [
{
"title": "Lahelu Search",
"summary": "Cari Meme Lahelu.",
"description": "Mencari meme di Lahelu berdasarkan kata kunci.",
"method": "GET",
"path": "/api/search/lahelu",
"responseType": "json",
"example": "async function searchMemes() {\n const res = await fetch('/api/search/lahelu?q=kucing');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian.",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Cursor halaman (integer). Default: 0.",
"required": false
}
]
},
{
"title": "Lyrics Search",
"summary": "Search Song Lyrics.",
"description": "Mencari lirik lagu berdasarkan judul atau artis menggunakan LRCLIB. Mengembalikan lirik biasa (plain) dan tersinkronisasi (synced/LRC) jika tersedia.",
"method": "GET",
"path": "/api/search/lyrics",
"responseType": "json",
"example": "async function getLyrics() {\n const res = await fetch('/api/search/lyrics?q=Alan Walker Faded');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Judul lagu atau nama artis.",
"required": true
}
]
},
{
"title": "Pinterest Search",
"summary": "Search Pinterest Pins.",
"description": "Mencari gambar atau pin di Pinterest berdasarkan kata kunci. Mengambil sesi dan token secara otomatis untuk mengakses API internal Pinterest.",
"method": "GET",
"path": "/api/search/pinterest",
"responseType": "json",
"example": "async function pinterestSearch() {\n try {\n const res = await fetch('/api/search/pinterest?q=Anime Wallpaper');\n const data = await res.json();\n console.log(data);\n } catch (e) {\n console.error(e);\n }\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (contoh: \"Anime Wallpaper\").",
"required": true
}
]
},
{
"title": "SoundCloud Search",
"summary": "Search SoundCloud Tracks.",
"description": "Melakukan pencarian lagu di SoundCloud berdasarkan kata kunci. Endpoint ini mengembalikan daftar lagu yang cocok beserta metadata seperti durasi dan jumlah pemutaran.",
"method": "GET",
"path": "/api/search/soundcloud",
"responseType": "json",
"example": "// Contoh penggunaan\n async function searchSoundCloud() {\n try {\n const response = await fetch('/api/search/soundcloud?q=lofi&limit=5');\n const data = await response.json();\n console.log(data);\n } catch (error) {\n console.error('Error:', error);\n }\n }\n \n searchSoundCloud();",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (judul lagu/artis).",
"required": true
},
{
"name": "limit",
"in": "query",
"type": "string",
"description": "Batas jumlah hasil yang ditampilkan (default: 10).",
"required": false
}
]
},
{
"title": "SoundCloud Playlist",
"summary": "Get SoundCloud Playlist Tracks.",
"description": "Mengambil daftar lagu lengkap dari sebuah playlist SoundCloud menggunakan scraping dinamis Client ID.",
"method": "GET",
"path": "/api/search/soundcloud-playlist",
"responseType": "json",
"example": "async function getPlaylist() {\n const res = await fetch('/api/search/soundcloud-playlist?url=https://soundcloud.com/mhd-rayyan/sets/lagu-pop-indonesia-hits-2026');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "query",
"type": "string",
"description": "URL Playlist SoundCloud.",
"required": true
}
]
},
{
"title": "Spotify Search via Yahoo",
"summary": "Mencari track Spotify menggunakan mesin pencari Yahoo.",
"description": "Mencari lagu/track Spotify melalui Yahoo Search dengan format `site:spotify.com/intl-id/track`. Mengembalikan judul, track ID, dan URL Spotify. Cocok untuk mencari track yang mungkin tidak muncul di pencarian internal Spotify.",
"method": "GET",
"path": "/api/search/spotify",
"responseType": "json",
"example": "async function searchSpotify() {\n const res = await fetch('/api/search/spotify?q=DJ+ya+odna');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian (contoh: \"DJ ya odna\").",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Halaman hasil pencarian (default: 1).",
"required": false
}
]
},
{
"title": "Search Autocomplete",
"summary": "Get search suggestions.",
"description": "Mendapatkan daftar saran kata kunci pencarian (autocomplete) berdasarkan input pengguna. Fitur ini menggunakan engine Google Suggest.",
"method": "GET",
"path": "/api/search/suggest",
"responseType": "json",
"example": "async function getSuggestions() {\n const res = await fetch('/api/search/suggest?q=apa+itu');\n const data = await res.json();\n console.log(data.result);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci atau awalan kalimat.",
"required": true
}
]
},
{
"title": "Yahoo Search",
"summary": "Search information on Yahoo.",
"description": "Mencari informasi web secara langsung dari mesin pencari Yahoo. Mengembalikan judul, link, dan cuplikan konten.",
"method": "GET",
"path": "/api/search/yahoo",
"responseType": "json",
"example": "async function searchYahoo() {\n const res = await fetch('/api/search/yahoo?q=berita+terkini');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian.",
"required": true
}
]
},
{
"title": "Yahoo SoundCloud Search",
"summary": "Cari lagu/playlist SoundCloud via Yahoo.",
"description": "Mencari konten SoundCloud (track atau playlist) menggunakan mesin pencari Yahoo. Menghasilkan output yang bersih dengan ekstraksi URL asli.",
"method": "GET",
"path": "/api/search/yahoo-soundcloud",
"responseType": "json",
"example": "async function search() {\n const res = await fetch('/api/search/yahoo-soundcloud?q=dj+ya+odna');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian.",
"required": true
},
{
"name": "page",
"in": "query",
"type": "number",
"description": "Offset hasil pencarian (default: 1).",
"required": false
}
]
},
{
"title": "YouTube Search",
"summary": "Search YouTube Videos.",
"description": "Mencari video di YouTube berdasarkan kata kunci menggunakan provider pihak ketiga. Mengembalikan judul, link video, channel, durasi, dan thumbnail.",
"method": "GET",
"path": "/api/search/youtube",
"responseType": "json",
"example": "async function searchYouTube() {\n const res = await fetch('/api/search/youtube?q=DJ ya odna');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Kata kunci pencarian.",
"required": true
}
]
}
],
"tools": [
{
"title": "AI Music & Melody Generator",
"summary": "สร้างเนื้อเพลง ไอเดียท่วงทำนอง และแต่งบทเพลงด้วย AI (AI Music & Lyrics Generator)",
"description": "สร้างเนื้อเพลงภาษาไทย/อังกฤษ ท่อนฮุค ท่อนร้อง และไอเดียท่วงทำนองเพลงอัตโนมัติตามสไตล์เพลงหรืออารมณ์ที่กำหนด",
"method": "POST",
"path": "/api/tools/aimelody",
"responseType": "json",
"example": "async function generateMusic() {\n const res = await fetch('/api/tools/aimelody', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"เพลงรักสดใส สไตล์ K-Pop Melody\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "หัวข้อเพลงหรืออารมณ์ของเพลงที่ต้องการแต่ง (e.g. \"เพลงรักอกหัก สไตล์ Acoustic Pop\")",
"required": true
}
]
},
{
"title": "Audio to Text (MMS) - SSE",
"summary": "Transkripsi Audio ke Teks (1000+ Bahasa) via Server-Sent Events.",
"description": "Mengonversi file suara/audio menjadi teks menggunakan Meta MMS (Massively Multilingual Speech) model. Mendukung 1000+ bahasa. Response dalam format SSE (Server-Sent Events). Saat menunggu hasil, server mengirim ping event berisi fakta unik.",
"method": "POST",
"path": "/api/tools/audio2text",
"responseType": "json",
"example": "// Via fetch + ReadableStream (rekomendasi)\n const res = await fetch('https://allapi.getth.xyz/api/tools/audio2text', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n url: 'https://allapi.getth.xyz/example.mp3',\n lang: 'ind'\n })\n });\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const chunk = decoder.decode(value);\n // Parse SSE events: start, submit, submitted, processing, ping, result, done\n console.log(chunk);\n }\n\n// EventSource (browser) — gunakan POST proxy atau library seperti @microsoft/fetch-event-source\n // Karena EventSource tidak support POST, gunakan fetch + manual parse:\n const res = await fetch('/api/tools/audio2text', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ url: 'https://allapi.getth.xyz/example.mp3', lang: 'ind' })\n });\n // Baca stream, setiap event \"ping\" berisi fakta unik sambil menunggu \"result\"",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file audio (WAV/MP3/FLAC/OGG, dll).",
"required": true
},
{
"name": "lang",
"in": "body",
"type": "string",
"description": "Kode/nama bahasa target. Contoh: 'ind', 'Indonesia', 'Indonesian (ind)'. Default: 'Indonesian (ind)'.",
"required": false
}
]
},
{
"title": "Voice & Audio Editor",
"summary": "Ubah efek suara video/audio.",
"description": "Menerapkan efek suara ke file video atau audio (MP3). Pilihan efek: bass, deep, chipmunk, echo, radio, nightcore.",
"method": "POST",
"path": "/api/tools/audioedit",
"responseType": "json",
"example": "async function editAudio() {\n const res = await fetch('/api/tools/audioedit', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://allapi.getth.xyz/example.mp4\",\n \"effect\": \"nightcore\"\n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file media (MP4/MP3).",
"required": true
},
{
"name": "effect",
"in": "body",
"type": "string",
"description": "Jenis efek (bass, deep, chipmunk, echo, radio, nightcore). Default: bass.",
"required": false
}
]
},
{
"title": "AI Auto Clipper",
"summary": "Ubah Video Panjang Jadi Klip Viral.",
"description": "Menggunakan kecerdasan buatan untuk menganalisis video panjang dan memotong bagian paling menarik secara otomatis untuk konten TikTok/Reels/Shorts. Mendukung video dengan durasi bebas selama ukuran file tidak melebihi 200MB.",
"method": "POST",
"path": "/api/tools/autoclip",
"responseType": "json",
"example": "async function generateClip() {\n const res = await fetch('/api/tools/autoclip', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4\" \n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file video MP4 (contoh: https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/videoplayback.mp4).",
"required": true
}
]
},
{
"title": "Brat Generator",
"summary": "Brat Generator (Text to Image).",
"description": "Membuat meme teks gaya \"Brat\" berdasarkan input teks menggunakan API eksternal yang cepat. Mengembalikan URL gambar hasil (PNG) yang sudah diproses menjadi URL publik.",
"method": "POST",
"path": "/api/tools/brat",
"responseType": "json",
"example": "async function createBrat() {\n const res = await fetch('/api/tools/brat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"text\": \"hai kamu siapa sih😈\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "text",
"in": "body",
"type": "string",
"description": "Teks yang akan ditampilkan pada gambar.",
"required": true
}
]
},
{
"title": "AI Video Dubbing",
"summary": "Terjemahkan Suara Video (Dubbing).",
"description": "Mengubah suara asli dalam video ke bahasa lain menggunakan AI dengan tetap mempertahankan nuansa suara aslinya. Mendukung bahasa Indonesia (id-ID), Inggris (en-US), dan Jepang (ja-JP).",
"method": "POST",
"path": "/api/tools/dubbing",
"responseType": "json",
"example": "async function startDubbing() {\n const res = await fetch('/api/tools/dubbing', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://github.com/purujawa06-bot/My-db/raw/refs/heads/main/video/english-conversation-have-a-coffee-with-tim-shorts-ytshorts.savetube.vip.mp4\",\n \"voice\": \"id-ID\",\n \"prompt\": \"Santai Dan Gaul Bro\"\n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file video (MP4) yang ingin di-dubbing.",
"required": true
},
{
"name": "voice",
"in": "body",
"type": "string",
"description": "Kode bahasa target: 'id-ID', 'en-US', 'ja-JP'. Default: 'id-ID'.",
"required": false
},
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "Instruksi tambahan untuk AI (misal: \"Gaya bicara santai\").",
"required": false
}
]
},
{
"title": "Ghibli Style",
"summary": "Transform Image to Ghibli Style.",
"description": "Mengubah foto menjadi gaya seni anime Studio Ghibli. Endpoint ini menggunakan Server-Sent Events (SSE).",
"method": "POST",
"path": "/api/tools/ghibli",
"responseType": "json",
"example": "// Contoh penggunaan SSE\n async function ghibliTransform() {\n const response = await fetch('/api/tools/ghibli', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://allapi.getth.xyz/example.jpg\",\n \"prompt\": \"Jadikan ghibli\"\n })\n });\n \n const reader = response.body.getReader();\n // Read stream...\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL gambar sumber.",
"required": true
},
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "Prompt kustom (opsional).",
"required": false
}
]
},
{
"title": "HD Video 60FPS",
"summary": "AI Video Enhancer.",
"description": "Mempertajam dan membuat video menjadi sangat mulus (60 FPS) menggunakan AI. Endpoint ini akan mengembalikan job ID dan polling URL untuk memeriksa status pemrosesan.",
"method": "POST",
"path": "/api/tools/hdvideo",
"responseType": "json",
"example": "async function makeHD() {\n const res = await fetch('/api/tools/hdvideo', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://allapi.getth.xyz/example.mp4\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file video (MP4) yang ingin di-HD-kan.",
"required": true
}
]
},
{
"title": "ImgBB Uploader",
"summary": "Upload Gambar ke ImgBB.",
"description": "Mengupload gambar ke ImgBB dan mendapatkan direct link secara gratis. Mendukung format JPG, PNG, BMP, GIF, TIF, WEBP, HEIC, PDF.",
"method": "POST",
"path": "/api/tools/imgbb",
"responseType": "json",
"example": "// Contoh penggunaan dengan FormData (Browser)\n const formData = new FormData();\n formData.append('image', fileInput.files[0]);\n \n const res = await fetch('/api/tools/imgbb', {\n method: 'POST',\n body: formData\n });\n \n const data = await res.json();\n console.log(data);",
"params": [
{
"name": "image",
"in": "formData",
"type": "file",
"description": "File gambar yang akan diupload.",
"required": true
}
]
},
{
"title": "Media Job Status",
"summary": "Cek Status Pemrosesan Media.",
"description": "Memeriksa status pekerjaan untuk HD Video, atau Audio Edit. Jika selesai, akan mengembalikan URL file hasil.",
"method": "GET",
"path": "/api/tools/media-status",
"responseType": "json",
"example": "async function checkStatus() {\n const res = await fetch('/api/tools/media-status?jobId=12345abcde');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "jobId",
"in": "query",
"type": "string",
"description": "ID Job yang didapat dari request sebelumnya.",
"required": true
}
]
},
{
"title": "MLBB Region Checker",
"summary": "Cek Region & Nickname MLBB.",
"description": "Mengecek region ID, nickname, dan metadata akun Mobile Legends: Bang Bang berdasarkan User ID dan Zone ID menggunakan layanan PizzoShop.",
"method": "POST",
"path": "/api/tools/mlbb",
"responseType": "json",
"example": "async function checkML() {\n const res = await fetch('/api/tools/mlbb', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"userId\": \"2002113712\", \n \"zoneId\": \"19417\" \n })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "userId",
"in": "body",
"type": "string",
"description": "User ID Mobile Legends.",
"required": true
},
{
"name": "zoneId",
"in": "body",
"type": "string",
"description": "Zone ID Mobile Legends.",
"required": true
}
]
},
{
"title": "MP4 to MP3 Converter",
"summary": "Konversi Video MP4 ke Audio MP3.",
"description": "Mengekstrak audio dari file video MP4 dan mengubahnya menjadi format MP3. Endpoint ini menggunakan Server-Sent Events (SSE) untuk memberikan update status proses konversi secara real-time.",
"method": "POST",
"path": "/api/tools/mp4tomp3",
"responseType": "json",
"example": "async function convert() {\n const res = await fetch('/api/tools/mp4tomp3', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://allapi.getth.xyz/example.mp4\" })\n });\n \n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n console.log(decoder.decode(value));\n }\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file MP4 yang ingin dikonversi.",
"required": true
}
]
},
{
"title": "Photo To Anime & AI Image Generator",
"summary": "แปลงรูปภาพเป็นสไตล์อนิเมะ หรือสร้างภาพจากข้อความ (Photo to Anime / FLUX AI)",
"description": "แปลงภาพถ่ายคนจริงเป็นลายเส้นการ์ตูนอนิเมะ หรือสร้างภาพ AI Photorealistic ด้วยคำสั่งข้อความ (Prompt)",
"method": "POST",
"path": "/api/tools/phototoanime",
"responseType": "json",
"example": "async function convertAnime() {\n const res = await fetch('/api/tools/phototoanime', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"prompt\": \"anime girl portrait, ghibli style\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "prompt",
"in": "body",
"type": "string",
"description": "คำอธิบายรูปภาพภาษาอังกฤษ (e.g. \"studio ghibli style, anime girl\")",
"required": false
},
{
"name": "image",
"in": "body",
"type": "string",
"description": "URL รูปภาพต้นฉบับสำหรับแปลงเป็นอนิเมะ (Image to Image)",
"required": false
}
]
},
{
"title": "Preview HTML Uploader",
"summary": "Upload HTML String เพื่อสร้างลิงก์แสดงผลหน้าเว็บ Preview",
"description": "แปลงข้อความ HTML ให้กลายเป็นหน้าเว็บและรับลิงก์ URL สำหรับแสดงผลทันที",
"method": "POST",
"path": "/api/tools/preview-upload",
"responseType": "json",
"example": "const res = await fetch('/api/tools/preview-upload', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n html: 'Hello World
Welcome to PuruBoy API Preview
',\n filename: 'preview-test'\n })\n });\n \n const data = await res.json();\n console.log(data);",
"params": [
{
"name": "html",
"in": "body",
"type": "string",
"description": "ข้อความโค้ด HTML ที่ต้องการอัปโหลด",
"required": true
},
{
"name": "filename",
"in": "body",
"type": "string",
"description": "ชื่อไฟล์ (ตัวเลือก, Default: \"preview\")",
"required": false
}
]
},
{
"title": "Al-Quran Digital",
"summary": "Al-Quran Digital Kemenag.",
"description": "Mengambil data ayat-ayat suci Al-Quran beserta terjemahan dan teks latin langsung dari sumber web-api Kemenag. Respons telah dirapikan dan dibersihkan dari properti bernilai null untuk efisiensi data.",
"method": "GET",
"path": "/api/tools/quran",
"responseType": "json",
"example": "async function getQuran() {\n const res = await fetch('/api/tools/quran?surah=10&ayah=1,2');\n const data = await res.json();\n console.log(data.result.data);\n }",
"params": [
{
"name": "surah",
"in": "query",
"type": "string",
"description": "Nomor surah (1-114).",
"required": true
},
{
"name": "ayah",
"in": "query",
"type": "string",
"description": "Nomor ayat spesifik atau daftar ayat dipisah koma (contoh: \"1,2,3\"). Default: \"all\".",
"required": false
}
]
},
{
"title": "Remove BG",
"summary": "Hapus Background Gambar.",
"description": "Menghapus latar belakang gambar menggunakan API Pixelcut dan mengupload hasilnya ke penyimpanan sementara. Mengembalikan URL gambar hasil (PNG).",
"method": "POST",
"path": "/api/tools/removebg",
"responseType": "json",
"example": "// Contoh penggunaan\n async function removeBg() {\n try {\n const response = await fetch('/api/tools/removebg', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://allapi.getth.xyz/example.jpg\" \n })\n });\n \n const data = await response.json();\n console.log(data); \n // Output: { status: 'success', url: 'https://domain.com/api/media/...' }\n } catch (error) {\n console.error('Error:', error.message);\n }\n }\n \n removeBg();",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik dari gambar yang ingin diproses.",
"required": true
}
]
},
{
"title": "Remove BG V2",
"summary": "Hapus Background V2 (ILoveIMG).",
"description": "Menghapus latar belakang gambar menggunakan layanan ILoveIMG. Alternatif handal untuk menghapus background dengan presisi tinggi.",
"method": "POST",
"path": "/api/tools/removebg-v2",
"responseType": "json",
"example": "// Contoh penggunaan\n async function removeBg() {\n try {\n const response = await fetch('/api/tools/removebg-v2', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://allapi.getth.xyz/example.jpg\" \n })\n });\n \n const data = await response.json();\n console.log(data); \n } catch (error) {\n console.error('Error:', error.message);\n }\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik dari gambar yang ingin diproses.",
"required": true
}
]
},
{
"title": "Colorize Image",
"summary": "Colorize Image (AI Engine V2).",
"description": "Mewarnai gambar hitam putih menggunakan AI Engine terbaru yang lebih akurat. Endpoint ini menggunakan Server-Sent Events (SSE). Hasil akhir disimpan sementara dalam database selama 30 menit.",
"method": "POST",
"path": "/api/tools/reviva",
"responseType": "json",
"example": "async function colorizeImage() {\n const response = await fetch('/api/tools/reviva', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \n \"url\": \"https://allapi.getth.xyz/example.jpg\" \n })\n });\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n \n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const text = decoder.decode(value);\n if(text.includes('[true]')) {\n const retrieveUrl = text.replace('[true]', '').trim();\n console.log(\"Data tersedia di:\", retrieveUrl);\n }\n }\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL gambar (hitam putih) yang ingin diwarnai.",
"required": true
}
]
},
{
"title": "Jadwal Sholat / ตารางเวลาละหมาด",
"summary": "ตารางเวลาละหมาดรายเดือนตามเมือง (Prayer Times Schedule)",
"description": "ดึงข้อมูลตารางเวลาละหมาดตามรายชื่อเมือง",
"method": "GET",
"path": "/api/tools/sholat",
"responseType": "json",
"example": "async function getSholat() {\n const res = await fetch('/api/tools/sholat?q=Jakarta');\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "ชื่อเมือง (เช่น \"Jakarta\", \"Bandung\", Default: \"Jakarta\")",
"required": false
}
]
},
{
"title": "AI Video Stabilizer",
"summary": "Menstabilkan Video Shaky.",
"description": "Memperbaiki guncangan (shake) pada video menggunakan teknologi AI Stabilizer. Endpoint ini akan mengembalikan job ID dan polling URL untuk memeriksa status pemrosesan.",
"method": "POST",
"path": "/api/tools/stabilizer",
"responseType": "json",
"example": "async function stabilize() {\n const res = await fetch('/api/tools/stabilizer', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://allapi.getth.xyz/example.mp4\" })\n });\n const data = await res.json();\n console.log(data);\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL publik file video (MP4) yang ingin distabilkan.",
"required": true
}
]
},
{
"title": "AI Unblur",
"summary": "AI Image Unblur (UnblurImage.ai).",
"description": "Memperbaiki gambar yang buram (blur) agar menjadi lebih tajam dan jernih menggunakan teknologi AI. Endpoint ini menggunakan Server-Sent Events (SSE).",
"method": "POST",
"path": "/api/tools/unblur",
"responseType": "json",
"example": "// Contoh penggunaan SSE di client\n async function unblurImage() {\n const response = await fetch('/api/tools/unblur', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://allapi.getth.xyz/example.jpg\" })\n });\n \n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n const text = decoder.decode(value);\n if(text.includes('[true]')) {\n const url = text.replace('[true]', '').trim();\n console.log(\"Success:\", url);\n }\n }\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL gambar yang ingin diperbaiki.",
"required": true
}
]
},
{
"title": "AI Upscale",
"summary": "AI Image Upscale.",
"description": "Meningkatkan resolusi dan kualitas gambar menggunakan AI (via Cloudinary). Endpoint ini menggunakan Server-Sent Events (SSE).",
"method": "POST",
"path": "/api/tools/upscale",
"responseType": "json",
"example": "// Contoh penggunaan SSE\n async function upscaleImage() {\n const response = await fetch('/api/tools/upscale', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ \"url\": \"https://allapi.getth.xyz/example.jpg\" })\n });\n \n const reader = response.body.getReader();\n // Read stream...\n }",
"params": [
{
"name": "url",
"in": "body",
"type": "string",
"description": "URL gambar yang ingin di-upscale.",
"required": true
}
]
}
]
}
---
// FILE: public\admin.html
Admin Console
🔐
Admin Access
Masukkan kredensial untuk melanjutkan
New Blog Post
Create Custom Page
---
// FILE: lib\ytsearch.js
const axios = require('axios');
const BASE_URL = 'https://inv.nadeko.net';
const 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';
/**
* YouTube Search via Invidious (inv.nadeko.net) — without cheerio
*
* @param {string} query - Kata kunci pencarian
* @param {object} [options]
* @param {number} [options.page] - Halaman (default: 1)
* @param {string} [options.sort] - Sort: 'relevance' | 'views' | 'rating' | 'date'
* @param {string} [options.duration] - Durasi: 'short' | 'medium' | 'long'
* @param {string} [options.type] - Tipe: 'video' | 'channel' | 'playlist' | 'movie' | 'show'
* @param {string} [options.date] - Upload: 'hour' | 'today' | 'week' | 'month' | 'year'
* @returns {Promise}
*/
async function search(query, options = {}) {
if (!query || typeof query !== 'string') {
throw new Error('Query is required.');
}
const page = options.page || 1;
const params = new URLSearchParams({ q: query, page });
if (options.sort) params.set('sort', options.sort);
if (options.duration) params.set('duration', options.duration);
if (options.type) params.set('type', options.type);
if (options.date) params.set('date', options.date);
if (options.features) {
const features = Array.isArray(options.features) ? options.features : [options.features];
features.forEach((f) => params.append('features[]', f));
}
const url = `${BASE_URL}/search?${params.toString()}`;
const { data } = await axios.get(url, {
headers: {
'User-Agent': USER_AGENT,
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
},
timeout: 15000,
});
const results = [];
// Split by card: each card starts with TITLE
const titleMatch = cardHtml.match(/
]*>([\s\S]*?)<\/p><\/a>/);
if (!titleMatch) continue;
const title = titleMatch[1]
.replace(/<[^>]+>/g, '')
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(///g, '/')
.trim();
if (!title) continue;
// -- Video ID --
const vidMatch = cardHtml.match(/\/watch\?v=([a-zA-Z0-9_-]{11})/);
const videoId = vidMatch ? vidMatch[1] : '';
// -- Extract duration --
const durMatch = cardHtml.match(/
([\s\S]*?)<\/p>/);
const duration = durMatch ? durMatch[1].trim() : '';
// -- Extract thumbnail --
const thumbMatch = cardHtml.match(/
]*src="([^"]+)"[^>]*>/);
let thumbnail = '';
if (thumbMatch) {
thumbnail = thumbMatch[1].startsWith('http') ? thumbMatch[1] : BASE_URL + thumbMatch[1];
}
// -- Extract channel name --
const chMatch = cardHtml.match(/
]*>([\s\S]*?)<\/p>/);
let channel = '';
if (chMatch) {
channel = chMatch[1]
.replace(/<[^>]+>/g, '')
.replace(/ /g, ' ')
.replace(/&/g, '&')
.trim();
}
// -- Channel ID --
const chIdMatch = cardHtml.match(/\/channel\/(UC[a-zA-Z0-9_-]+)/);
const channelId = chIdMatch ? chIdMatch[1] : '';
// -- Extract views & published from .video-data --
const videoDataMatches = [...cardHtml.matchAll(/
]*>([\s\S]*?)<\/p>/g)];
let published = '';
let views = '';
for (const vdMatch of videoDataMatches) {
const text = vdMatch[1]
.replace(/<[^>]+>/g, '')
.replace(/ /g, ' ')
.trim();
if (/views?/i.test(text)) {
views = text;
} else if (/(Shared|Streamed|Premiered|ago)/i.test(text)) {
published = text;
}
}
results.push({
title,
url: `https://www.youtube.com/watch?v=${videoId}`,
videoId,
channel,
channelId,
channelUrl: channelId ? `https://www.youtube.com/channel/${channelId}` : '',
duration,
thumbnail,
views,
published,
});
}
return results;
}
module.exports = { search };
---
// FILE: lib\yahooSpotify.js
const cheerio = require('cheerio');
/**
* Spotify Search via Yahoo (Single Engine dengan Retry + Cookie)
* Mencari track Spotify melalui Yahoo Search.
* Jika gagal, retry otomatis dengan cookies dari permintaan sebelumnya.
* Jika gagal 2x, throw error.
*
* @class YahooSpotifyScraper
*/
class YahooSpotifyScraper {
constructor() {
this.timeout = 15000;
/** @type {string|null} Cookie jar: menyimpan cookies dari response sebelumnya */
this._cookies = null;
}
/**
* Ekstrak track ID dari URL Spotify
* @param {string} spotifyUrl
* @returns {string|null}
*/
_extractTrackId(spotifyUrl) {
if (!spotifyUrl) return null;
const match = spotifyUrl.match(/\/track\/([a-zA-Z0-9]+)/);
return match ? match[1] : null;
}
/**
* Bersihkan judul dari breadcrumb dan artefak URL
* @param {string} rawTitle
* @returns {string}
*/
_cleanTitle(rawTitle) {
if (!rawTitle) return '';
let title = rawTitle;
// Hapus "Spotify" prefix
title = title.replace(/^Spotify\s*/i, '');
// Hapus URL + breadcrumb
title = title
.replace(/https?:\/\/open\.spotify\.com\s*[›»]?\s*\/?\s*intl-id\s*[›»]?\s*\/?\s*track\s*\/?/gi, '')
.replace(/open\.spotify\.com\s*[›»]\s*intl-id\s*[›»]\s*track\s*/gi, '')
.replace(/open\.spotify\.com\/intl-id\/track\s*/gi, '')
.replace(/https?:\/\/open\.spotify\.com\/track\s*/gi, '');
// Hapus " - lagu dan lirik oleh ..." atau " - lagu oleh ..."
title = title.replace(/\s*[-–]\s*lagu\s*(dan\s*lirik)?\s*oleh\s+.*$/i, '');
// Hapus " | Spotify" atau " | ..." di akhir
title = title.replace(/\s*\|.*$/, '');
// Bersihkan spasi berlebih
title = title.replace(/\s+/g, ' ').trim();
// Jika hasilnya adalah track ID saja (hanya alfanumerik)
if (/^[a-zA-Z0-9]+$/.test(title)) {
return `Spotify Track ${title}`;
}
// Jika masih mengandung http/URL, ambil kata-kata non-URL saja
if (title.includes('http') || title.includes('spotify.com')) {
const parts = title.split(/\s+/);
const cleanParts = parts.filter(p => !p.includes('http') && !p.includes('spotify.com'));
if (cleanParts.length > 0) {
title = cleanParts.join(' ');
}
}
return title.trim() || `Spotify Track`;
}
/**
* Ekstrak URL asli dari redirect Yahoo (parameter RU)
* @param {string} yahooUrl
* @returns {string|null}
*/
_extractRealUrl(yahooUrl) {
if (!yahooUrl) return null;
const match = yahooUrl.match(/RU=([^/&]+)/);
if (match && match[1]) {
try {
const decoded = decodeURIComponent(match[1]);
return decoded.split('/RK=')[0];
} catch (e) {
return null;
}
}
return null;
}
/**
* Fetch dengan cookie jar internal
* @param {string} url
* @param {object} [customHeaders={}]
* @returns {Promise<{html: string, headers: Headers}>}
*/
async _fetch(url, customHeaders = {}) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeout);
try {
const headers = { ...customHeaders };
// Sisipkan cookies jika ada
if (this._cookies) {
headers['Cookie'] = this._cookies;
}
const response = await fetch(url, {
headers,
signal: controller.signal,
redirect: 'follow'
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}${response.statusText ? ': ' + response.statusText : ''}`);
}
// Simpan cookies dari response untuk retry nanti
const setCookie = response.headers.get('set-cookie');
if (setCookie) {
// Ambil bagian cookie saja (nama=value), buang atribut
const parsed = setCookie.split(',').map(c => c.split(';')[0].trim()).filter(Boolean);
if (parsed.length > 0) {
this._cookies = parsed.join('; ');
}
}
return {
html: await response.text(),
headers: response.headers
};
} finally {
clearTimeout(timer);
}
}
/**
* Cari track Spotify via Yahoo Search
* @param {string} query
* @param {number} offset
* @returns {Promise}
*/
async _searchYahoo(query, offset) {
const params = new URLSearchParams({
p: `site:spotify.com/intl-id/track ${query}`,
b: offset,
ei: 'UTF-8'
});
const url = `https://id.search.yahoo.com/search?${params.toString()}`;
const { html } = await this._fetch(url, {
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7'
});
const $ = cheerio.load(html);
const results = [];
const seenIds = new Set();
// Cari semua link Yahoo redirect yang mengandung Spotify track
$('a[href*="r.search.yahoo.com"]').each((i, el) => {
const href = $(el).attr('href');
if (!href || !href.includes('/RU=')) return;
const realUrl = this._extractRealUrl(href);
if (!realUrl || !realUrl.includes('open.spotify.com/intl-id/track')) return;
const trackId = this._extractTrackId(realUrl);
if (!trackId || seenIds.has(trackId)) return;
seenIds.add(trackId);
const title = this._cleanTitle($(el).text());
results.push({
title: title || `Spotify Track ${trackId}`,
trackID: trackId,
trackURL: realUrl.split('?')[0]
});
});
// Fallback: cari langsung di HTML untuk URL encoded
if (results.length === 0) {
const encodedMatches = html.match(/open\.spotify\.com%2fintl-id%2ftrack%2f([a-zA-Z0-9]+)/gi);
if (encodedMatches) {
encodedMatches.forEach(match => {
try {
const decoded = decodeURIComponent(match);
const trackId = decoded.match(/\/track\/([a-zA-Z0-9]+)/);
if (trackId && !seenIds.has(trackId[1])) {
seenIds.add(trackId[1]);
results.push({
title: `Spotify Track ${trackId[1]}`,
trackID: trackId[1],
trackURL: `https://open.spotify.com/intl-id/track/${trackId[1]}`
});
}
} catch (e) {
// Skip invalid encoded URLs
}
});
}
}
return results;
}
/**
* Cari track Spotify via Yahoo Search dengan retry mechanism.
*
* Alur:
* 1. Coba Yahoo Search pertama kali
* 2. Jika gagal → retry dengan cookies dari sebelumnya (jika ada)
* 3. Jika gagal 2x → throw error
*
* @param {string} query - Kata kunci pencarian
* @param {number} [offset=1] - Halaman hasil pencarian
* @returns {Promise>}
*
* @example
* const scraper = require('./lib/yahooSpotify');
* const results = await scraper.search('dj ya odna');
* // => [{ title: '...', trackID: '...', trackURL: '...' }, ...]
*/
async search(query, offset = 1) {
if (!query || typeof query !== 'string') {
throw new Error("Parameter 'query' wajib diisi.");
}
let lastError = null;
// Percobaan ke-1
try {
const results = await this._searchYahoo(query, offset);
if (results && results.length > 0) {
return results;
}
lastError = new Error('Yahoo tidak mengembalikan hasil');
} catch (error) {
lastError = error;
}
// Percobaan ke-2 (retry dengan cookies)
try {
const results = await this._searchYahoo(query, offset);
if (results && results.length > 0) {
return results;
}
lastError = new Error('Yahoo tidak mengembalikan hasil (retry)');
} catch (error) {
lastError = error;
}
// Gagal 2x — throw error
throw new Error(`Gagal mencari di Yahoo setelah 2 percobaan: ${lastError.message}`);
}
}
module.exports = new YahooSpotifyScraper();
---
// FILE: lib\yahooSoundcloud.js
const axios = require('axios');
const cheerio = require('cheerio');
/**
* YahooSoundCloudScraper V2
* Output yang lebih bersih dan deteksi tipe konten.
*/
class YahooSoundCloudScraper {
constructor() {
this.baseUrl = 'https://id.search.yahoo.com/search';
this.headers = {
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7'
};
}
/**
* Ekstraksi URL asli dari redirector Yahoo menggunakan Regex
*/
_extractSoundCloudUrl(yahooUrl) {
if (!yahooUrl) return null;
// Mencari pola RU=... sampai akhir segment sebelum /RK atau &
const match = yahooUrl.match(/RU=([^/&]+)/);
if (match && match[1]) {
try {
const decoded = decodeURIComponent(match[1]);
return decoded.split('/RK=')[0]; // Bersihkan sisa parameter tracking
} catch (e) {
return yahooUrl;
}
}
return yahooUrl;
}
/**
* Menentukan apakah konten berupa track atau playlist
*/
_determineType(url) {
if (!url) return 'unknown';
return url.includes('/sets/') ? 'playlist' : 'track';
}
/**
* Membersihkan judul dari breadcrumb Yahoo (seperti 'SoundCloud https://...')
*/
_cleanTitle(rawTitle) {
if (!rawTitle) return '';
// Yahoo sering menggabungkan breadcrumb di awal.
// Kita ambil bagian setelah teks "SoundCloud" atau segment URL.
const parts = rawTitle.split(' - SoundCloud');
let title = parts[0];
// Hapus sisa-sisa breadcrumb URL jika masih ada
if (title.includes('https://')) {
const cleanParts = title.split(/\s+/);
// Ambil hanya teks yang bukan bagian dari URL navigasi
title = cleanParts.filter(p => !p.includes('http') && !p.includes('›') && p.toLowerCase() !== 'soundcloud').join(' ');
}
return title.trim();
}
async search(query, offset = 1) {
try {
const params = {
p: `site://soundcloud.com ${query}`,
b: offset,
ei: 'UTF-8',
nojs: '1'
};
const response = await axios.get(this.baseUrl, { params, headers: this.headers });
const $ = cheerio.load(response.data);
const finalData = [];
$('section.algo-sr').each((i, el) => {
const anchor = $(el).find('.compTitle a');
const rawUrl = anchor.attr('href');
const scUrl = this._extractSoundCloudUrl(rawUrl);
if (scUrl && scUrl.includes('soundcloud.com')) {
finalData.push({
title: this._cleanTitle(anchor.text()),
url: scUrl,
type: this._determineType(scUrl),
description: $(el).find('.s-desc').text().replace(/^.*?\d{4}\s·\s/, '').trim()
});
}
});
return finalData;
} catch (error) {
throw new Error(error.message);
}
}
}
module.exports = new YahooSoundCloudScraper();
---
// FILE: lib\yahooSearch.js
const axios = require('axios');
const cheerio = require('cheerio');
/**
* Yahoo Search Scraper (Enhanced for Mobile/Modern Layout)
* @param {string} query - Kata kunci pencarian
*/
async function search(query) {
if (!query) throw new Error("Query is required.");
// Updated URL with parameters to match the provided context (Mobile/Standard layout)
const url = `https://search.yahoo.com/search?p=${encodeURIComponent(query)}&fr=yfp-hrmob&fr2=p:fp,m:sb&.tsrc=yfp-hrmob&ei=UTF-8&fp=1&toggle=1&cop=mss`;
try {
const response = await axios.get(url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8',
'Referer': 'https://search.yahoo.com/'
}
});
const $ = cheerio.load(response.data);
const results = [];
// Unified selection for both Mobile and Desktop layouts found in Yahoo search results
$('.algo, .algo-sr, .Sr, .ag-1, .ag-2, .ag-3, .ag-4, .ag-5, .ag-6, .ag-7, .ag-8, .ag-9, .ag-10').each((i, el) => {
const titleNode = $(el).find('.compTitle h3 a, .compTitle a.s-title, h3 a').first();
const title = titleNode.text().trim();
let link = titleNode.attr('href');
// Extract the real URL from Yahoo's redirect link if present
if (link && link.includes('r.search.yahoo.com')) {
const match = link.match(/\/RU=([^\/]+)\//);
if (match && match[1]) {
try {
link = decodeURIComponent(match[1]);
} catch (e) {
// Keep original link if decoding fails
}
}
}
// Look for description in common mobile/desktop snippet classes
const snippet = $(el).find('.compText p, .s-desc, .compText, .st').first().text().trim();
if (title && link && link.startsWith('http')) {
results.push({
title,
link,
snippet: snippet || 'No description available.'
});
}
});
// Fallback for specific legacy or different regional layouts
if (results.length === 0) {
$('.algo-sr').each((i, el) => {
const titleNode = $(el).find('h3 a');
const title = titleNode.text().trim();
const link = titleNode.attr('href');
const snippet = $(el).find('.compText, .s-desc').text().trim();
if (title && link) {
results.push({
title,
link,
snippet: snippet || 'No description available.'
});
}
});
}
return results;
} catch (error) {
throw new Error("Gagal mengambil hasil pencarian Yahoo: " + error.message);
}
}
module.exports = { search };
---
// FILE: lib\xdownloader.js
const axios = require('axios');
const cheerio = require('cheerio');
/**
* X/Twitter Video Downloader for xsaver.io
* @param {string} twitterUrl - URL video dari X (Twitter)
*/
async function getXVideoInfo(twitterUrl) {
try {
const baseUrl = 'https://www.xsaver.io/x-downloader/';
const targetUrl = `${baseUrl}download.php?url=${encodeURIComponent(twitterUrl)}`;
const response = await axios.get(targetUrl, {
headers: {
'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',
'Referer': 'https://www.xsaver.io/x-downloader/id/',
'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7'
}
});
const $ = cheerio.load(response.data);
const results = [];
// 1. Ambil Judul Video
const title = $('.video-title').text().trim();
// 2. Iterasi setiap item media yang ditemukan
$('.media-item').each((index, element) => {
const thumb = $(element).find('.media-thumb img').attr('src');
// Mencari link download video (save-url.php)
const downloadLinkRaw = $(element).find('a[href^="save-url.php"]').attr('href');
if (downloadLinkRaw) {
// Ekstraksi URL asli dari parameter query 'url'
const urlParams = new URLSearchParams(downloadLinkRaw.split('?')[1]);
const directVideoUrl = urlParams.get('url');
results.push({
id: index + 1,
type: 'video',
thumbnail: thumb,
url: directVideoUrl,
proxy_link: baseUrl + downloadLinkRaw
});
}
});
return {
success: true,
title: title || 'X Video',
results: results
};
} catch (error) {
return {
success: false,
message: error.message
};
}
}
module.exports = { getXVideoInfo };
---
// FILE: lib\vdfr-downloader.js
const axios = require('axios');
const cheerio = require('cheerio');
const fs = require('fs');
const path = require('path');
class VDFRDownloader {
constructor() {
this.baseUrl = 'https://vdfr.app';
this.client = axios.create({
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5'
},
timeout: 15000
});
}
/**
* Mengambil link download video dari halaman hasil vdfr.app
* @param {string} instagramUrl - URL reel/post Instagram publik
* @returns {Promise} - URL unduhan dengan token JWT
*/
async getDownloadLink(instagramUrl) {
try {
// Request halaman download
const encodedUrl = encodeURIComponent(instagramUrl);
const response = await this.client.get(`${this.baseUrl}/download/`, {
params: { url: instagramUrl } // axios otomatis encoding
});
const $ = cheerio.load(response.data);
// Cari link download dengan selector spesifik
const downloadLink = $('a.download__item__info__actions__button').attr('href');
if (!downloadLink) {
// Coba alternatif: mungkin ada beberapa link
const allLinks = $('a[href*="downloads.acxcdn.com/vdfr/video?token="]');
if (allLinks.length > 0) {
return allLinks.first().attr('href');
}
throw new Error('Download link tidak ditemukan. Kemungkinan video tidak tersedia atau Instagram memblokir permintaan.');
}
return downloadLink;
} catch (error) {
if (error.response) {
throw new Error(`Server vdfr.app mengembalikan status ${error.response.status}`);
}
throw error;
}
}
/**
* Mengunduh video dari link token langsung ke file
* @param {string} downloadUrl - URL hasil dari getDownloadLink()
* @param {string} outputDir - Direktori penyimpanan (default: './downloads')
* @returns {Promise} - Path file yang berhasil diunduh
*/
async downloadVideo(downloadUrl, outputDir = './downloads') {
try {
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const response = await this.client.get(downloadUrl, {
responseType: 'stream'
});
// Ambil nama file dari header Content-Disposition atau gunakan timestamp
const disposition = response.headers['content-disposition'];
let filename = `instagram_${Date.now()}.mp4`;
if (disposition) {
const match = disposition.match(/filename="(.+)"/);
if (match) filename = match[1];
}
const filePath = path.join(outputDir, filename);
const writer = fs.createWriteStream(filePath);
response.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on('finish', () => resolve(filePath));
writer.on('error', reject);
});
} catch (error) {
throw new Error(`Gagal mengunduh video: ${error.message}`);
}
}
/**
* Proses lengkap: dapatkan link -> unduh video
* @param {string} instagramUrl
* @param {string} outputDir
* @returns {Promise<{downloadLink: string, filePath: string}>}
*/
async process(instagramUrl, outputDir) {
console.log(`Mengambil link download untuk: ${instagramUrl}`);
const downloadLink = await this.getDownloadLink(instagramUrl);
console.log(`Link didapat: ${downloadLink}`);
console.log(`Mengunduh video...`);
const filePath = await this.downloadVideo(downloadLink, outputDir);
console.log(`Video tersimpan di: ${filePath}`);
return { downloadLink, filePath };
}
}
module.exports = VDFRDownloader;
---
// FILE: lib\upscale.js
const axios = require('axios');
const FormData = require('form-data');
const { uploadToTmp } = require('./uploader');
// --- KONFIGURASI CONSTANTS ---
const TARGET_URL = 'https://cloudinary.com/tools/image-upscale';
const SIGNER_URL = 'https://cloudinary-tools.netlify.app/.netlify/functions/sign-upload-params';
// --- FALLBACK CONFIG ---
const FALLBACK_CONFIG = {
cloudName: 'dtz0urit6',
apiKey: '985946268373735',
uploadPreset: 'cloudinary-tools'
};
const client = axios.create({
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': TARGET_URL
}
});
/**
* 1. DYNAMIC CONFIG EXTRACTOR
*/
async function getDynamicConfig() {
try {
const htmlParams = await client.get(TARGET_URL);
const scriptMatch = htmlParams.data.match(/src="([^"]*\/app\.js[^"]*)"/);
if (!scriptMatch) throw new Error("Path app.js tidak ditemukan.");
const appJsUrl = new URL(scriptMatch[1], TARGET_URL).href;
const jsParams = await client.get(appJsUrl);
const jsContent = jsParams.data;
const cloudNameMatch = jsContent.match(/cloudName\s*=\s*\(isLocal\)\s*\?\s*'[^']+'\s*:\s*'([^']+)'/);
const apiKeyMatch = jsContent.match(/api_key\s*=\s*\(isLocal\)\s*\?\s*'[^']+'\s*:\s*'([^']+)'/);
const presetMatch = jsContent.match(/uploadPreset\s*=\s*\(isLocal\)\s*\?\s*'[^']+'\s*:\s*'([^']+)'/);
if (cloudNameMatch && apiKeyMatch && presetMatch) {
return {
cloudName: cloudNameMatch[1],
apiKey: apiKeyMatch[1],
uploadPreset: presetMatch[1]
};
}
throw new Error("Gagal regex config.");
} catch (error) {
return FALLBACK_CONFIG;
}
}
/**
* 2. SIGNATURE GENERATOR
*/
async function getSignature(config, timestamp) {
try {
const payload = {
paramsToSign: {
source: 'uw',
timestamp: timestamp,
upload_preset: config.uploadPreset
}
};
const response = await client.post(SIGNER_URL, payload, {
headers: { 'Content-Type': 'application/json' }
});
if (!response.data.signature) throw new Error("Signature kosong.");
return response.data.signature;
} catch (error) {
throw new Error(`Gagal get signature: ${error.message}`);
}
}
/**
* 3. UPLOADER (Buffer Support)
*/
async function uploadImage(config, signature, timestamp, imageBuffer) {
const form = new FormData();
form.append('file', imageBuffer, { filename: 'input.jpg' });
form.append('api_key', config.apiKey);
form.append('timestamp', timestamp);
form.append('upload_preset', config.uploadPreset);
form.append('signature', signature);
form.append('source', 'uw');
const uploadUrl = `https://api.cloudinary.com/v1_1/${config.cloudName}/auto/upload`;
try {
const response = await client.post(uploadUrl, form, {
headers: { ...form.getHeaders() }
});
return response.data;
} catch (error) {
throw new Error(`Upload gagal: ${error.response?.data?.error?.message || error.message}`);
}
}
const upscale = {
process: async (url) => {
try {
// 1. Download source image
const imgRes = await axios.get(url, { responseType: 'arraybuffer' });
const imgBuffer = Buffer.from(imgRes.data);
// 2. Get Config
const config = await getDynamicConfig();
// 3. Auth
const timestamp = Math.floor(Date.now() / 1000);
const signature = await getSignature(config, timestamp);
// 4. Upload to Cloudinary
const uploadResult = await uploadImage(config, signature, timestamp, imgBuffer);
// 5. Construct URL
// Parameter Transformasi Cloudinary: e_upscale, q_auto, f_auto
const transformation = 'e_upscale,q_auto,f_auto';
const cloudinaryUrl = `https://res.cloudinary.com/${config.cloudName}/image/upload/${transformation}/${uploadResult.public_id}`;
// 6. Download Result
const resultRes = await axios.get(cloudinaryUrl, { responseType: 'arraybuffer' });
const resultBuffer = Buffer.from(resultRes.data);
// 7. Upload to Public Server (Puruh2o / tmp)
const publicUrl = await uploadToTmp(resultBuffer, `upscale-${Date.now()}.jpg`);
return {
success: true,
image: publicUrl
};
} catch (error) {
return {
success: false,
error: error.message
};
}
}
};
module.exports = { upscale };
---
// FILE: lib\uploader.js
const axios = require('axios');
const FormData = require('form-data');
const https = require('https');
const { encrypt } = require('./crypto');
/**
* Upload file via raw multipart HTTP request
*/
function rawMultipartUpload(hostname, path, buffer, filename, fieldName = 'file') {
return new Promise((resolve, reject) => {
const boundary = '----Boundary' + Math.random().toString(36).slice(2, 16);
const header = Buffer.from(
`--${boundary}\r\n` +
`Content-Disposition: form-data; name="${fieldName}"; filename="${filename}"\r\n` +
`Content-Type: application/octet-stream\r\n\r\n`
);
const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
const body = Buffer.concat([header, buffer, footer]);
const options = {
hostname,
path,
method: 'POST',
headers: {
'Content-Type': `multipart/form-data; boundary=${boundary}`,
'Content-Length': body.length,
'User-Agent': 'Mozilla/5.0'
},
timeout: 120000
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk.toString());
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(data.trim());
} else {
reject(new Error(`HTTP ${res.statusCode}: ${data.trim()}`));
}
});
});
req.on('error', reject);
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
req.write(body);
req.end();
});
}
async function uploadToCatbox(buffer, filename) {
const text = await rawMultipartUpload('catbox.moe', '/user/api.php', buffer, filename, 'fileToUpload');
if (!text.startsWith('http')) throw new Error(`Invalid response: ${text}`);
return text;
}
async function uploadToLitterbox(buffer, filename) {
const boundary = '----Boundary' + Math.random().toString(36).slice(2, 16);
const parts = [
Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="reqtype"\r\n\r\nfileupload\r\n`),
Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="time"\r\n\r\n24h\r\n`),
Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="fileToUpload"; filename="${filename}"\r\nContent-Type: application/octet-stream\r\n\r\n`),
buffer,
Buffer.from(`\r\n--${boundary}--\r\n`)
];
const body = Buffer.concat(parts);
return new Promise((resolve, reject) => {
const options = {
hostname: 'litterbox.catbox.moe',
path: '/resources/internals/api.php',
method: 'POST',
headers: {
'Content-Type': `multipart/form-data; boundary=${boundary}`,
'Content-Length': body.length,
'User-Agent': 'Mozilla/5.0'
},
timeout: 120000
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', chunk => data += chunk.toString());
res.on('end', () => {
const text = data.trim();
if (text.startsWith('http')) resolve(text);
else reject(new Error(`HTTP ${res.statusCode}: ${text}`));
});
});
req.on('error', reject);
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
req.write(body);
req.end();
});
}
async function uploadToTmpfiles(buffer, filename) {
const form = new FormData();
form.append('file', buffer, filename);
const resp = await axios.post('https://tmpfiles.org/api/v1/upload', form, {
headers: { ...form.getHeaders(), 'User-Agent': 'Mozilla/5.0' },
timeout: 60000
});
if (resp.data?.status !== 'success') throw new Error('Tmpfiles upload failed');
return resp.data.data.url.replace(/https?:\/\/(www\.)?tmpfiles\.org\//, 'https://tmpfiles.org/dl/');
}
async function uploadToGofile(buffer, filename) {
// Step 1: Create guest account to get token
let token = null;
try {
const guestRes = await axios.post('https://api.gofile.io/accounts', {}, {
headers: { 'User-Agent': 'Mozilla/5.0' },
timeout: 30000
});
if (guestRes.data?.status === 'ok') {
token = guestRes.data.data.token;
}
} catch (e) {
// If guest account creation fails, proceed without token
}
// Step 2: Upload file
const form = new FormData();
form.append('file', buffer, filename);
const headers = { ...form.getHeaders(), 'User-Agent': 'Mozilla/5.0' };
if (token) headers['Authorization'] = 'Bearer ' + token;
const resp = await axios.post('https://store3.gofile.io/uploadFile', form, {
headers,
timeout: 120000
});
if (resp.data?.status !== 'ok') throw new Error('Gofile upload failed: ' + (resp.data?.status || 'unknown'));
const downloadPage = resp.data.data.downloadPage;
const contentCode = resp.data.data.code || downloadPage.split('/').pop();
// Step 3: Get direct download URL via content API
if (token && contentCode) {
try {
const contentRes = await axios.get('https://api.gofile.io/contents/' + contentCode, {
headers: {
'Authorization': 'Bearer ' + token,
'User-Agent': 'Mozilla/5.0'
},
timeout: 30000
});
if (contentRes.data?.status === 'ok' && contentRes.data.data) {
const data = contentRes.data.data;
// If it's a folder with children, get the first file's link
if (data.children) {
const children = Object.values(data.children);
if (children.length > 0 && children[0].link) {
return children[0].link;
}
}
// Direct file link
if (data.link) {
return data.link;
}
}
} catch (e) {
// Fall through to scraping approach
}
}
// Step 4: Scrape download page HTML for direct URL
try {
const directUrl = await scrapeGofileDirectUrl(downloadPage, token);
if (directUrl) return directUrl;
} catch (e) {
// Fall through
}
// Step 5: If all else fails, try constructing direct URL from known pattern
// Pattern: https://{server}.gofile.io/download/{contentId}
try {
const serverRes = await axios.get('https://api.gofile.io/servers', {
headers: { 'User-Agent': 'Mozilla/5.0' },
timeout: 10000
});
if (serverRes.data?.status === 'ok' && serverRes.data.data?.servers?.length > 0) {
const server = serverRes.data.data.servers[0].name;
const directUrl = `https://${server}.gofile.io/download/${contentCode}`;
return directUrl;
}
} catch (e) {
// If server list fails, use store3 as default
return `https://store3.gofile.io/download/${contentCode}`;
}
// Ultimate fallback: return the download page
return downloadPage;
}
/**
* Scrape gofile download page HTML to extract direct download URL
*/
async function scrapeGofileDirectUrl(downloadPage, token) {
const headers = {
'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',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Referer': 'https://gofile.io/',
};
if (token) {
headers['Cookie'] = `accountToken=${token}`;
}
const pageRes = await axios.get(downloadPage, {
headers,
maxRedirects: 5,
timeout: 30000
});
const html = pageRes.data;
const contentCode = downloadPage.split('/').pop();
// Pattern 1: Look for direct download URL in JSON-LD or structured data
const jsonLdMatch = html.match(/