stremio-community-v5/build/build_anime4k.js
Zarg 16d1bce51c WebView2 letss gooo
- Big Massive init
2025-01-15 10:23:31 +01:00

229 lines
8.5 KiB
JavaScript

#!/usr/bin/env node
/**
* build_anime4k.js
*
* This script performs the following: (Needed for deploy_windows to include Anime4k in installer)
* 1. Determines the latest Anime4K version from bloc97/Anime4K releases.
* 2. Downloads the corresponding GLSL_Windows_High-end.zip from Tama47/Anime4K.
* 3. Auto-detects 7z.exe on the system.
* 4. Saves the downloaded zip as anime4k-High-end.zip in utils/mpv.
* 5. Extracts the zip into the anime4k folder.
* 6. Cleans up temporary files.
*
* Usage:
* node build_anime4k.js
*/
const fs = require('fs');
const path = require('path');
const https = require('https');
const { execSync } = require('child_process');
const os = require('os');
// Configuration
const BLOC97_API_URL = 'https://api.github.com/repos/bloc97/Anime4K/releases/latest';
const TEMP_DIR = path.join(os.tmpdir(), 'anime4k_build_temp');
const OUTPUT_DIR = path.resolve(__dirname, '..', 'utils', 'mpv', 'anime4k');
const OUTPUT_ZIP_NAME = 'anime4k-High-end.zip';
const EXTRACTION_DIR = path.join(OUTPUT_DIR, 'portable_config');
// Common 7z.exe installation paths on Windows
const COMMON_7Z_PATHS = [
path.join(process.env.PROGRAMFILES || 'C:\\Program Files', '7-Zip', '7z.exe'),
path.join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', '7-Zip', '7z.exe'),
path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), '7-Zip', '7z.exe')
];
// Maximum number of redirects to follow
const MAX_REDIRECTS = 5;
// Helper Functions
function httpsGet(url, headers = {}, redirectCount = 0) {
return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) return reject(new Error('Too many redirects'));
const options = {
headers: {
'User-Agent': 'Node.js Script',
...headers
}
};
https.get(url, options, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
return resolve(httpsGet(res.headers.location, headers, redirectCount + 1));
}
if (res.statusCode !== 200) {
res.resume();
return reject(new Error(`Request Failed. Status Code: ${res.statusCode}`));
}
let data = '';
res.setEncoding('utf8');
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', e => reject(e));
});
}
function downloadFile(url, dest, headers = {}, redirectCount = 0) {
return new Promise((resolve, reject) => {
if (redirectCount > MAX_REDIRECTS) return reject(new Error('Too many redirects'));
const options = {
headers: {
'User-Agent': 'Node.js Script',
...headers
}
};
https.get(url, options, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
console.log(`Redirecting to ${res.headers.location}`);
return resolve(downloadFile(res.headers.location, dest, headers, redirectCount + 1));
}
if (res.statusCode !== 200) {
res.resume();
return reject(new Error(`Failed to get '${url}' (${res.statusCode})`));
}
const totalSize = parseInt(res.headers['content-length'], 10);
let downloadedSize = 0;
const file = fs.createWriteStream(dest);
res.pipe(file);
res.on('data', chunk => {
downloadedSize += chunk.length;
if (totalSize) {
const percent = ((downloadedSize / totalSize) * 100).toFixed(2);
process.stdout.write(`Downloading... ${percent}%\r`);
} else {
process.stdout.write(`Downloading... ${downloadedSize} bytes\r`);
}
});
file.on('finish', () => {
file.close(() => {
process.stdout.write('\n');
resolve();
});
});
file.on('error', err => {
fs.unlink(dest, () => reject(err));
});
}).on('error', err => reject(err));
});
}
function execCommand(command, cwd = process.cwd()) {
try {
execSync(command, { stdio: 'inherit', cwd });
} catch (error) {
throw new Error(`Command failed: ${command}\n${error.message}`);
}
}
function commandExists(command) {
try {
execSync(`where ${command}`, { stdio: 'ignore' });
return true;
} catch {
return false;
}
}
function find7zExecutable() {
if (commandExists('7z')) {
console.log('Found 7z.exe in PATH.');
return '7z';
}
for (const potentialPath of COMMON_7Z_PATHS) {
if (fs.existsSync(potentialPath)) {
console.log(`Found 7z.exe at: ${potentialPath}`);
return `"${potentialPath}"`;
}
}
throw new Error('7z.exe not found. Please install 7-Zip.');
}
// Main Build Function
(async function buildAnime4K() {
try {
console.log('=== Build Anime4K Script Started ===');
const sevenZipPath = find7zExecutable();
if (fs.existsSync(TEMP_DIR)) fs.rmSync(TEMP_DIR, { recursive: true, force: true });
fs.mkdirSync(TEMP_DIR, { recursive: true });
console.log(`Created temporary directory at ${TEMP_DIR}`);
console.log('Fetching latest Anime4K version information...');
const releaseData = await httpsGet(BLOC97_API_URL);
const releaseJson = JSON.parse(releaseData);
const version = releaseJson.tag_name;
console.log(`Latest version: ${version}`);
const downloadUrl = `https://github.com/Tama47/Anime4K/releases/download/${version}/GLSL_Windows_High-end.zip`;
const downloadedFilePath = path.join(TEMP_DIR, 'GLSL_Windows_High-end.zip');
console.log(`Downloading GLSL_Windows_High-end.zip for version ${version}...`);
await downloadFile(downloadUrl, downloadedFilePath);
console.log(`Downloaded to ${downloadedFilePath}`);
// Ensure output directory exists
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
const outputZipPath = path.join(OUTPUT_DIR, OUTPUT_ZIP_NAME);
fs.copyFileSync(downloadedFilePath, outputZipPath);
console.log(`Saved zip as ${outputZipPath}`);
// Extract the zip to the anime4k folder
fs.mkdirSync(EXTRACTION_DIR, { recursive: true });
console.log(`Extracting ${outputZipPath} to ${EXTRACTION_DIR}...`);
execCommand(`${sevenZipPath} x "${outputZipPath}" -o"${EXTRACTION_DIR}" -y`);
console.log('Extraction complete.');
// Path to the mpv.conf file inside the extraction directory
const mpvConfPath = path.join(EXTRACTION_DIR, 'mpv.conf');
// Check if mpv.conf exists before attempting to modify it
if (fs.existsSync(mpvConfPath)) {
console.log(`Modifying ${mpvConfPath} to comment out glsl-shaders lines...`);
// Read the existing content of mpv.conf
let confData = fs.readFileSync(mpvConfPath, 'utf8');
// Split the file into lines
const lines = confData.split(/\r?\n/);
// Map over lines to comment out ones that start with 'glsl-shaders='
const modifiedLines = lines.map(line => {
// Trim whitespace at beginning of line for accurate check
const trimmedLine = line.trim();
if (trimmedLine.startsWith('glsl-shaders=')) {
// If not already commented out, add a comment marker
if (!trimmedLine.startsWith('#')) {
return `# ${line}`;
}
}
return line;
});
// Join the modified lines back together
confData = modifiedLines.join(os.EOL);
// Write the changes back to mpv.conf
fs.writeFileSync(mpvConfPath, confData, 'utf8');
console.log('Modification complete.');
} else {
console.log(`Warning: ${mpvConfPath} not found. Skipping modification.`);
}
// Cleanup
console.log(`Cleaning up temporary files at ${TEMP_DIR}...`);
fs.rmSync(TEMP_DIR, { recursive: true, force: true });
console.log('Cleanup complete.');
console.log('=== Build Anime4K Script Completed Successfully ===');
process.exit(1);
} catch (error) {
console.error('Error during build:', error.message);
process.exit(1);
}
})();