198 lines
6.6 KiB
JavaScript
198 lines
6.6 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Build script for nuvio-providers
|
|
*
|
|
* Bundles each provider from src/<provider>/ into a single file at providers/<provider>.js
|
|
*
|
|
* Usage:
|
|
* node build.js # Build all providers
|
|
* node build.js vixsrc # Build only vixsrc
|
|
* node build.js --minify # Build all with minification
|
|
* node build.js --watch # Watch mode (requires nodemon)
|
|
* node build.js --transpile # Transpile async/await in providers/
|
|
*/
|
|
|
|
const esbuild = require('esbuild');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const srcDir = path.join(__dirname, 'src');
|
|
const outDir = path.join(__dirname, 'providers');
|
|
|
|
// Modules that the Nuvio app provides - don't bundle these
|
|
const EXTERNAL_MODULES = [
|
|
'cheerio-without-node-native',
|
|
'react-native-cheerio',
|
|
'cheerio',
|
|
'crypto-js',
|
|
'axios'
|
|
];
|
|
|
|
// Get provider names from command line or discover all
|
|
function getProvidersToBuild() {
|
|
const args = process.argv.slice(2).filter(arg => !arg.startsWith('-'));
|
|
|
|
if (args.length > 0) {
|
|
return args;
|
|
}
|
|
|
|
// Discover all provider folders in src/
|
|
if (!fs.existsSync(srcDir)) {
|
|
console.error('❌ src/ directory not found. Create provider folders in src/<provider>/');
|
|
process.exit(1);
|
|
}
|
|
|
|
return fs.readdirSync(srcDir, { withFileTypes: true })
|
|
.filter(d => d.isDirectory())
|
|
.map(d => d.name);
|
|
}
|
|
|
|
async function buildProvider(providerName, options = {}) {
|
|
const providerDir = path.join(srcDir, providerName);
|
|
const entryPoint = path.join(providerDir, 'index.js');
|
|
const outFile = path.join(outDir, `${providerName}.js`);
|
|
|
|
if (!fs.existsSync(entryPoint)) {
|
|
console.warn(`⚠️ Skipping ${providerName}: no src/${providerName}/index.js found`);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const result = await esbuild.build({
|
|
entryPoints: [entryPoint],
|
|
bundle: true,
|
|
outfile: outFile,
|
|
format: 'cjs', // CommonJS for module.exports compatibility
|
|
platform: 'neutral', // Works in both browser and node-like environments
|
|
// Both Nuvio runtimes support native async/await. Keeping it avoids
|
|
// esbuild's generator helper, which older NuvioTV builds can reject.
|
|
target: 'es2017',
|
|
minify: options.minify || false, // Minify if --minify flag is set
|
|
sourcemap: false,
|
|
external: EXTERNAL_MODULES,
|
|
banner: {
|
|
// NuvioTV embeds the bundle in its own function wrapper. Keep the
|
|
// leading comment on one line so it cannot span wrapper boundaries.
|
|
js: `// ${providerName} - bundled from src/${providerName}/`
|
|
},
|
|
logLevel: 'warning'
|
|
});
|
|
|
|
const stats = fs.statSync(outFile);
|
|
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
const minifyIndicator = options.minify ? ' (minified)' : '';
|
|
console.log(`✅ ${providerName}.js (${sizeKB} KB)${minifyIndicator}`);
|
|
return true;
|
|
} catch (err) {
|
|
console.error(`❌ Failed to build ${providerName}:`, err.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Transpile a single file in providers/ (for developers writing single-file providers with async)
|
|
async function transpileSingleFile(filename) {
|
|
const inputPath = path.join(outDir, filename);
|
|
|
|
if (!fs.existsSync(inputPath)) {
|
|
console.warn(`⚠️ File not found: providers/${filename}`);
|
|
return false;
|
|
}
|
|
|
|
// Read original file
|
|
const originalContent = fs.readFileSync(inputPath, 'utf-8');
|
|
|
|
// Check if it needs transpilation (has async/await)
|
|
if (!originalContent.includes('async ') && !originalContent.includes('await ')) {
|
|
console.log(`⏭️ ${filename} - no async/await, skipping`);
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
const result = await esbuild.transform(originalContent, {
|
|
loader: 'js',
|
|
// Match bundled providers and retain native async/await for both apps.
|
|
target: 'es2017',
|
|
format: 'cjs'
|
|
});
|
|
|
|
// Write transpiled content back
|
|
fs.writeFileSync(inputPath, result.code);
|
|
|
|
const stats = fs.statSync(inputPath);
|
|
const sizeKB = (stats.size / 1024).toFixed(1);
|
|
console.log(`✅ ${filename} transpiled (${sizeKB} KB)`);
|
|
return true;
|
|
} catch (err) {
|
|
console.error(`❌ Failed to transpile ${filename}:`, err.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
const args = process.argv.slice(2);
|
|
const shouldMinify = args.includes('--minify');
|
|
|
|
// Handle --transpile flag for single-file providers
|
|
if (args.includes('--transpile')) {
|
|
const files = args.filter(a => a !== '--transpile' && !a.startsWith('-'));
|
|
|
|
if (files.length === 0) {
|
|
// Transpile all .js files in providers/ that aren't from src/
|
|
const srcProviders = fs.existsSync(srcDir)
|
|
? fs.readdirSync(srcDir, { withFileTypes: true })
|
|
.filter(d => d.isDirectory())
|
|
.map(d => d.name + '.js')
|
|
: [];
|
|
|
|
const allProviderFiles = fs.readdirSync(outDir)
|
|
.filter(f => f.endsWith('.js') && !srcProviders.includes(f));
|
|
|
|
console.log(`\n🔄 Transpiling ${allProviderFiles.length} single-file provider(s)...\n`);
|
|
|
|
for (const file of allProviderFiles) {
|
|
await transpileSingleFile(file);
|
|
}
|
|
} else {
|
|
console.log(`\n🔄 Transpiling ${files.length} file(s)...\n`);
|
|
for (const file of files) {
|
|
const filename = file.endsWith('.js') ? file : file + '.js';
|
|
await transpileSingleFile(filename);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
const providers = getProvidersToBuild();
|
|
|
|
if (providers.length === 0) {
|
|
console.log('No providers found in src/ directory.');
|
|
console.log('Create a provider: mkdir -p src/myprovider && touch src/myprovider/index.js');
|
|
return;
|
|
}
|
|
|
|
const minifyLabel = shouldMinify ? ' (minified)' : '';
|
|
console.log(`\n📦 Building ${providers.length} provider(s)${minifyLabel}...\n`);
|
|
|
|
// Ensure output directory exists
|
|
if (!fs.existsSync(outDir)) {
|
|
fs.mkdirSync(outDir, { recursive: true });
|
|
}
|
|
|
|
let success = 0;
|
|
let failed = 0;
|
|
|
|
for (const provider of providers) {
|
|
const result = await buildProvider(provider, { minify: shouldMinify });
|
|
if (result) success++;
|
|
else failed++;
|
|
}
|
|
|
|
console.log(`\n✨ Done! ${success} built, ${failed} skipped/failed\n`);
|
|
}
|
|
|
|
main().catch(err => {
|
|
console.error('Build failed:', err);
|
|
process.exit(1);
|
|
});
|