nb-scraper
Version:
Community scraper library by Newbie Scrape
1,556 lines (1,541 loc) • 118 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// app/index.ts
var index_exports = {};
__export(index_exports, {
CREATOR: () => CREATOR,
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
INFO: () => INFO,
VERSION: () => VERSION,
WeatherMaster: () => WeatherMaster,
Ytdl: () => Ytdl,
analyzeDream: () => analyzeDream,
animeIndo: () => animeIndo,
anyDownloader: () => anyDownloader,
blackboxAi: () => blackboxAi,
createErrorResponse: () => createErrorResponse,
createExomlMessage: () => createExomlMessage,
createSuccessResponse: () => createSuccessResponse,
extractDomain: () => extractDomain,
facebookDownloader: () => facebookDownloader,
ffstalk: () => ffstalk,
formatBytes: () => formatBytes,
generateDeepInfraResponse: () => generateDeepInfraResponse,
generateExomlResponse: () => generateExomlResponse,
generateLyrics: () => generateLyrics,
generatePollinationsImage: () => generatePollinationsImage,
getPollinationsDirectUrl: () => getPollinationsDirectUrl,
getSoundCloudCacheInfo: () => getSoundCloudCacheInfo,
getTurnstileToken: () => getTurnstileToken,
getYoutubePost: () => getYoutubePost,
groupdaSearch: () => groupdaSearch,
isValidUrl: () => isValidUrl,
laraTranslate: () => laraTranslate,
lemonWrite: () => lemonWrite,
liputan6: () => liputan6,
periksadata: () => periksadata,
pinterest: () => pinterest,
premiumDreamAnalysis: () => premiumDreamAnalysis,
quickDreamAnalysis: () => quickDreamAnalysis,
sanitizeString: () => sanitizeString,
savegram: () => savegram,
searchApk: () => searchApk,
searchComics: () => searchComics,
searchSoundCloud: () => searchSoundCloud,
ssyoutube: () => ssyoutube,
teraboxSearch: () => teraboxSearch,
textcraft: () => textcraft,
threads: () => threads,
tiktok: () => tiktok,
translateEcommerceImageFromUrl: () => translateEcommerceImageFromUrl,
translateImage: () => translateImage,
translateManga: () => translateManga,
tutwuriBypass: () => tutwuriBypass,
unaimytextHumanize: () => unaimytextHumanize,
uploadImage: () => uploadImage,
ytmp3cc: () => ytmp3cc,
ytmp3mobi: () => ytmp3mobi
});
module.exports = __toCommonJS(index_exports);
// app/utils.ts
var import_axios = __toESM(require("axios"));
var DEFAULT_CONFIG = {
timeout: 3e4,
retries: 3,
retryDelay: 1e3,
userAgent: "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36"
};
var CREATOR = "nb-scraper";
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function isValidUrl(url2) {
try {
new URL(url2);
return true;
} catch {
return false;
}
}
function sanitizeString(input) {
return input.replace(/[<>'"]/g, "").trim().slice(0, 1e4);
}
function createErrorResponse(error, context) {
let errorMessage;
let errorType = "UNKNOWN_ERROR" /* UNKNOWN_ERROR */;
if (typeof error === "string") {
errorMessage = error;
} else if (error instanceof Error) {
errorMessage = error.message;
if (error.name === "AxiosError" || error.message.includes("network")) {
errorType = "NETWORK_ERROR" /* NETWORK_ERROR */;
} else if (error.message.includes("timeout")) {
errorType = "NETWORK_ERROR" /* NETWORK_ERROR */;
} else if (error.message.includes("rate") || error.message.includes("limit")) {
errorType = "RATE_LIMITED" /* RATE_LIMITED */;
}
} else {
errorMessage = error.message;
errorType = error.type;
}
return {
creator: CREATOR,
status: false,
error: `[${errorType}] ${errorMessage}${context ? ` | Context: ${JSON.stringify(context)}` : ""}`
};
}
function createSuccessResponse(data) {
return {
creator: CREATOR,
status: true,
data
};
}
async function makeRequest(config, options = {}) {
const {
timeout = DEFAULT_CONFIG.timeout,
retries = DEFAULT_CONFIG.retries,
retryDelay = DEFAULT_CONFIG.retryDelay,
headers = {}
} = options;
const requestConfig = {
...config,
timeout,
headers: {
"User-Agent": DEFAULT_CONFIG.userAgent,
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "id-ID,id;q=0.9,en;q=0.8",
...headers,
...config.headers
}
};
let lastError;
for (let attempt = 0; attempt <= retries; attempt++) {
try {
const response2 = await (0, import_axios.default)(requestConfig);
return response2;
} catch (error) {
lastError = error;
if (import_axios.default.isAxiosError(error)) {
const axiosError = error;
if (axiosError.response?.status && axiosError.response.status >= 400 && axiosError.response.status < 500 && axiosError.response.status !== 429) {
throw error;
}
}
if (attempt === retries) {
throw lastError;
}
await sleep(retryDelay * (attempt + 1));
}
}
throw lastError;
}
function validateRequiredParams(params, required) {
for (const param of required) {
const value = params[param];
if (value === void 0 || value === null || value === "") {
throw new Error(`Parameter '${param}' is required and cannot be empty`);
}
if (typeof value === "string" && value.trim() === "") {
throw new Error(`Parameter '${param}' cannot be an empty string`);
}
}
}
function safeJsonParse(jsonString) {
try {
return JSON.parse(jsonString);
} catch {
return null;
}
}
function extractDomain(url2) {
try {
const urlObj = new URL(url2);
return urlObj.hostname;
} catch {
return null;
}
}
function formatBytes(bytes, decimals = 2) {
if (bytes === 0) return "0 Bytes";
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
}
// app/scrapers/blackbox.ts
var DEFAULT_BLACKBOX_CONFIG = {
maxTokens: 1024,
temperature: null,
webSearchMode: false,
memoryEnabled: false
};
async function blackboxAi(query, options = {}) {
try {
validateRequiredParams({ query }, ["query"]);
const sanitizedQuery = query.trim();
if (sanitizedQuery.length === 0) {
return createErrorResponse("Query cannot be empty", { query });
}
if (sanitizedQuery.length > 1e4) {
return createErrorResponse("Query too long (max 10,000 characters)", {
queryLength: sanitizedQuery.length
});
}
const config = { ...DEFAULT_BLACKBOX_CONFIG, ...options };
const headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "id-ID,id;q=0.9",
"Content-Type": "application/json",
"Origin": "https://www.blackbox.ai",
"Referer": "https://www.blackbox.ai/",
"Sec-Ch-Ua": '"Chromium";v="137", "Not/A)Brand";v="24"',
"Sec-Ch-Ua-Mobile": "?1",
"Sec-Ch-Ua-Platform": '"Android"',
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
...options.headers
};
const payload = {
messages: [{
role: "user",
content: sanitizedQuery,
id: generateRandomId()
}],
id: generateRandomId(),
previewToken: null,
userId: null,
codeModelMode: true,
trendingAgentMode: {},
isMicMode: false,
userSystemPrompt: null,
maxTokens: config.maxTokens,
playgroundTopP: null,
playgroundTemperature: config.temperature,
isChromeExt: false,
githubToken: "",
clickedAnswer2: false,
clickedAnswer3: false,
clickedForceWebSearch: config.webSearchMode,
visitFromDelta: false,
isMemoryEnabled: config.memoryEnabled,
mobileClient: false,
userSelectedModel: null,
validated: generateUUID(),
imageGenerationMode: false,
webSearchModePrompt: config.webSearchMode,
deepSearchMode: false,
domains: null,
vscodeClient: false,
codeInterpreterMode: false,
customProfile: {
name: "",
occupation: "",
traits: [],
additionalInfo: "",
enableNewChats: false
},
webSearchModeOption: {
autoMode: true,
webMode: config.webSearchMode,
offlineMode: !config.webSearchMode
},
session: null,
isPremium: false,
subscriptionCache: null,
beastMode: false,
reasoningMode: false,
designerMode: false,
workspaceId: "",
asyncMode: false,
isTaskPersistent: false
};
const response2 = await makeRequest(
{
method: "POST",
url: "https://www.blackbox.ai/api/chat",
data: payload,
headers
},
{
timeout: options.timeout,
retries: options.retries,
retryDelay: options.retryDelay
}
);
if (!response2.data || typeof response2.data !== "string") {
return createErrorResponse("Invalid response format from BlackBox AI", {
responseType: typeof response2.data,
status: response2.status
});
}
const rawResponse = response2.data;
const parsedData = parseBlackBoxResponse(rawResponse);
if (!parsedData) {
return createErrorResponse("Failed to parse BlackBox AI response", {
rawResponse: rawResponse.substring(0, 100) + "..."
});
}
return createSuccessResponse(parsedData);
} catch (error) {
return createErrorResponse(error, {
query: query.substring(0, 100),
options: { ...options, headers: void 0 }
// Don't log headers for security
});
}
}
function parseBlackBoxResponse(rawResponse) {
try {
const parsed = rawResponse.split("$~~~$");
if (parsed.length === 1) {
const response2 = parsed[0]?.trim();
if (!response2) {
return null;
}
return {
response: response2,
source: []
};
} else if (parsed.length >= 3) {
const response2 = parsed[2]?.trim();
const sourcesData = parsed[1];
if (!response2 || !sourcesData) {
return null;
}
const sources = safeJsonParse(sourcesData);
if (!Array.isArray(sources)) {
return {
response: response2,
source: []
};
}
const validSources = sources.filter(
(source) => source && typeof source === "object" && typeof source.link === "string" && typeof source.title === "string"
).map((source) => ({
link: source.link,
title: source.title,
snippet: source.snippet || "",
position: typeof source.position === "number" ? source.position : 0
}));
return {
response: response2,
source: validSources
};
}
return null;
} catch {
return null;
}
}
function generateRandomId() {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < 7; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
function generateUUID() {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === "x" ? r : r & 3 | 8;
return v.toString(16);
});
}
// app/scrapers/threads.ts
async function threads(url2, options = {}) {
try {
validateRequiredParams({ url: url2 }, ["url"]);
const sanitizedUrl = url2.trim();
if (!isValidUrl(sanitizedUrl)) {
return createErrorResponse("Invalid URL format", { url: sanitizedUrl });
}
const domain = extractDomain(sanitizedUrl);
if (!domain?.includes("threads.net")) {
return createErrorResponse("URL must be from threads.net", { domain, url: sanitizedUrl });
}
const apiUrl = `https://api.threadsphotodownloader.com/v2/media?url=${encodeURIComponent(sanitizedUrl)}`;
const headers = {
"User-Agent": "5.0",
"Accept": "application/json",
"Accept-Language": "id-ID,id;q=0.9,en;q=0.8",
...options.headers
};
const response2 = await makeRequest(
{
method: "GET",
url: apiUrl,
headers
},
{
timeout: options.timeout,
retries: options.retries,
retryDelay: options.retryDelay
}
);
if (!response2.data || typeof response2.data !== "object") {
return createErrorResponse("Invalid response format from Threads API", {
responseType: typeof response2.data,
status: response2.status
});
}
const rawData = response2.data;
const imageUrls = parseMediaUrls(rawData.image_urls);
const videoUrls = parseMediaUrls(rawData.video_urls);
let filteredData = {
image_urls: imageUrls,
video_urls: videoUrls
};
if (options.imagesOnly) {
filteredData.video_urls = [];
} else if (options.videosOnly) {
filteredData.image_urls = [];
}
if (filteredData.image_urls.length === 0 && filteredData.video_urls.length === 0) {
return createErrorResponse("No media found in the Threads post", {
url: sanitizedUrl,
rawImageCount: imageUrls.length,
rawVideoCount: videoUrls.length
});
}
return createSuccessResponse(filteredData);
} catch (error) {
return createErrorResponse(error, {
url: url2.substring(0, 100),
options: { ...options, headers: void 0 }
});
}
}
function parseMediaUrls(urls) {
if (!Array.isArray(urls)) {
return [];
}
return urls.filter(
(url2) => typeof url2 === "string" && url2.trim().length > 0 && isValidUrl(url2.trim())
).map((url2) => url2.trim()).slice(0, 50);
}
// app/scrapers/pinterest.ts
async function pinterest(query, options) {
try {
validateRequiredParams({ query }, ["query"]);
const searchUrl = "https://www.pinterest.com/resource/BaseSearchResource/get/";
const params = new URLSearchParams({
data: JSON.stringify({
options: {
query
}
})
});
const response2 = await makeRequest({
url: `${searchUrl}?${params.toString()}`,
method: "HEAD",
headers: {
"screen-dpr": "4",
"x-pinterest-pws-handler": "www/search/[scope].js",
...options?.headers
}
}, options);
const linkHeader = response2.headers.link;
if (!linkHeader) {
return createErrorResponse("No results found for the query", {
type: "INVALID_RESPONSE" /* INVALID_RESPONSE */,
context: { query }
});
}
const links = [...linkHeader.matchAll(/<(.*?)>/gm)].map((v) => v[1]);
return createSuccessResponse({
result: links
});
} catch (error) {
return createErrorResponse(error, {
type: "NETWORK_ERROR" /* NETWORK_ERROR */,
context: { query }
});
}
}
// app/scrapers/exomlapi.ts
var BASE_URL = "https://exomlapi.com/api/chat";
var EXOML_MODELS = [
"llama",
"gemma",
"qwen-3-235b",
"gpt-4.1",
"gpt-4o",
"gpt-4o-mini",
"llama-4-scout",
"llama-4-maverick",
"deepseek-r1",
"qwq-32b"
];
function generateRandomIds() {
const gen = (length, charSet = {}) => {
const l = "abcdefghijklmnopqrstuvwxyz";
const u = l.toUpperCase();
const s = "-_";
const n = "0123456789";
const {
lowerCase = false,
upperCase = false,
symbol = false,
number = false
} = charSet;
let cs = "";
if (!lowerCase && !upperCase && !symbol && !number) {
cs = l + u + s + n;
} else {
if (lowerCase) cs += l;
if (upperCase) cs += u;
if (symbol) cs += s;
if (number) cs += n;
}
return Array.from(
{ length },
() => cs[Math.floor(Math.random() * cs.length)]
).join("");
};
const id = gen(16, { upperCase: true, lowerCase: true, number: true });
const timestamp = (/* @__PURE__ */ new Date()).getTime();
const chatId = `chat-${timestamp}-${gen(9, { lowerCase: true, number: true })}`;
const userId = `local-user-${timestamp}-${gen(9, { lowerCase: true, number: true })}`;
const antiBotId = `${gen(32)}-${gen(8, { number: true, lowerCase: true })}`;
return { id, chatId, userId, antiBotId };
}
function createExomlMessage(role, content) {
return { role, content };
}
async function generateExomlResponse(options) {
try {
validateRequiredParams(options, ["messages"]);
const { messages, systemPrompt = "", model = "gpt-4.1" } = options;
if (!EXOML_MODELS.includes(model)) {
return createErrorResponse(
`Invalid model. Available models: ${EXOML_MODELS.join(", ")}`,
{
type: "INVALID_PARAMETER" /* INVALID_PARAMETER */,
context: { model }
}
);
}
const body = JSON.stringify({
messages,
systemPrompt,
model,
isAuthenticated: true,
...generateRandomIds()
});
const response2 = await makeRequest({
url: BASE_URL,
method: "POST",
headers: {
"Content-Type": "application/json"
},
data: body
});
if (typeof response2.data !== "string") {
return createErrorResponse("Invalid response format from server", {
type: "INVALID_RESPONSE" /* INVALID_RESPONSE */,
context: { rawResponse: response2.data }
});
}
const data = response2.data;
const content = [...data.matchAll(/^0:"(.*?)"$/gm)].map((v) => v[1]).join("").replaceAll("\\n", "\n").replaceAll('\\"', '"');
if (!content) {
return createErrorResponse("Failed to parse message from server", {
type: "PARSE_ERROR" /* PARSE_ERROR */,
context: { rawResponse: data }
});
}
return createSuccessResponse({ content });
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: { service: "ExomlAPI" }
});
}
}
// app/scrapers/dreamanalysis.ts
var BASE_URL2 = "https://safe-coast-53976-cd772af9b056.herokuapp.com/";
function parseDreamResponse(raw) {
if (typeof raw !== "string") return null;
try {
const data = JSON.parse(raw);
return {
analysis: data.analysis,
interpretation: data.interpretation,
symbols: data.symbols || [],
emotions: data.emotions || [],
themes: data.themes || [],
metadata: data.metadata || {}
};
} catch {
return null;
}
}
async function analyzeDream(options) {
try {
validateRequiredParams(options, ["text"]);
const { text, isPremium = true } = options;
const response2 = await makeRequest({
url: BASE_URL2,
method: "POST",
headers: {
"Accept-Encoding": "gzip",
"Connection": "Keep-Alive",
"Content-Type": "application/json",
"Host": "safe-coast-53976-cd772af9b056.herokuapp.com",
"User-Agent": "okhttp/4.9.2"
},
data: JSON.stringify({ text, isPremium })
});
const rawResponse = response2.data;
if (typeof rawResponse !== "string") {
return createErrorResponse("Invalid response format", {
type: "INVALID_RESPONSE" /* INVALID_RESPONSE */,
context: {
service: "DreamAnalysis",
rawResponse: String(rawResponse).substring(0, 100) + "..."
}
});
}
const parsedData = parseDreamResponse(rawResponse);
if (!parsedData) {
return createErrorResponse("Failed to parse Dream response", {
type: "PARSE_ERROR" /* PARSE_ERROR */,
context: {
rawResponse: rawResponse.substring(0, 100) + "..."
}
});
}
return createSuccessResponse(parsedData);
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: { service: "DreamAnalysis" }
});
}
}
async function quickDreamAnalysis(text) {
return analyzeDream({ text, isPremium: false });
}
async function premiumDreamAnalysis(text) {
return analyzeDream({ text, isPremium: true });
}
// app/scrapers/pollinations.ts
var import_stream = require("stream");
var import_form_data = __toESM(require("form-data"));
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_os = __toESM(require("os"));
var BASE_URL3 = "https://image.pollinations.ai/prompt/";
var UPLOAD_URL = "https://catbox.moe/user/api.php";
async function generatePollinationsImage(options) {
try {
validateRequiredParams(options, ["prompt"]);
const { prompt, nologo = true } = options;
const encodedPrompt = encodeURIComponent(prompt);
const imageUrl = `${BASE_URL3}${encodedPrompt}${nologo ? "?nologo=true" : ""}`;
const tempPath = import_path.default.join(import_os.default.tmpdir(), `pollinations_${Date.now()}.jpg`);
const response2 = await makeRequest({
url: imageUrl,
responseType: "arraybuffer"
});
const buffer = Buffer.from(response2.data);
const readable = new import_stream.Readable();
readable.push(buffer);
readable.push(null);
const writer = import_fs.default.createWriteStream(tempPath);
readable.pipe(writer);
await new Promise((resolve, reject) => {
writer.on("finish", () => resolve());
writer.on("error", (err) => reject(err));
});
const form = new import_form_data.default();
form.append("reqtype", "fileupload");
form.append("fileToUpload", import_fs.default.createReadStream(tempPath));
const upload = await makeRequest({
method: "POST",
url: UPLOAD_URL,
data: form,
headers: form.getHeaders()
});
import_fs.default.unlinkSync(tempPath);
if (typeof upload.data !== "string") {
throw new Error("Invalid upload response");
}
return createSuccessResponse({
url: upload.data,
directUrl: imageUrl
});
} catch (error) {
return createErrorResponse(error, {
type: "IMAGE_GENERATION_ERROR" /* IMAGE_GENERATION_ERROR */,
context: { service: "Pollinations" }
});
}
}
function getPollinationsDirectUrl(options) {
validateRequiredParams(options, ["prompt"]);
const { prompt, nologo = true } = options;
const encodedPrompt = encodeURIComponent(prompt);
return `${BASE_URL3}${encodedPrompt}${nologo ? "?nologo=true" : ""}`;
}
// app/scrapers/soundcloud.ts
var BASE_URL4 = "https://soundcloud.com/";
var API_URL = "https://api-v2.soundcloud.com/search/tracks";
var cache = { version: "", id: "" };
function formatDuration(ms) {
const sec = Math.floor(ms / 1e3);
const min = Math.floor(sec / 60);
const remainder = sec % 60;
return `${min}:${remainder.toString().padStart(2, "0")}`;
}
function formatNumber(n) {
if (n >= 1e6) return (n / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
if (n >= 1e3) return (n / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
return n.toString();
}
function formatDate(dateStr) {
if (!dateStr) return null;
const d = new Date(dateStr);
return d.toISOString().split("T")[0];
}
async function getClientID() {
try {
const response2 = await makeRequest({
url: BASE_URL4,
method: "GET"
});
if (typeof response2.data !== "string") {
throw new Error("invalid html data");
}
const html2 = response2.data;
const version = html2.match(
/<script>window\.__sc_version="(\d{10})"<\/script>/
)?.[1];
if (!version) return null;
if (cache.version === version) return cache.id;
const scriptMatches = [...html2.matchAll(
/<script.*?src="(https:\/\/a-v2\.sndcdn\.com\/assets\/[^"]+)"/g
)];
for (const [, scriptUrl] of scriptMatches) {
const { data: js } = await makeRequest({
url: scriptUrl,
method: "GET"
});
if (typeof js !== "string") {
continue;
}
const idMatch = js.match(/client_id:"([a-zA-Z0-9]{32})"/);
if (idMatch) {
cache = { version, id: idMatch[1] };
return idMatch[1];
}
}
} catch (error) {
throw new Error(
`Failed to get client_id: ${error instanceof Error ? error.message : "Unknown error"}`
);
}
return null;
}
async function searchSoundCloud(options) {
const { query, limit = 3 } = options;
let clientId = null;
try {
validateRequiredParams(options, ["query"]);
const clientId2 = await getClientID();
if (!clientId2) {
return createErrorResponse("Failed to obtain client_id", {
type: "AUTH_ERROR" /* AUTH_ERROR */,
context: { service: "SoundCloud" }
});
}
const response2 = await makeRequest({
url: API_URL,
method: "GET",
params: {
q: query,
client_id: clientId2,
limit
}
});
if (!response2.data?.collection) {
return createErrorResponse("Invalid SoundCloud API response", {
type: "INVALID_RESPONSE" /* INVALID_RESPONSE */
});
}
const tracks = response2.data.collection.map((track) => {
const durationMs = track.duration;
const duration = formatDuration(durationMs);
const likeCount = formatNumber(track.likes_count);
const playCount = formatNumber(track.playback_count);
const downloadCount = formatNumber(track.download_count);
const releaseDate = track.release_date || track.created_at;
return {
id: track.id,
title: track.title,
url: track.permalink_url,
duration,
thumbnail: track.artwork_url,
author: {
name: track.user.username,
url: track.user.permalink_url
},
like_count: likeCount,
download_count: downloadCount,
play_count: playCount,
release_date: formatDate(releaseDate)
};
});
return createSuccessResponse({ tracks });
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: { service: "SoundCloud", query, clientId: clientId ? "*****" : "null" }
});
}
}
function getSoundCloudCacheInfo() {
return { ...cache };
}
// app/scrapers/deepinfra.ts
var BASE_URL5 = "https://ai-sdk-starter-deepinfra.vercel.app/api/chat";
async function generateDeepInfraResponse(options) {
try {
validateRequiredParams(options, ["prompt"]);
const { prompt, model = "meta-llama/Llama-3.3-70B-Instruct-Turbo" } = options;
const body = {
id: Math.random().toString(36).slice(2),
selectedModel: model,
messages: [{
role: "user",
content: prompt,
parts: [{ type: "text", text: prompt }]
}]
};
const response2 = await makeRequest({
url: BASE_URL5,
method: "POST",
headers: {
"Content-Type": "application/json"
},
data: body
});
const parts = [];
const responseData = response2.data;
if (responseData && typeof responseData === "object") {
const data = responseData;
if (data.g) {
parts.push(...Array.isArray(data.g) ? data.g : [data.g]);
}
if (data.f) {
parts.push(...Array.isArray(data.f) ? data.f : [data.f]);
}
if (data["0"]) {
parts.push(...Array.isArray(data["0"]) ? data["0"] : [data["0"]]);
}
} else if (typeof responseData === "string") {
parts.push(responseData);
}
const result = parts.join("").trim() || "No response generated";
return createSuccessResponse({
response: result
});
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: {
service: "DeepInfraAI",
model: options.model
}
});
}
}
// app/scrapers/animeindo.ts
var import_url = require("url");
var cheerio = __toESM(require("cheerio"));
var BASE_URL6 = "https://anime-indo.lol";
var animeIndo = {
/**
* Search anime
*
* @example
* ```typescript
* const result = await animeIndo.search("Naruto");
* if (result.status) {
* console.log(result.data);
* }
* ```
* @author Jul
*/
async search(query) {
try {
validateRequiredParams({ query }, ["query"]);
const url2 = `${BASE_URL6}/search/${encodeURIComponent(query)}/`;
const response2 = await makeRequest({ url: url2 });
const $ = cheerio.load(response2.data);
const results = [];
$("table.otable").each((_index, el) => {
const element = $(el);
const title = element.find(".videsc a").text().trim();
const link = BASE_URL6 + element.find(".videsc a").attr("href");
const image = BASE_URL6 + element.find("img").attr("src");
const description = element.find("p.des").text().trim();
const labelEls = element.find(".label");
const year = labelEls.last().text().trim();
results.push({
title,
link,
image,
year,
description
});
});
return createSuccessResponse(results);
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: { service: "AnimeIndo", query }
});
}
},
/**
* Get anime details
*
* @example
* ```typescript
* const result = await animeIndo.detail("https://anime-indo.lol/anime/naruto");
* if (result.status) {
* console.log(result.data);
* }
* ```
* @author Jul
*/
async detail(url2) {
try {
validateRequiredParams({ url: url2 }, ["url"]);
const response2 = await makeRequest({ url: url2 });
const $ = cheerio.load(response2.data);
const title = $("h1.title").text().trim();
let imageSrc = $(".detail img").attr("src") || "";
if (imageSrc.startsWith("/")) {
imageSrc = BASE_URL6 + imageSrc;
}
const genres = [];
$(".detail li a").each((_index, el) => {
genres.push($(el).text().trim());
});
const description = $(".detail p").text().trim();
const episodes = [];
$(".ep a").each((_index, el) => {
let epLink = $(el).attr("href");
if (epLink && epLink.startsWith("/")) {
epLink = BASE_URL6 + epLink;
}
episodes.push({
episode: $(el).text().trim(),
link: epLink || ""
});
});
return createSuccessResponse({
title,
image: imageSrc,
genres,
description,
episodes
});
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: { service: "AnimeIndo", url: url2 }
});
}
},
/**
* Download episode
*
* @example
* ```typescript
* const result = await animeIndo.download("https://anime-indo.lol/episode/naruto-1");
* if (result.status) {
* console.log(result.data.downloadUrl);
* }
* ```
* @author Jul
*/
async download(episodeUrl) {
try {
validateRequiredParams({ episodeUrl }, ["episodeUrl"]);
const { data: episodeHtml } = await makeRequest({
url: episodeUrl,
headers: { "User-Agent": "Mozilla/5.0" }
});
const $ = cheerio.load(episodeHtml);
const title = $("h1.title").first().text().trim();
const description = $(".detail p").text().trim();
const videoLinks = [];
$(".servers a.server").each((_index, el) => {
const label = $(el).text().trim();
let videoUrl = $(el).attr("data-video") || "";
if (videoUrl.startsWith("//")) {
videoUrl = "https:" + videoUrl;
}
videoLinks.push({ label, videoUrl });
});
const gdriveHdLinkObj = videoLinks.find(
(v) => v.label.toLowerCase().includes("gdrive") && v.label.toLowerCase().includes("hd")
);
if (!gdriveHdLinkObj) {
return createErrorResponse("HD quality not available", {
type: "QUALITY_NOT_AVAILABLE" /* QUALITY_NOT_AVAILABLE */,
context: {
episodeUrl,
availableQualities: videoLinks.map((v) => v.label)
}
});
}
const { data: gdriveHtml } = await makeRequest({
url: gdriveHdLinkObj.videoUrl,
headers: { "User-Agent": "Mozilla/5.0" }
});
const $$ = cheerio.load(gdriveHtml);
const gdriveRawLink = $$("#subtitlez").text().trim();
if (!gdriveRawLink) {
throw new Error("Google Drive raw link not found in embed page");
}
const parsedUrl = new import_url.URL(gdriveRawLink);
const allowedHosts = ["drive.google.com"];
if (!allowedHosts.includes(parsedUrl.host)) {
throw new Error("Invalid host for Google Drive raw link");
}
const idMatch = gdriveRawLink.match(/\/d\/([^\/]+)\//) || gdriveRawLink.match(/id=([^&]+)/);
if (!idMatch) throw new Error("Google Drive file ID not found");
const fileId = idMatch[1];
const driveApiUrl = `https://drive.google.com/uc?id=${fileId}&authuser=0&export=download`;
const driveResponse = await makeRequest({
method: "POST",
url: driveApiUrl,
headers: {
"accept-encoding": "gzip, deflate, br",
"content-length": "0",
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
"origin": "https://drive.google.com",
"user-agent": "Mozilla/5.0",
"x-client-data": "CKG1yQEIkbbJAQiitskBCMS2yQEIqZ3KAQioo8oBGLeYygE=",
"x-drive-first-party": "DriveWebUi",
"x-json-requested": "true"
}
});
const jsonStr = driveResponse.data.slice(4);
const json = JSON.parse(jsonStr);
if (!json.downloadUrl || !json.fileName || !json.sizeBytes) {
throw new Error("Invalid Google Drive response");
}
const fileDownloadUrl = json.downloadUrl;
const fileName = json.fileName;
const fileSize = json.sizeBytes;
const headResponse = await makeRequest({
method: "HEAD",
url: fileDownloadUrl,
headers: { "User-Agent": "Mozilla/5.0" }
});
return createSuccessResponse({
title,
description,
videoLinks,
gdriveHdLink: gdriveHdLinkObj.videoUrl,
downloadUrl: fileDownloadUrl,
fileName,
fileSize,
mimetype: headResponse.headers["content-type"] || "application/octet-stream"
});
} catch (error) {
return createErrorResponse(error, {
type: "DOWNLOAD_ERROR" /* DOWNLOAD_ERROR */,
context: { service: "AnimeIndo", episodeUrl }
});
}
}
};
// app/scrapers/facebook.ts
var cheerio2 = __toESM(require("cheerio"));
var import_qs = __toESM(require("qs"));
async function facebookDownloader(url2) {
try {
validateRequiredParams({ url: url2 }, ["url"]);
const allowedHosts = ["facebook.com", "www.facebook.com"];
const parsedHost = new URL(url2).host;
if (!allowedHosts.includes(parsedHost)) {
return createErrorResponse("Invalid Facebook video URL format", {
type: "INVALID_INPUT" /* INVALID_INPUT */,
context: { url: url2 }
});
}
const verifyPayload = import_qs.default.stringify({ url: url2 });
const verifyConfig = {
method: "POST",
url: "https://fdownloader.net/api/userverify",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Accept": "*/*",
"X-Requested-With": "XMLHttpRequest"
},
data: verifyPayload
};
const verifyRes = await makeRequest(verifyConfig);
if (verifyRes.status !== 200 || !verifyRes.data?.token) {
return createErrorResponse("Failed to get verification token", {
type: "AUTH_ERROR" /* AUTH_ERROR */,
context: { service: "FacebookDownloader" }
});
}
const cftoken = verifyRes.data.token;
const ajaxPayload = import_qs.default.stringify({
k_exp: Math.floor(Date.now() / 1e3) + 1800,
k_token: "4901a847f621da898b5429bf38df6f3a0959738cd4eb52a2bf0cf44b3eb44cad",
q: url2,
lang: "id",
web: "fdownloader.net",
v: "v2",
w: "",
cftoken
});
const ajaxConfig = {
method: "POST",
url: "https://v3.fdownloader.net/api/ajaxSearch",
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Accept": "*/*"
},
data: ajaxPayload
};
const ajaxRes = await makeRequest(ajaxConfig);
if (ajaxRes.status !== 200 || typeof ajaxRes.data !== "string" && ajaxRes.data?.status !== "ok") {
return createErrorResponse("Failed to fetch video data", {
type: "API_ERROR" /* API_ERROR */,
context: { service: "FacebookDownloader" }
});
}
const html2 = typeof ajaxRes.data === "string" ? ajaxRes.data : ajaxRes.data?.data || "";
if (!html2) {
return createErrorResponse("No HTML content found in response", {
type: "API_ERROR" /* API_ERROR */,
context: { service: "FacebookDownloader" }
});
}
const $ = cheerio2.load(html2);
const thumbnail = $(".image-fb img").attr("src") || "";
const duration = $(".content p").text().trim();
const title = $(".content h3").text().trim();
const links = [];
$("a.download-link-fb").each((_index, el) => {
const link = $(el).attr("href");
const quality = $(el).attr("title")?.replace("Download ", "") || "Unknown";
const format = link?.includes(".mp4") ? "mp4" : "unknown";
if (link) {
links.push({
quality,
format,
link
});
}
});
if (links.length === 0) {
return createErrorResponse("No download links found", {
type: "NOT_FOUND" /* NOT_FOUND */,
context: { service: "FacebookDownloader" }
});
}
return createSuccessResponse({
title,
duration,
thumbnail,
links
});
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */,
context: { service: "FacebookDownloader" }
});
}
}
// app/scrapers/anydownloader.ts
var cheerio3 = __toESM(require("cheerio"));
async function getToken() {
try {
const config = {
method: "GET",
url: "https://anydownloader.com/en/xiaohongshu-videos-and-photos-downloader",
headers: {
"User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36"
}
};
const response2 = await makeRequest(config);
if (!response2.status || !response2.data) {
return createErrorResponse("Failed to fetch token page", {
type: "AUTH_ERROR" /* AUTH_ERROR */
});
}
const $ = cheerio3.load(response2.data);
const token = $("#token").val();
if (!token) {
return createErrorResponse("Token not found in page", {
type: "NOT_FOUND" /* NOT_FOUND */
});
}
return createSuccessResponse({ token });
} catch (error) {
return createErrorResponse(error, {
type: "NETWORK_ERROR" /* NETWORK_ERROR */
});
}
}
function calculateHash(url2, salt) {
return Buffer.from(url2).toString("base64") + (url2.length + 1e3) + Buffer.from(salt).toString("base64");
}
async function anyDownloader(url2) {
try {
validateRequiredParams({ url: url2 }, ["url"]);
const tokenResponse = await getToken();
if (!tokenResponse.status || !tokenResponse.data?.token) {
return createErrorResponse(
tokenResponse.error ?? "Failed to obtain token",
{ type: "AUTH_ERROR" /* AUTH_ERROR */ }
);
}
const { token } = tokenResponse.data;
const hash = calculateHash(url2, "aio-dl");
const data = new URLSearchParams();
data.append("url", url2);
data.append("token", token);
data.append("hash", hash);
const config = {
method: "POST",
url: "https://anydownloader.com/wp-json/aio-dl/video-data/",
headers: {
"Accept": "*/*",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Origin": "https://anydownloader.com",
"Referer": "https://anydownloader.com/en/xiaohongshu-videos-and-photos-downloader",
"User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36",
"X-Requested-With": "XMLHttpRequest"
},
data: data.toString()
};
const response2 = await makeRequest(config);
if (!response2.status || !response2.data) {
return createErrorResponse("Failed to fetch video data", {
type: "API_ERROR" /* API_ERROR */
});
}
if (response2.data.error) {
return createErrorResponse(response2.data.error, {
type: "API_ERROR" /* API_ERROR */
});
}
return createSuccessResponse(response2.data);
} catch (error) {
return createErrorResponse(error, {
type: "API_ERROR" /* API_ERROR */
});
}
}
// app/scrapers/youtube.ts
var import_axios2 = __toESM(require("axios"));
var import_form_data2 = __toESM(require("form-data"));
var validQualities = {
"480": 480,
"1080": 1080,
"720": 720,
"360": 360,
"audio": "mp3"
};
var YOUTUBE_DOMAINS = /* @__PURE__ */ new Set([
"youtube.com",
"www.youtube.com",
"youtu.be",
"m.youtube.com"
]);
function validateYouTubeUrl(url2) {
if (!isValidUrl(url2)) {
return createErrorResponse("Invalid YouTube URL", {
type: "INVALID_INPUT" /* INVALID_INPUT */
});
}
const domain = extractDomain(url2);
if (!domain || !YOUTUBE_DOMAINS.has(domain.replace(/^www\./, ""))) {
return createErrorResponse("URL must be from YouTube domain", {
type: "INVALID_INPUT" /* INVALID_INPUT */,
context: { validDomains: Array.from(YOUTUBE_DOMAINS) }
});
}
try {
return createSuccessResponse(new URL(url2));
} catch (error) {
return createErrorResponse(error, {
type: "INVALID_INPUT" /* INVALID_INPUT */
});
}
}
var waitForDownloadUrl = async (progressUrl) => {
const maxAttempts = 40;
let attempts = 0;
while (attempts < maxAttempts) {
await new Promise((resolve) => setTimeout(resolve, 3e3));
try {
const progressResponse = await import_axios2.default.get(
progressUrl,
{
timeout: 15e3,
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
}
);
if (progressResponse.data?.download_url) {
return progressResponse.data.download_url;
}
} catch (pollError) {
if (import_axios2.default.isAxiosError(pollError) && pollError.response?.status !== void 0 && pollError.response.status >= 400) {
throw new Error(
`Remote server responded with ${pollError.response.status}`
);
}
}
attempts++;
}
throw new Error("Timeout: please try again");
};
var Ytdl = {
/**
* @beta
*
* Download YouTube video as MP3
* @param url - YouTube video URL
* @example
* ```ts
* import { Ytdl } from 'nb-scraper';
*
* const result = await Ytdl.mp3("https://youtube.com/.../");
* console.log(result)
* ```
* @author YogikId
*/
mp3: async (url2) => {
const urlValidation = validateYouTubeUrl(url2);
if (!urlValidation.status) {
return createErrorResponse({
message: "Invalid YouTube URL",
type: "INVALID_INPUT" /* INVALID_INPUT */
});
}
const ds = new import_form_data2.default();
ds.append("url", url2);
try {
const config = {
method: "post",
url: "https://www.youtubemp3.ltd/convert",
headers: {
...ds.getHeaders(),
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
},
data: ds,
timeout: 45e3
};
const response2 = await (0, import_axios2.default)(config);
const data = response2.data;
if (!data?.link) {
return createErrorResponse("Failed to get download link", {
type: "API_ERROR" /* API_ERROR */
});
}
return createSuccessResponse({
title: data.filename || "Unknown Title",
downloadUrl: data.link,
type: "mp3"
});
} catch (error) {
if (import_axios2.default.isAxiosError(error) && error.code === "ECONNABORTED") {
return createErrorResponse("Request timeout", {
type: "NETWORK_ERROR" /* NETWORK_ERROR */
});
}
const ax = error;
const serverMsg = typeof ax.response?.data === "object" && ax.response?.data !== null && "message" in ax.response.data ? ax.response.data.message : void 0;
return createErrorResponse(
serverMsg ?? ax.message ?? "Audio Download Failed",
{
type: "API_ERROR" /* API_ERROR */
}
);
}
},
/**
* @beta
*
* Download YouTube video in specified quality
* @param url - YouTube video URL
* @param quality - Quality option (480, 720, 1080, 360, audio)
* @example
* ```ts
* import { Ytdl } from 'nb-scraper';
*
* const result = await Ytdl.mp4("https://youtube.com/.../");
* console.log(result)
* ```
* @author YogikId
*/
mp4: async (url2, quality = "720") => {
const urlValidation = validateYouTubeUrl(url2);
if (!urlValidation.status) {
return createErrorResponse({
message: "Invalid YouTube URL",
type: "INVALID_INPUT" /* INVALID_INPUT */
});
}
if (!Object.keys(validQualities).includes(quality)) {
return createErrorResponse(
{ message: "Quality not valid!", type: "INVALID_INPUT" /* INVALID_INPUT */ },
{ availableQuality: Object.keys(validQualities) }
);
}
const qualityParam = validQualities[quality];
const initialUrl = `https://p.oceansaver.in/ajax/download.php?button=1&start=1&end=1&format=${qualityParam}&iframe_source=https://allinonetools.com/&url=${encodeURIComponent(url2)}`;
try {
const firstResponse = await import_axios2.default.get(
initialUrl,
{
timeout: 3e4,
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
}
);
if (!firstResponse.data?.progress_url) {
return createErrorResponse("Failed to proceed download", {
type: "API_ERROR" /* API_ERROR */
});
}
const metadata = {
title: firstResponse.data.info?.title || "Unknown Title",
thumbnail: firstResponse.data.info?.image,
quality: quality === "audio" ? void 0 : quality,
type: quality === "audio" ? "mp3" : "mp4"
};
try {
const downloadUrl = await waitForDownloadUrl(firstResponse.data.progress_url);
metadata.downloadUrl = downloadUrl;
return createSuccessResponse(metadata);
} catch (timeoutError) {
const msg = timeoutError instanceof Error ? timeoutError.message : String(timeoutError);
return createErrorResponse(msg, {
type: "NETWORK_ERROR" /* NETWORK_ERROR */
});
}
} catch (error) {
if (error.code === "ECONNABORTED") {
return createErrorResponse("Request timeout", {
type: "NETWORK_ERROR" /* NETWORK_ERROR */
});
}
const ax = error;
const serverMsg = typeof ax.response?.data === "object" && ax.response?.data !== null && "message" in ax.response.data ? ax.response.data.message : void 0;
return createErrorResponse(
serverMsg ?? ax.message ?? "Video Download Failed",
{
type: "API_ERROR" /* API_ERROR */
}
);
}
}
};
var HEADERS = {
"Referer": "https://ytmp3.cc/",
"Origin": "https://ytmp3.cc/",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0"
};
async function hit(url2, description, returnType = "text") {
const listReturnType = ["text", "json"];
if (!listReturnType.includes(returnType)) {
throw new Error(`${returnType} invalid. `);
}
let result;
let response2;
try {
response2 = await fetch(url2, {
headers: HEADERS
});
const data = await response2.text();
result = data;
try {
if (returnType === "json") {
result = JSON.parse(data);
}
} catch (error) {
throw new Error(`Failed to change return type to ${returnType}. ${error.message}`);
}
return { result, response: response2 };
} catch (error) {
throw new Error(
`Fetch failed at ${description}
Reason: ${error.message}
Status: ${response2?.status || "N/A"} ${response2?.statusText || "N/A"}
Response body: ${result || "N/A"}`
);
}
}
async function getAuthCode() {
const { result: html, response } = await hit("https://ytmp3.cc", "hit homepage ytmp3cc");
const valueOnHtmlMatch = html.match(/<script[^>]*>(.*?)<\/script>/i)?.[1];
if (!valueOnHtmlMatch) {
throw new Error(`Failed to get regex match for code value in html`);
}