mirror of
https://github.com/Zaarrg/stremio-community-v5.git
synced 2026-01-11 20:10:31 +00:00
229 lines
8.5 KiB
JavaScript
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);
|
|
}
|
|
})();
|