diff --git a/interactive-test.js b/interactive-test.js new file mode 100644 index 0000000..84508a8 --- /dev/null +++ b/interactive-test.js @@ -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); +}); diff --git a/package-lock.json b/package-lock.json index 8811389..2d2311e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "axios": "^1.10.0", "cheerio": "^1.1.0", "react-native-aes-crypto": "^3.2.1", - "rimraf": "^6.0.1" + "rimraf": "^6.0.1", + "zod": "^4.0.2" }, "devDependencies": { "@types/cheerio": "^0.22.35", @@ -2642,6 +2643,15 @@ "engines": { "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" + } } } } diff --git a/package.json b/package.json index 8464ac0..32f10ac 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,11 @@ "main": "index.js", "scripts": { "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", "dev": "node dev-server.js", "dev:build": "npm run build && npm run dev", @@ -30,6 +35,7 @@ "axios": "^1.10.0", "cheerio": "^1.1.0", "react-native-aes-crypto": "^3.2.1", - "rimraf": "^6.0.1" + "rimraf": "^6.0.1", + "zod": "^4.0.2" } } diff --git a/test-config.js b/test-config.js new file mode 100644 index 0000000..786669f --- /dev/null +++ b/test-config.js @@ -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, +}; diff --git a/test-provider.js b/test-provider.js new file mode 100644 index 0000000..ea62a4c --- /dev/null +++ b/test-provider.js @@ -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 [--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 [--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); +}); diff --git a/test-runner.js b/test-runner.js new file mode 100644 index 0000000..2f282ad --- /dev/null +++ b/test-runner.js @@ -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 - Run a single test"); + console.log(" node test-runner.js 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); +});