Musique/node_modules/ffmpeg-static/install.js
2021-12-04 20:00:33 +01:00

180 lines
5.6 KiB
JavaScript

'use strict'
var fs = require("fs");
var os = require("os");
const {encode: encodeQuery} = require('querystring')
const {strictEqual} = require('assert')
const envPaths = require('env-paths')
const FileCache = require('@derhuerst/http-basic/lib/FileCache').default
const {extname} = require('path')
var ProgressBar = require("progress");
var request = require('@derhuerst/http-basic')
const {createGunzip} = require('zlib')
const {pipeline} = require('stream')
var ffmpegPath = require(".");
var pkg = require("./package");
const exitOnError = (err) => {
console.error(err)
process.exit(1)
}
const exitOnErrorOrWarnWith = (msg) => (err) => {
if (err.statusCode === 404) console.warn(msg)
else exitOnError(err)
}
if (!ffmpegPath) {
exitOnError('ffmpeg-static install failed: No binary found for architecture')
}
try {
if (fs.statSync(ffmpegPath).isFile()) {
console.info('ffmpeg is installed already.')
process.exit(0)
}
} catch (err) {
if (err && err.code !== 'ENOENT') exitOnError(err)
}
let agent = false
// https://github.com/request/request/blob/a9557c9e7de2c57d92d9bab68a416a87d255cd3d/lib/getProxyFromURI.js#L66-L71
const proxyUrl = (
process.env.HTTPS_PROXY ||
process.env.https_proxy ||
process.env.HTTP_PROXY ||
process.env.http_proxy
)
if (proxyUrl) {
const HttpsProxyAgent = require('https-proxy-agent')
const {hostname, port, protocol} = new URL(proxyUrl)
agent = new HttpsProxyAgent({hostname, port, protocol})
}
// https://advancedweb.hu/how-s3-signed-urls-work/
const normalizeS3Url = (url) => {
url = new URL(url)
if (url.hostname.slice(-17) !== '.s3.amazonaws.com') return url.href
const query = Array.from(url.searchParams.entries())
.filter(([key]) => key.slice(0, 6).toLowerCase() !== 'x-amz-')
.reduce((query, [key, val]) => ({...query, [key]: val}), {})
url.search = encodeQuery(query)
return url.href
}
strictEqual(
normalizeS3Url('https://example.org/foo?bar'),
'https://example.org/foo?bar'
)
strictEqual(
normalizeS3Url('https://github-production-release-asset-2e65be.s3.amazonaws.com/29458513/26341680-4231-11ea-8e36-ae454621d74a?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20200405%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200405T225358Z&X-Amz-Expires=300&X-Amz-Signature=d6415097af04cf62ea9b69d3c1a421278e96bcb069afa48cf021ec3b6941bae4&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B%20filename%3Ddarwin-x64&response-content-type=application%2Foctet-stream'),
'https://github-production-release-asset-2e65be.s3.amazonaws.com/29458513/26341680-4231-11ea-8e36-ae454621d74a?actor_id=0&response-content-disposition=attachment%3B%20filename%3Ddarwin-x64&response-content-type=application%2Foctet-stream'
)
const cache = new FileCache(envPaths(pkg.name).cache)
cache.getCacheKey = (url) => {
return FileCache.prototype.getCacheKey(normalizeS3Url(url))
}
const isGzUrl = (url) => {
const path = new URL(url).pathname.split('/')
const filename = path[path.length - 1]
return filename && extname(filename) === '.gz'
}
const noop = () => {}
function downloadFile(url, destinationPath, progressCallback = noop) {
let fulfill, reject;
let totalBytes = 0;
const promise = new Promise((x, y) => {
fulfill = x;
reject = y;
});
request('GET', url, {
agent,
followRedirects: true,
maxRedirects: 3,
gzip: true,
cache,
timeout: 30 * 1000, // 30s
retry: true,
}, (err, response) => {
if (err || response.statusCode !== 200) {
err = err || new Error('Download failed.')
if (response) {
err.url = response.url
err.statusCode = response.statusCode
}
reject(err)
return;
}
const file = fs.createWriteStream(destinationPath);
const streams = isGzUrl(url)
? [response.body, createGunzip(), file]
: [response.body, file]
pipeline(
...streams,
(err) => {
if (err) {
err.url = response.url
err.statusCode = response.statusCode
reject(err)
} else fulfill()
}
)
if (!response.fromCache && progressCallback) {
const cLength = response.headers["content-length"]
totalBytes = cLength ? parseInt(cLength, 10) : null
response.body.on('data', (chunk) => {
progressCallback(chunk.length, totalBytes);
});
}
});
return promise;
}
let progressBar = null;
function onProgress(deltaBytes, totalBytes) {
if (totalBytes === null) return;
if (!progressBar) {
progressBar = new ProgressBar(`Downloading ffmpeg ${releaseName} [:bar] :percent :etas `, {
complete: "|",
incomplete: " ",
width: 20,
total: totalBytes
});
}
progressBar.tick(deltaBytes);
}
const release = (
process.env.FFMPEG_BINARY_RELEASE ||
pkg['ffmpeg-static']['binary-release-tag']
)
const releaseName = (
pkg['ffmpeg-static']['binary-release-name'] ||
release
)
const arch = process.env.npm_config_arch || os.arch()
const platform = process.env.npm_config_platform || os.platform()
const baseUrl = `https://github.com/eugeneware/ffmpeg-static/releases/download/${release}`
const downloadUrl = `${baseUrl}/${platform}-${arch}.gz`
const readmeUrl = `${baseUrl}/${platform}-${arch}.README`
const licenseUrl = `${baseUrl}/${platform}-${arch}.LICENSE`
downloadFile(downloadUrl, ffmpegPath, onProgress)
.then(() => {
fs.chmodSync(ffmpegPath, 0o755) // make executable
})
.catch(exitOnError)
.then(() => downloadFile(readmeUrl, `${ffmpegPath}.README`))
.catch(exitOnErrorOrWarnWith('Failed to download the ffmpeg README.'))
.then(() => downloadFile(licenseUrl, `${ffmpegPath}.LICENSE`))
.catch(exitOnErrorOrWarnWith('Failed to download the ffmpeg LICENSE.'))