mirror of
https://github.com/vega-org/vega-providers.git
synced 2026-04-17 15:41:45 +00:00
feat: add testing and configuration for providers
This commit is contained in:
352
interactive-test.js
Normal file
352
interactive-test.js
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
const cheerio = require("cheerio");
|
||||||
|
const axios = require("axios");
|
||||||
|
const readline = require("readline");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const { getBaseUrl } = require("./dist/getBaseUrl.js");
|
||||||
|
|
||||||
|
const providerContext = { axios, cheerio, getBaseUrl };
|
||||||
|
|
||||||
|
// Create readline interface
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper function to prompt user input
|
||||||
|
function prompt(question) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
rl.question(question, (answer) => {
|
||||||
|
resolve(answer.trim());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all available providers and their functions
|
||||||
|
function getAvailableProviders() {
|
||||||
|
const distPath = path.join(__dirname, "dist");
|
||||||
|
const providers = {};
|
||||||
|
|
||||||
|
if (!fs.existsSync(distPath)) {
|
||||||
|
console.log(
|
||||||
|
"❌ Build directory not found. Please run 'npm run build' first."
|
||||||
|
);
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = fs.readdirSync(distPath, { withFileTypes: true });
|
||||||
|
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (item.isDirectory()) {
|
||||||
|
const providerPath = path.join(distPath, item.name);
|
||||||
|
const files = fs.readdirSync(providerPath);
|
||||||
|
|
||||||
|
providers[item.name] = {};
|
||||||
|
|
||||||
|
files.forEach((file) => {
|
||||||
|
if (file.endsWith(".js")) {
|
||||||
|
const functionName = file.replace(".js", "");
|
||||||
|
try {
|
||||||
|
const modulePath = path.join(providerPath, file);
|
||||||
|
const module = require(modulePath);
|
||||||
|
|
||||||
|
// Get all exported functions
|
||||||
|
const functions = Object.keys(module).filter(
|
||||||
|
(key) => typeof module[key] === "function"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (functions.length > 0) {
|
||||||
|
providers[item.name][functionName] = {
|
||||||
|
path: modulePath,
|
||||||
|
functions: functions,
|
||||||
|
module: module,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Skip files that can't be loaded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also check for standalone files
|
||||||
|
items.forEach((item) => {
|
||||||
|
if (item.isFile() && item.name.endsWith(".js")) {
|
||||||
|
const functionName = item.name.replace(".js", "");
|
||||||
|
try {
|
||||||
|
const modulePath = path.join(distPath, item.name);
|
||||||
|
const module = require(modulePath);
|
||||||
|
|
||||||
|
const functions = Object.keys(module).filter(
|
||||||
|
(key) => typeof module[key] === "function"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (functions.length > 0) {
|
||||||
|
if (!providers["standalone"]) providers["standalone"] = {};
|
||||||
|
providers["standalone"][functionName] = {
|
||||||
|
path: modulePath,
|
||||||
|
functions: functions,
|
||||||
|
module: module,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Skip files that can't be loaded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display available providers
|
||||||
|
function displayProviders(providers) {
|
||||||
|
console.log("\n🎯 Available Providers:");
|
||||||
|
console.log("========================");
|
||||||
|
|
||||||
|
const providerNames = Object.keys(providers);
|
||||||
|
providerNames.forEach((provider, index) => {
|
||||||
|
const functionCount = Object.keys(providers[provider]).length;
|
||||||
|
console.log(`${index + 1}. ${provider} (${functionCount} modules)`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return providerNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display functions for a provider
|
||||||
|
function displayFunctions(provider, providerData) {
|
||||||
|
console.log(`\n📋 Available modules in ${provider}:`);
|
||||||
|
console.log("======================================");
|
||||||
|
|
||||||
|
const modules = Object.keys(providerData);
|
||||||
|
modules.forEach((module, index) => {
|
||||||
|
const functions = providerData[module].functions;
|
||||||
|
console.log(`${index + 1}. ${module} - Functions: ${functions.join(", ")}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get sample data for different function types
|
||||||
|
function getSampleData(functionName, moduleName) {
|
||||||
|
const samples = {
|
||||||
|
// Meta functions
|
||||||
|
getMeta: {
|
||||||
|
link: "https://example.com/movie-title",
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Posts/Search functions
|
||||||
|
getPosts: {
|
||||||
|
url: "https://example.com/search?q=movie",
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
getSearchPosts: {
|
||||||
|
searchQuery: "avengers",
|
||||||
|
page: 1,
|
||||||
|
providerContext,
|
||||||
|
providerValue: moduleName,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Episodes functions
|
||||||
|
getEpisodes: {
|
||||||
|
url: "episode-id-or-url",
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Stream functions
|
||||||
|
getStream: {
|
||||||
|
url: "https://example.com/stream-url",
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Catalog functions
|
||||||
|
getCatalog: {
|
||||||
|
type: "movie",
|
||||||
|
genre: "action",
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return samples[functionName] || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the selected function
|
||||||
|
async function executeFunction(module, functionName, params) {
|
||||||
|
try {
|
||||||
|
console.log(`\n⚡ Executing ${functionName}...`);
|
||||||
|
console.log("📝 Parameters:", JSON.stringify(params, null, 2));
|
||||||
|
console.log("⏳ Please wait...\n");
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
const result = await module[functionName](params);
|
||||||
|
const endTime = Date.now();
|
||||||
|
|
||||||
|
console.log("✅ Success!");
|
||||||
|
console.log(`⏱️ Execution time: ${endTime - startTime}ms`);
|
||||||
|
console.log("📊 Result:");
|
||||||
|
console.log("=".repeat(50));
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
console.log("=".repeat(50));
|
||||||
|
} catch (error) {
|
||||||
|
console.log("❌ Error occurred:");
|
||||||
|
console.log("🔍 Error details:", error.message);
|
||||||
|
if (error.stack) {
|
||||||
|
console.log("📚 Stack trace:", error.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow user to customize parameters
|
||||||
|
async function customizeParameters(sampleParams, functionName) {
|
||||||
|
console.log(`\n🔧 Customize parameters for ${functionName}:`);
|
||||||
|
console.log("Current parameters:", JSON.stringify(sampleParams, null, 2));
|
||||||
|
|
||||||
|
const useCustom = await prompt(
|
||||||
|
"\nDo you want to customize parameters? (y/n): "
|
||||||
|
);
|
||||||
|
|
||||||
|
if (useCustom.toLowerCase() === "y" || useCustom.toLowerCase() === "yes") {
|
||||||
|
const customParams = { ...sampleParams };
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(sampleParams)) {
|
||||||
|
if (key !== "providerContext") {
|
||||||
|
const newValue = await prompt(
|
||||||
|
`${key} (current: ${JSON.stringify(value)}): `
|
||||||
|
);
|
||||||
|
if (newValue) {
|
||||||
|
// Try to parse as JSON, otherwise use as string
|
||||||
|
try {
|
||||||
|
customParams[key] = JSON.parse(newValue);
|
||||||
|
} catch {
|
||||||
|
customParams[key] = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return customParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sampleParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main interactive loop
|
||||||
|
async function main() {
|
||||||
|
console.log("🚀 Vega Providers Interactive Tester");
|
||||||
|
console.log("=====================================");
|
||||||
|
|
||||||
|
const providers = getAvailableProviders();
|
||||||
|
|
||||||
|
if (Object.keys(providers).length === 0) {
|
||||||
|
console.log(
|
||||||
|
"❌ No providers found. Make sure to build the project first with 'npm run build'"
|
||||||
|
);
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
// Select provider
|
||||||
|
const providerNames = displayProviders(providers);
|
||||||
|
const providerChoice = await prompt(
|
||||||
|
`\nSelect a provider (1-${providerNames.length}) or 'q' to quit: `
|
||||||
|
);
|
||||||
|
|
||||||
|
if (providerChoice.toLowerCase() === "q") {
|
||||||
|
console.log("👋 Goodbye!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerIndex = parseInt(providerChoice) - 1;
|
||||||
|
if (providerIndex < 0 || providerIndex >= providerNames.length) {
|
||||||
|
console.log("❌ Invalid choice. Please try again.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedProvider = providerNames[providerIndex];
|
||||||
|
const providerData = providers[selectedProvider];
|
||||||
|
|
||||||
|
// Select module
|
||||||
|
const modules = displayFunctions(selectedProvider, providerData);
|
||||||
|
const moduleChoice = await prompt(
|
||||||
|
`\nSelect a module (1-${modules.length}): `
|
||||||
|
);
|
||||||
|
|
||||||
|
const moduleIndex = parseInt(moduleChoice) - 1;
|
||||||
|
if (moduleIndex < 0 || moduleIndex >= modules.length) {
|
||||||
|
console.log("❌ Invalid choice. Please try again.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedModule = modules[moduleIndex];
|
||||||
|
const moduleData = providerData[selectedModule];
|
||||||
|
|
||||||
|
// Select function
|
||||||
|
console.log(`\n🔧 Available functions in ${selectedModule}:`);
|
||||||
|
moduleData.functions.forEach((func, index) => {
|
||||||
|
console.log(`${index + 1}. ${func}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
const functionChoice = await prompt(
|
||||||
|
`\nSelect a function (1-${moduleData.functions.length}): `
|
||||||
|
);
|
||||||
|
|
||||||
|
const functionIndex = parseInt(functionChoice) - 1;
|
||||||
|
if (functionIndex < 0 || functionIndex >= moduleData.functions.length) {
|
||||||
|
console.log("❌ Invalid choice. Please try again.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedFunction = moduleData.functions[functionIndex];
|
||||||
|
|
||||||
|
// Get and customize parameters
|
||||||
|
const sampleParams = getSampleData(selectedFunction, selectedProvider);
|
||||||
|
const finalParams = await customizeParameters(
|
||||||
|
sampleParams,
|
||||||
|
selectedFunction
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute function
|
||||||
|
await executeFunction(moduleData.module, selectedFunction, finalParams);
|
||||||
|
|
||||||
|
// Ask if user wants to continue
|
||||||
|
const continueChoice = await prompt(
|
||||||
|
"\n🔄 Test another function? (y/n): "
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
continueChoice.toLowerCase() !== "y" &&
|
||||||
|
continueChoice.toLowerCase() !== "yes"
|
||||||
|
) {
|
||||||
|
console.log("👋 Goodbye!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("❌ An unexpected error occurred:", error.message);
|
||||||
|
const retryChoice = await prompt("🔄 Try again? (y/n): ");
|
||||||
|
if (
|
||||||
|
retryChoice.toLowerCase() !== "y" &&
|
||||||
|
retryChoice.toLowerCase() !== "yes"
|
||||||
|
) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rl.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle process termination
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
console.log("\n👋 Goodbye!");
|
||||||
|
rl.close();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the interactive tester
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("❌ Fatal error:", error);
|
||||||
|
rl.close();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -12,7 +12,8 @@
|
|||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
"cheerio": "^1.1.0",
|
"cheerio": "^1.1.0",
|
||||||
"react-native-aes-crypto": "^3.2.1",
|
"react-native-aes-crypto": "^3.2.1",
|
||||||
"rimraf": "^6.0.1"
|
"rimraf": "^6.0.1",
|
||||||
|
"zod": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cheerio": "^0.22.35",
|
"@types/cheerio": "^0.22.35",
|
||||||
@@ -2642,6 +2643,15 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-X2niJNY54MGam4L6Kj0AxeedeDIi/E5QFW0On2faSX5J4/pfLk1tW+cRMIMoojnCavn/u5W/kX17e1CSGnKMxA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test-providers.js",
|
"test": "node test-providers.js",
|
||||||
|
"test:provider": "node test-provider.js",
|
||||||
|
"test:provider:build": "npm run build && node test-provider.js",
|
||||||
|
"test:interactive": "npm run build && node interactive-test.js",
|
||||||
|
"test:quick": "npm run build && node quick-test.js",
|
||||||
|
"test:ui": "npm run test:interactive",
|
||||||
"build": "node build-simple.js",
|
"build": "node build-simple.js",
|
||||||
"dev": "node dev-server.js",
|
"dev": "node dev-server.js",
|
||||||
"dev:build": "npm run build && npm run dev",
|
"dev:build": "npm run build && npm run dev",
|
||||||
@@ -30,6 +35,7 @@
|
|||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
"cheerio": "^1.1.0",
|
"cheerio": "^1.1.0",
|
||||||
"react-native-aes-crypto": "^3.2.1",
|
"react-native-aes-crypto": "^3.2.1",
|
||||||
"rimraf": "^6.0.1"
|
"rimraf": "^6.0.1",
|
||||||
|
"zod": "^4.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
111
test-config.js
Normal file
111
test-config.js
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// Common test configurations
|
||||||
|
// You can customize these and run them quickly
|
||||||
|
|
||||||
|
const testConfigs = {
|
||||||
|
// UHD Tests
|
||||||
|
uhdMeta: {
|
||||||
|
provider: "uhd",
|
||||||
|
module: "meta",
|
||||||
|
function: "getMeta",
|
||||||
|
params: {
|
||||||
|
link: "https://uhdmovies.email/download-squid-game-season-2-hindi-1080p-2160p-4k/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// LuxMovies Tests
|
||||||
|
luxPosts: {
|
||||||
|
provider: "luxMovies",
|
||||||
|
module: "posts",
|
||||||
|
function: "getPosts",
|
||||||
|
params: {
|
||||||
|
url: "https://rogmovies.sbs/page/1/?s=pan",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// PrimeMirror Tests
|
||||||
|
primeMirrorEpisodes: {
|
||||||
|
provider: "primeMirror",
|
||||||
|
module: "episodes",
|
||||||
|
function: "getEpisodes",
|
||||||
|
params: {
|
||||||
|
url: "0KMA7H0RHEPJA51SUBXKN9V6VA",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
primeMirrorMeta: {
|
||||||
|
provider: "primeMirror",
|
||||||
|
module: "meta",
|
||||||
|
function: "getMeta",
|
||||||
|
params: {
|
||||||
|
link: "https://www.netflixmirror.com/title/82020512",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
primeMirrorSearch: {
|
||||||
|
provider: "primeMirror",
|
||||||
|
module: "posts",
|
||||||
|
function: "getSearchPosts",
|
||||||
|
params: {
|
||||||
|
searchQuery: "breaking",
|
||||||
|
page: 1,
|
||||||
|
providerValue: "primeMirror",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// CinemaLuxe Tests
|
||||||
|
cinemaLuxeEpisodes: {
|
||||||
|
provider: "cinemaLuxe",
|
||||||
|
module: "episodes",
|
||||||
|
function: "getEpisodes",
|
||||||
|
params: {
|
||||||
|
url: "https://cinemalux.net/?88fdac61e5=cVQxdnNXeGRIRXlZTEQ0bTZSZlFsT09qclNlQzExOUNwVk5JZ05JK1ZjbzVxSWt1SHZSZjdZUm5vVnZEOEd1QXlrdXhPdnNETHRHTnpPUUNFN3k3VVdpY0J0OW5rem10c1ZlZ2xRcjI2YjFWRm9Uc3FEeEd0aWZlNFBpOHJ6bms=",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Add more test configurations here as needed
|
||||||
|
// Template:
|
||||||
|
// yourTestName: {
|
||||||
|
// provider: 'providerName',
|
||||||
|
// module: 'moduleName',
|
||||||
|
// function: 'functionName',
|
||||||
|
// params: {
|
||||||
|
// // your parameters here
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Predefined test batches
|
||||||
|
const testBatches = {
|
||||||
|
// Test all meta functions
|
||||||
|
allMeta: [
|
||||||
|
testConfigs.uhdMeta,
|
||||||
|
testConfigs.primeMirrorMeta,
|
||||||
|
// Add more meta tests
|
||||||
|
],
|
||||||
|
|
||||||
|
// Test all posts/search functions
|
||||||
|
allPosts: [
|
||||||
|
testConfigs.luxPosts,
|
||||||
|
testConfigs.primeMirrorSearch,
|
||||||
|
// Add more posts tests
|
||||||
|
],
|
||||||
|
|
||||||
|
// Test all episode functions
|
||||||
|
allEpisodes: [
|
||||||
|
testConfigs.primeMirrorEpisodes,
|
||||||
|
testConfigs.cinemaLuxeEpisodes,
|
||||||
|
// Add more episode tests
|
||||||
|
],
|
||||||
|
|
||||||
|
// Quick smoke test - test one function from each major provider
|
||||||
|
smokeTest: [
|
||||||
|
testConfigs.uhdMeta,
|
||||||
|
testConfigs.luxPosts,
|
||||||
|
testConfigs.primeMirrorSearch,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
testConfigs,
|
||||||
|
testBatches,
|
||||||
|
};
|
||||||
507
test-provider.js
Normal file
507
test-provider.js
Normal file
@@ -0,0 +1,507 @@
|
|||||||
|
const readline = require("readline");
|
||||||
|
const cheerio = require("cheerio");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { z } = require("zod");
|
||||||
|
const { getBaseUrl } = require("./dist/getBaseUrl.js");
|
||||||
|
const { hubcloudExtracter } = require("./dist/hubcloudExtractor.js");
|
||||||
|
const { gofileExtracter } = require("./dist/gofileExtracter.js");
|
||||||
|
const { superVideoExtractor } = require("./dist/superVideoExtractor.js");
|
||||||
|
const { gdFlixExtracter } = require("./dist/gdFlixExtractor.js");
|
||||||
|
|
||||||
|
// Create readline interface
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Helper function to prompt user input
|
||||||
|
function prompt(question) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
rl.question(question, (answer) => {
|
||||||
|
resolve(answer.trim());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock providerContext (predefined - user doesn't need to provide this)
|
||||||
|
const providerContext = {
|
||||||
|
axios,
|
||||||
|
cheerio,
|
||||||
|
getBaseUrl,
|
||||||
|
commonHeaders: {
|
||||||
|
"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",
|
||||||
|
},
|
||||||
|
extractors: {
|
||||||
|
hubcloudExtracter: hubcloudExtracter,
|
||||||
|
gofileExtracter: gofileExtracter,
|
||||||
|
superVideoExtractor: superVideoExtractor,
|
||||||
|
gdFlixExtracter: gdFlixExtracter,
|
||||||
|
},
|
||||||
|
Crypto: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function parameter definitions based on README and types
|
||||||
|
const functionParams = {
|
||||||
|
// Posts functions
|
||||||
|
getPosts: {
|
||||||
|
required: ["filter", "page"],
|
||||||
|
optional: ["signal"],
|
||||||
|
defaults: {
|
||||||
|
page: 1,
|
||||||
|
filter: "",
|
||||||
|
providerValue: "", // Will be set to provider name
|
||||||
|
signal: new AbortController().signal,
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
prompts: {
|
||||||
|
filter: "Enter filter (e.g., '/category/popular' or '' for latest): ",
|
||||||
|
page: "Enter page number (default: 1): ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
getSearchPosts: {
|
||||||
|
required: ["searchQuery", "page"],
|
||||||
|
optional: ["signal"],
|
||||||
|
defaults: {
|
||||||
|
page: 1,
|
||||||
|
providerValue: "", // Will be set to provider name
|
||||||
|
signal: new AbortController().signal,
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
prompts: {
|
||||||
|
searchQuery: "Enter search query: ",
|
||||||
|
page: "Enter page number (default: 1): ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Meta function
|
||||||
|
getMeta: {
|
||||||
|
required: ["link"],
|
||||||
|
optional: [],
|
||||||
|
defaults: {
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
prompts: {
|
||||||
|
link: "Enter movie/show URL: ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Episodes function
|
||||||
|
getEpisodes: {
|
||||||
|
required: ["url"],
|
||||||
|
optional: [],
|
||||||
|
defaults: {
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
prompts: {
|
||||||
|
url: "Enter episode/season URL or ID: ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Stream function
|
||||||
|
getStream: {
|
||||||
|
required: ["link", "type"],
|
||||||
|
optional: ["signal"],
|
||||||
|
defaults: {
|
||||||
|
type: "movie",
|
||||||
|
signal: new AbortController().signal,
|
||||||
|
providerContext,
|
||||||
|
},
|
||||||
|
prompts: {
|
||||||
|
link: "Enter stream link/URL: ",
|
||||||
|
type: "Enter type (movie/series) [default: movie]: ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sample values for quick testing
|
||||||
|
const sampleValues = {
|
||||||
|
getPosts: {
|
||||||
|
filter: "",
|
||||||
|
page: "1",
|
||||||
|
},
|
||||||
|
getSearchPosts: {
|
||||||
|
searchQuery: "avengers",
|
||||||
|
page: "1",
|
||||||
|
},
|
||||||
|
getMeta: {
|
||||||
|
link: "https://example.com/movie-title",
|
||||||
|
},
|
||||||
|
getEpisodes: {
|
||||||
|
url: "season-1-url-or-id",
|
||||||
|
},
|
||||||
|
getStream: {
|
||||||
|
link: "https://example.com/stream-url",
|
||||||
|
type: "movie",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getParameters(functionName, providerName) {
|
||||||
|
const paramDef = functionParams[functionName];
|
||||||
|
if (!paramDef) {
|
||||||
|
throw new Error(`Unknown function: ${functionName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = { ...paramDef.defaults };
|
||||||
|
|
||||||
|
// Set providerValue to the provider name for functions that need it
|
||||||
|
if (params.hasOwnProperty("providerValue")) {
|
||||||
|
params.providerValue = providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n📝 Enter parameters for ${functionName}:`);
|
||||||
|
console.log(`💡 Press Enter to use sample values`);
|
||||||
|
|
||||||
|
// Get required parameters
|
||||||
|
for (const paramName of paramDef.required) {
|
||||||
|
const promptText = paramDef.prompts[paramName];
|
||||||
|
const sampleValue = sampleValues[functionName]?.[paramName] || "";
|
||||||
|
|
||||||
|
let value = await prompt(
|
||||||
|
`${promptText}${sampleValue ? `[sample: ${sampleValue}] ` : ""}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!value && sampleValue) {
|
||||||
|
value = sampleValue;
|
||||||
|
console.log(`Using sample value: ${sampleValue}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value && paramDef.required.includes(paramName)) {
|
||||||
|
console.log(`❌ ${paramName} is required!`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type conversion
|
||||||
|
if (paramName === "page") {
|
||||||
|
params[paramName] = parseInt(value) || 1;
|
||||||
|
} else {
|
||||||
|
params[paramName] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testProvider(providerName, functionName) {
|
||||||
|
try {
|
||||||
|
console.log(`\n🧪 Testing ${providerName} - ${functionName}`);
|
||||||
|
console.log("=".repeat(50));
|
||||||
|
|
||||||
|
// Check if provider exists
|
||||||
|
const modulePath = `./dist/${providerName}`;
|
||||||
|
let module;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// For posts, we need to check which file has the function
|
||||||
|
if (functionName === "getPosts" || functionName === "getSearchPosts") {
|
||||||
|
module = require(`${modulePath}/posts.js`);
|
||||||
|
} else if (functionName === "getMeta") {
|
||||||
|
module = require(`${modulePath}/meta.js`);
|
||||||
|
} else if (functionName === "getEpisodes") {
|
||||||
|
module = require(`${modulePath}/episodes.js`);
|
||||||
|
} else if (functionName === "getStream") {
|
||||||
|
module = require(`${modulePath}/stream.js`);
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unknown function: ${functionName}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(
|
||||||
|
`❌ Provider '${providerName}' not found or built. Make sure to run 'npm run build' first.`
|
||||||
|
);
|
||||||
|
console.log(`Error: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if function exists
|
||||||
|
if (!module[functionName]) {
|
||||||
|
console.log(`❌ Function '${functionName}' not found in ${providerName}`);
|
||||||
|
const availableFunctions = Object.keys(module).filter(
|
||||||
|
(key) => typeof module[key] === "function"
|
||||||
|
);
|
||||||
|
console.log(`Available functions: ${availableFunctions.join(", ")}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get parameters
|
||||||
|
const params = await getParameters(functionName, providerName);
|
||||||
|
|
||||||
|
console.log("\n📋 Final parameters:");
|
||||||
|
console.log(JSON.stringify(params, null, 2));
|
||||||
|
|
||||||
|
// Execute function
|
||||||
|
console.log("\n⏳ Executing...");
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
const result = await module[functionName](params);
|
||||||
|
const endTime = Date.now();
|
||||||
|
|
||||||
|
console.log(`\n✅ Success! (${endTime - startTime}ms)`);
|
||||||
|
console.log("📊 Result:");
|
||||||
|
console.log("-".repeat(60));
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
console.log("-".repeat(60));
|
||||||
|
|
||||||
|
// Validate response
|
||||||
|
console.log("\n🔍 Response Validation:");
|
||||||
|
const validationResult = validateResponse(functionName, result);
|
||||||
|
console.log(validationResult.message);
|
||||||
|
|
||||||
|
if (!validationResult.isValid) {
|
||||||
|
console.log(
|
||||||
|
"\n💡 Tip: Check your provider implementation to ensure it returns the correct format."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`\n❌ Error testing ${providerName}/${functionName}:`);
|
||||||
|
console.log("🔍 Error:", error.message);
|
||||||
|
if (error.stack) {
|
||||||
|
console.log("📚 Stack:", error.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zod schemas for response validation
|
||||||
|
const PostSchema = z.object({
|
||||||
|
title: z.string().min(1, "Title cannot be empty"),
|
||||||
|
link: z.string().url("Link must be a valid URL"),
|
||||||
|
image: z.string().url("Image must be a valid URL"),
|
||||||
|
provider: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const StreamSchema = z.object({
|
||||||
|
server: z.string().min(1, "Server name cannot be empty"),
|
||||||
|
link: z.string().url("Stream link must be a valid URL"),
|
||||||
|
type: z.string().min(1, "Type cannot be empty"),
|
||||||
|
quality: z.enum(["360", "480", "720", "1080", "2160"]).optional(),
|
||||||
|
subtitles: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
title: z.string(),
|
||||||
|
language: z.string(),
|
||||||
|
type: z.string(),
|
||||||
|
uri: z.string().url(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
headers: z.any().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const LinkSchema = z.object({
|
||||||
|
title: z.string().min(1, "Link title cannot be empty"),
|
||||||
|
quality: z.string().optional(),
|
||||||
|
episodesLink: z.string().optional(),
|
||||||
|
directLinks: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
title: z.string().min(1, "Direct link title cannot be empty"),
|
||||||
|
link: z.string().url("Direct link must be a valid URL"),
|
||||||
|
type: z.enum(["movie", "series"]).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const InfoSchema = z.object({
|
||||||
|
title: z.string().min(1, "Title cannot be empty"),
|
||||||
|
image: z.string().url("Image must be a valid URL"),
|
||||||
|
synopsis: z.string(),
|
||||||
|
imdbId: z.string(),
|
||||||
|
type: z.string().min(1, "Type cannot be empty"),
|
||||||
|
tags: z.array(z.string()).optional(),
|
||||||
|
cast: z.array(z.string()).optional(),
|
||||||
|
rating: z.string().optional(),
|
||||||
|
linkList: z.array(LinkSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const EpisodeLinkSchema = z.object({
|
||||||
|
title: z.string().min(1, "Episode title cannot be empty"),
|
||||||
|
link: z.string().min(1, "Episode link cannot be empty"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Response schemas for each function
|
||||||
|
const responseSchemas = {
|
||||||
|
getPosts: z.array(PostSchema),
|
||||||
|
getSearchPosts: z.array(PostSchema),
|
||||||
|
getMeta: InfoSchema,
|
||||||
|
getEpisodes: z.array(EpisodeLinkSchema),
|
||||||
|
getStream: z.array(StreamSchema),
|
||||||
|
};
|
||||||
|
|
||||||
|
function validateResponse(functionName, result) {
|
||||||
|
const schema = responseSchemas[functionName];
|
||||||
|
if (!schema) {
|
||||||
|
return { isValid: true, message: "No validation schema found" };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
schema.parse(result);
|
||||||
|
|
||||||
|
// Additional checks for array responses
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
const itemCount = result.length;
|
||||||
|
return {
|
||||||
|
isValid: true,
|
||||||
|
message: `✅ Validation Success: Response matches expected ${functionName} format (${itemCount} items)`,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
isValid: true,
|
||||||
|
message: `✅ Validation Success: Response matches expected ${functionName} format`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof z.ZodError) {
|
||||||
|
const issues = error.issues.map((issue) => {
|
||||||
|
let message = issue.message;
|
||||||
|
let location = "";
|
||||||
|
|
||||||
|
if (issue.path.length > 0) {
|
||||||
|
const path = issue.path.join(".");
|
||||||
|
// Check if it's an array item
|
||||||
|
if (issue.path.some((p) => typeof p === "number")) {
|
||||||
|
const arrayIndex = issue.path.find((p) => typeof p === "number");
|
||||||
|
const fieldPath = issue.path
|
||||||
|
.slice(issue.path.indexOf(arrayIndex) + 1)
|
||||||
|
.join(".");
|
||||||
|
location = ` in item ${arrayIndex}${
|
||||||
|
fieldPath ? ` (field: ${fieldPath})` : ""
|
||||||
|
}`;
|
||||||
|
} else {
|
||||||
|
location = ` at field: ${path}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${message}${location}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
message: `❌ Validation Failed:\n${issues
|
||||||
|
.map((issue) => ` • ${issue}`)
|
||||||
|
.join("\n")}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
message: `❌ Validation Error: ${error.message}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
// Check for rebuild flag
|
||||||
|
const rebuildIndex = args.indexOf("--rebuild");
|
||||||
|
const shouldRebuild = rebuildIndex !== -1;
|
||||||
|
|
||||||
|
// Remove rebuild flag from args
|
||||||
|
if (shouldRebuild) {
|
||||||
|
args.splice(rebuildIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
console.log("🎯 Vega Providers Command Line Tester");
|
||||||
|
console.log("====================================");
|
||||||
|
console.log("\nUsage:");
|
||||||
|
console.log(" node test-provider.js <provider> <function> [--rebuild]");
|
||||||
|
console.log("\nExamples:");
|
||||||
|
console.log(" node test-provider.js mod getPosts");
|
||||||
|
console.log(" node test-provider.js mod getSearchPosts --rebuild");
|
||||||
|
console.log(" node test-provider.js uhd getMeta");
|
||||||
|
console.log(" node test-provider.js primeMirror getEpisodes");
|
||||||
|
console.log(" node test-provider.js luxMovies getStream");
|
||||||
|
console.log("\nAvailable functions:");
|
||||||
|
console.log(" - getPosts (get posts by filter/category)");
|
||||||
|
console.log(" - getSearchPosts (search for posts)");
|
||||||
|
console.log(" - getMeta (get metadata for a movie/show)");
|
||||||
|
console.log(" - getEpisodes (get episodes for a season)");
|
||||||
|
console.log(" - getStream (get streaming links)");
|
||||||
|
console.log("\nFlags:");
|
||||||
|
console.log(" --rebuild Rebuild TypeScript files before testing");
|
||||||
|
console.log(
|
||||||
|
"\nNote: Run with --rebuild flag if you've made changes to TypeScript files!"
|
||||||
|
);
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
console.log("❌ Please provide both provider name and function name");
|
||||||
|
console.log(
|
||||||
|
"Usage: node test-provider.js <provider> <function> [--rebuild]"
|
||||||
|
);
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerName = args[0];
|
||||||
|
const functionName = args[1];
|
||||||
|
|
||||||
|
// Validate function name
|
||||||
|
const validFunctions = [
|
||||||
|
"getPosts",
|
||||||
|
"getSearchPosts",
|
||||||
|
"getMeta",
|
||||||
|
"getEpisodes",
|
||||||
|
"getStream",
|
||||||
|
];
|
||||||
|
if (!validFunctions.includes(functionName)) {
|
||||||
|
console.log(`❌ Invalid function name: ${functionName}`);
|
||||||
|
console.log(`Valid functions: ${validFunctions.join(", ")}`);
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild if requested
|
||||||
|
if (shouldRebuild) {
|
||||||
|
console.log("🔨 Rebuilding TypeScript files...");
|
||||||
|
const { spawn } = require("child_process");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const buildProcess = spawn("npm", ["run", "build"], {
|
||||||
|
stdio: "inherit",
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
buildProcess.on("close", (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
console.log("✅ Build completed successfully!");
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
console.log("❌ Build failed!");
|
||||||
|
reject(new Error(`Build process exited with code ${code}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buildProcess.on("error", (error) => {
|
||||||
|
console.log("❌ Build error:", error.message);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log("❌ Failed to rebuild. Please run 'npm run build' manually.");
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await testProvider(providerName, functionName);
|
||||||
|
rl.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle process termination
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
console.log("\n👋 Test cancelled!");
|
||||||
|
rl.close();
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the tester
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("❌ Fatal error:", error);
|
||||||
|
rl.close();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
78
test-runner.js
Normal file
78
test-runner.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
const { quickTest, batchTest } = require("./quick-test.js");
|
||||||
|
const { testConfigs, testBatches } = require("./test-config.js");
|
||||||
|
|
||||||
|
// Get command line arguments
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("🎯 Vega Providers Test Runner");
|
||||||
|
console.log("=============================");
|
||||||
|
|
||||||
|
if (args.length === 0) {
|
||||||
|
console.log("\nUsage:");
|
||||||
|
console.log(" node test-runner.js <testName> - Run a single test");
|
||||||
|
console.log(" node test-runner.js batch <batch> - Run a test batch");
|
||||||
|
console.log(" node test-runner.js list - List available tests");
|
||||||
|
console.log("\nExamples:");
|
||||||
|
console.log(" node test-runner.js uhdMeta");
|
||||||
|
console.log(" node test-runner.js batch smokeTest");
|
||||||
|
console.log(" node test-runner.js list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = args[0];
|
||||||
|
|
||||||
|
if (command === "list") {
|
||||||
|
console.log("\n📋 Available individual tests:");
|
||||||
|
Object.keys(testConfigs).forEach((test) => {
|
||||||
|
const config = testConfigs[test];
|
||||||
|
console.log(
|
||||||
|
` ${test} - ${config.provider}/${config.module}/${config.function}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\n📦 Available test batches:");
|
||||||
|
Object.keys(testBatches).forEach((batch) => {
|
||||||
|
const tests = testBatches[batch];
|
||||||
|
console.log(` ${batch} - ${tests.length} tests`);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command === "batch") {
|
||||||
|
const batchName = args[1];
|
||||||
|
if (!batchName || !testBatches[batchName]) {
|
||||||
|
console.log("❌ Please specify a valid batch name.");
|
||||||
|
console.log("Available batches:", Object.keys(testBatches).join(", "));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\n🚀 Running test batch: ${batchName}`);
|
||||||
|
await batchTest(testBatches[batchName]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single test
|
||||||
|
const testName = command;
|
||||||
|
if (!testConfigs[testName]) {
|
||||||
|
console.log(`❌ Test '${testName}' not found.`);
|
||||||
|
console.log("Available tests:", Object.keys(testConfigs).join(", "));
|
||||||
|
console.log("Use 'node test-runner.js list' to see all available tests.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = testConfigs[testName];
|
||||||
|
console.log(`\n🧪 Running test: ${testName}`);
|
||||||
|
|
||||||
|
await quickTest(
|
||||||
|
config.provider,
|
||||||
|
config.module,
|
||||||
|
config.function,
|
||||||
|
config.params
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("❌ Fatal error:", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user