import * as fs from 'node:fs/promises' import * as os from 'node:os' import * as path from 'node:path' import { env } from 'node:process' import { extractTo } from 'archive-wasm/src/fs.mjs' import { FFMPEG_SUFFFIX, FFMPEG_WORKFLOW, getConst, getSuffix, LIBHEIF_SUFFIX, LIBHEIF_WORKFLOW, PDFIUM_SUFFIX, PROTOC_SUFFIX, } from './consts.mjs' import { getGh, getGhArtifactContent, getGhReleasesAssets, getGhWorkflowRunArtifacts, } from './github.mjs' import { which } from './which.mjs' const noop = () => {} const __debug = env.NODE_ENV === 'debug' const __osType = os.type() // Github repos const PDFIUM_REPO = 'bblanchon/pdfium-binaries' const PROTOBUF_REPO = 'protocolbuffers/protobuf' const SPACEDRIVE_REPO = 'spacedriveapp/spacedrive' /** * Download and extract protobuff compiler binary * @param {string[]} machineId * @param {string} nativeDeps */ export async function downloadProtc(machineId, nativeDeps) { if (await which('protoc')) return console.log('Downloading protoc...') const protocSuffix = getSuffix(PROTOC_SUFFIX, machineId) if (protocSuffix == null) throw new Error('NO_PROTOC') let found = false for await (const release of getGhReleasesAssets(PROTOBUF_REPO)) { if (!protocSuffix.test(release.name)) continue try { await extractTo(await getGh(release.downloadUrl), nativeDeps, { chmod: 0o600, overwrite: true, }) found = true break } catch (error) { console.warn('Failed to download protoc, re-trying...') if (__debug) console.error(error) } } if (!found) throw new Error('NO_PROTOC') // cleanup await fs.unlink(path.join(nativeDeps, 'readme.txt')).catch(__debug ? console.error : noop) } /** * Download and extract pdfium library for generating PDFs thumbnails * @param {string[]} machineId * @param {string} nativeDeps */ export async function downloadPDFium(machineId, nativeDeps) { console.log('Downloading pdfium...') const pdfiumSuffix = getSuffix(PDFIUM_SUFFIX, machineId) if (pdfiumSuffix == null) throw new Error('NO_PDFIUM') let found = false for await (const release of getGhReleasesAssets(PDFIUM_REPO)) { if (!pdfiumSuffix.test(release.name)) continue try { await extractTo(await getGh(release.downloadUrl), nativeDeps, { chmod: 0o600, overwrite: true, }) found = true break } catch (error) { console.warn('Failed to download pdfium, re-trying...') if (__debug) console.error(error) } } if (!found) throw new Error('NO_PDFIUM') // cleanup const cleanup = [ fs.rename(path.join(nativeDeps, 'LICENSE'), path.join(nativeDeps, 'LICENSE.pdfium')), ...['args.gn', 'PDFiumConfig.cmake', 'VERSION'].map(file => fs.unlink(path.join(nativeDeps, file)).catch(__debug ? console.error : noop) ), ] switch (__osType) { case 'Linux': cleanup.push(fs.chmod(path.join(nativeDeps, 'lib', 'libpdfium.so'), 0o750)) break case 'Darwin': cleanup.push(fs.chmod(path.join(nativeDeps, 'lib', 'libpdfium.dylib'), 0o750)) break } await Promise.all(cleanup) } /** * Download and extract ffmpeg libs for video thumbnails * @param {string[]} machineId * @param {string} nativeDeps * @param {string[]} branches */ export async function downloadFFMpeg(machineId, nativeDeps, branches) { const workflow = getConst(FFMPEG_WORKFLOW, machineId) if (workflow == null) { console.log('Checking FFMPeg...') if (await which('ffmpeg')) { // TODO: check ffmpeg version match what we need return } else { throw new Error('NO_FFMPEG') } } console.log('Downloading FFMPeg...') const ffmpegSuffix = getSuffix(FFMPEG_SUFFFIX, machineId) if (ffmpegSuffix == null) throw new Error('NO_FFMPEG') let found = false for await (const artifact of getGhWorkflowRunArtifacts(SPACEDRIVE_REPO, workflow, branches)) { if (!ffmpegSuffix.test(artifact.name)) continue try { const data = await getGhArtifactContent(SPACEDRIVE_REPO, artifact.id) await extractTo(data, nativeDeps, { chmod: 0o600, recursive: true, overwrite: true, }) found = true break } catch (error) { console.warn('Failed to download FFMpeg, re-trying...') if (__debug) console.error(error) } } if (!found) throw new Error('NO_FFMPEG') } /** * Download and extract libheif libs for heif thumbnails * @param {string[]} machineId * @param {string} nativeDeps * @param {string[]} branches */ export async function downloadLibHeif(machineId, nativeDeps, branches) { const workflow = getConst(LIBHEIF_WORKFLOW, machineId) if (workflow == null) return console.log('Downloading LibHeif...') const libHeifSuffix = getSuffix(LIBHEIF_SUFFIX, machineId) if (libHeifSuffix == null) throw new Error('NO_LIBHEIF') let found = false for await (const artifact of getGhWorkflowRunArtifacts(SPACEDRIVE_REPO, workflow, branches)) { if (!libHeifSuffix.test(artifact.name)) continue try { const data = await getGhArtifactContent(SPACEDRIVE_REPO, artifact.id) await extractTo(data, nativeDeps, { chmod: 0o600, recursive: true, overwrite: true, }) found = true break } catch (error) { console.warn('Failed to download LibHeif, re-trying...') if (__debug) console.error(error) } } if (!found) throw new Error('NO_LIBHEIF') }