badan-ser
Version:
external functions for zoe
321 lines (275 loc) • 9.25 kB
JavaScript
const fs = require('fs');
const path = require('path');
const axios = require('axios');
const cheerio = require("cheerio");
const FormData = require('form-data');
const puppeteer = require('puppeteer');
function loadEnv(filePath = '.env') {
const envPath = path.resolve(process.cwd(), filePath);
if (!fs.existsSync(envPath)) {
throw new Error(`Environment file not found: ${filePath}`);
}
const envContent = fs.readFileSync(envPath, 'utf-8');
const lines = envContent.split('\n');
lines.forEach((line) => {
if (!line || line.startsWith('#')) return;
const [rawKey, ...rawValue] = line.split('=');
if (rawKey && rawValue.length > 0) {
const key = rawKey.trim();
const value = rawValue.join('=').trim();
const trimmedValue = value.replace(/^["']|["']$/g, '');
process.env[key] = trimmedValue;
}
});
return process.env;
};
async function ss({
url,
output,
type = 'viewport',
region,
selector,
viewport = { width: 1280, height: 720 },
delay = 0
}) {
if (!url) throw new Error('URL is required');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport(viewport);
await page.goto(url, { waitUntil: 'networkidle2' });
if (delay > 0) {
console.log(`Waiting ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
try {
let buffer;
if (type === 'full') {
buffer = await page.screenshot({ fullPage: true });
} else if (type === 'region') {
if (!region) throw new Error('Region must be provided for region screenshot');
buffer = await page.screenshot({ clip: region });
} else if (type === 'element') {
if (!selector) throw new Error('Selector must be provided for element screenshot');
const element = await page.$(selector);
if (!element) throw new Error('Element not found');
buffer = await element.screenshot();
} else {
buffer = await page.screenshot();
}
if (output) {
const screenshotPath = path.resolve(output);
fs.writeFileSync(screenshotPath, buffer);
console.log(`Screenshot saved to: ${screenshotPath}`);
}
return buffer;
} catch (err) {
console.error('Screenshot capture failed:', err);
throw err;
} finally {
await browser.close();
}
}
async function yts(query) {
try {
const response = await axios.get("https://m.youtube.com/results?search_query=" + encodeURIComponent(query), {
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
},
});
const html = response.data;
const $ = cheerio.load(html);
let ytInitialData;
$("script").each((_, element) => {
const scriptContent = $(element).html();
if (scriptContent && scriptContent.includes("var ytInitialData =")) {
const jsonStr = scriptContent
.replace(/^var ytInitialData = /, "")
.replace(/;$/, "");
ytInitialData = JSON.parse(jsonStr);
}
});
if (!ytInitialData) {
throw new Error("Failed to parse YouTube data.");
}
const results = [];
const content = ytInitialData.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents || [];
const items = content[0]?.itemSectionRenderer?.contents || [];
items.forEach((item) => {
const itemType = Object.keys(item)[0];
const data = item[itemType];
if (itemType === "videoRenderer") {
results.push({
title: data.title?.runs[0]?.text,
videoId: data.videoId,
url: `https://youtu.be/${data.videoId}`,
image: data.thumbnail?.thumbnails?.pop()?.url,
thumbnail: data.thumbnail?.thumbnails?.pop()?.url,
duration: data.lengthText?.simpleText,
views: data.viewCountText?.simpleText,
publishedTime: data.publishedTimeText?.simpleText || "N/A",
author: data.ownerText?.runs[0]?.text,
});
}
});
return results;
} catch (error) {
console.error("Error in ytsearch:", error);
return [];
}
}
class Success {
constructor(data) {
this.success = true;
this.data = data;
}
}
class ErrorResponse {
constructor(error) {
this.success = false;
this.error = error;
}
}
const ytdls = {
mp3: async (url) => {
try {
if (!url || !url.includes('youtube.com') && !url.includes('youtu.be')) {
return new ErrorResponse({
message: "URL YouTube tidak valid!"
});
}
const ds = new FormData();
ds.append("url", url);
const { data } = await axios.post(
"https://www.youtubemp3.ltd/convert",
ds,
{
headers: {
...ds.getHeaders(),
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
},
timeout: 45000
}
);
if (!data || !data.link) {
return new ErrorResponse({
message: "Gagal mendapatkan link download"
});
}
return new Success({
title: data.filename || "Unknown Title",
downloadUrl: data.link,
type: "mp3"
});
} catch (error) {
if (error.code === 'ECONNABORTED') {
return new ErrorResponse({
message: "Request timeout, coba lagi nanti"
});
}
return new ErrorResponse({
message: error.response?.data?.message || error.message || "Gagal convert YouTube ke MP3"
});
}
},
mp4: async (url, quality = "720") => {
try {
if (!url || !url.includes('youtube.com') && !url.includes('youtu.be')) {
return new ErrorResponse({
message: "URL YouTube tidak valid!"
});
}
const validQuality = {
"480": 480,
"1080": 1080,
"720": 720,
"360": 360,
"audio": "mp3",
};
if (!Object.keys(validQuality).includes(quality)) {
return new ErrorResponse({
message: "Quality tidak valid!",
availableQuality: Object.keys(validQuality)
});
}
const qualitys = validQuality[quality];
const { data: firstRequest } = await axios.get(
`https://p.oceansaver.in/ajax/download.php?button=1&start=1&end=1&format=${qualitys}&iframe_source=https://allinonetools.com/&url=${encodeURIComponent(url)}`,
{
timeout: 30000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
}
);
if (!firstRequest || !firstRequest.progress_url) {
return new ErrorResponse({
message: "Gagal memulai proses download"
});
}
const { progress_url } = firstRequest;
let metadata = {
image: firstRequest.info?.image || "",
title: firstRequest.info?.title || "Unknown Title",
downloadUrl: "",
quality: quality,
type: quality === "audio" ? "mp3" : "mp4"
};
let datas;
let attempts = 0;
const maxAttempts = 40;
console.log("Memproses download, mohon tunggu...");
do {
if (attempts >= maxAttempts) {
return new ErrorResponse({
message: "Timeout: Proses download terlalu lama, coba lagi"
});
}
await new Promise(resolve => setTimeout(resolve, 3000));
try {
const { data } = await axios.get(progress_url, {
timeout: 15000,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
datas = data;
if (datas.progress && datas.progress < 100) {
console.log(`Progress: ${datas.progress}%`);
}
} catch (pollError) {
console.log(`Polling attempt ${attempts + 1} failed, retrying...`);
}
attempts++;
} while (!datas?.download_url);
if (!datas.download_url) {
return new ErrorResponse({
message: "Gagal mendapatkan URL download"
});
}
metadata.downloadUrl = datas.download_url;
console.log("Download siap!");
return new Success(metadata);
} catch (error) {
if (error.code === 'ECONNABORTED') {
return new ErrorResponse({
message: "Request timeout, coba lagi nanti"
});
}
return new ErrorResponse({
message: error.response?.data?.message || error.message || "Gagal download video"
});
}
},
// Utility function untuk validasi URL YouTube
isValidYouTubeUrl: (url) => {
const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+$/;
return youtubeRegex.test(url);
},
// Utility function untuk extract video ID
extractVideoId: (url) => {
const regex = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/;
const match = url.match(regex);
return match ? match[1] : null;
}
};
module.exports = { loadEnv, ss, yts, ytdls };