/* Aerostat Beam Coder - Node.js native bindings to FFmpeg. Copyright (C) 2019 Streampunk Media Ltd. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . https://www.streampunk.media/ mailto:[email protected] 14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K. */ const os = require('os'); const fs = require('fs'); const util = require('util'); const https = require('https'); const cp = require('child_process'); const [ mkdir, access, rename, execFile, exec ] = // eslint-disable-line [ fs.mkdir, fs.access, fs.rename, cp.execFile, cp.exec ].map(util.promisify); async function get(ws, url, name) { let received = 0; let totalLength = 0; return new Promise((comp, err) => { https.get(url, res => { if (res.statusCode === 301 || res.statusCode === 302) { err({ name: 'RedirectError', message: res.headers.location }); } else { res.pipe(ws); if (totalLength == 0) { totalLength = +res.headers['content-length']; } res.on('end', () => { process.stdout.write(`Downloaded 100% of '${name}'. Total length ${received} bytes.\n`); comp(); }); res.on('error', err); res.on('data', x => { received += x.length; process.stdout.write(`Downloaded ${received * 100/ totalLength | 0 }% of '${name}'.\r`); }); } }).on('error', err); }); } async function getHTML(url, name) { let received = 0; let totalLength = 0; return new Promise((resolve, reject) => { https.get(url, res => { const chunks = []; if (totalLength == 0) { totalLength = +res.headers['content-length']; } res.on('end', () => { process.stdout.write(`Downloaded 100% of '${name}'. Total length ${received} bytes.\n`); resolve(Buffer.concat(chunks)); }); res.on('error', reject); res.on('data', (chunk) => { chunks.push(chunk); received += chunk.length; process.stdout.write(`Downloaded ${received * 100/ totalLength | 0 }% of '${name}'.\r`); }); }).on('error', reject); }); } async function inflate(rs, folder, name) { const unzip = require('unzipper'); const directory = await unzip.Open.file(`${folder}/${name}.zip`); const directoryName = directory.files[0].path; return new Promise((comp, err) => { console.log(`Unzipping '${folder}/${name}.zip'.`); rs.pipe(unzip.Extract({ path: folder }).on('close', () => { fs.rename(`./${folder}/${directoryName}`, `./${folder}/${name}`, () => { console.log(`Unzipping of '${folder}/${name}.zip' completed.`); comp(); }); })); rs.on('error', err); }); } async function win32() { console.log('Checking/Installing FFmpeg dependencies for Beam Coder on Windows.'); await mkdir('ffmpeg').catch(e => { if (e.code === 'EEXIST') return; else throw e; }); const ffmpegFilename = 'ffmpeg-5.x-win64-shared'; await access(`ffmpeg/${ffmpegFilename}`, fs.constants.R_OK).catch(async () => { const html = await getHTML('https://github.com/BtbN/FFmpeg-Builds/wiki/Latest', 'latest autobuilds'); const htmlStr = html.toString('utf-8'); const autoPos = htmlStr.indexOf('

', autoPos); const autoStr = htmlStr.substring(autoPos, endPos); const sharedEndPos = autoStr.lastIndexOf('">win64-gpl-shared-5.'); if (sharedEndPos === -1) throw new Error('Failed to find latest v4.x autobuild from "https://github.com/BtbN/FFmpeg-Builds/wiki/Latest"'); const startStr = '