import assert from 'node:assert/strict' import fs from 'node:fs' import path from 'node:path' import process from 'node:process' import { fileURLToPath } from 'node:url' import vm from 'node:vm' import { build, transform } from 'esbuild' import { verifyAmbilightContract } from '../../refactor/scripts/ambilight-contract.mjs' import { readMember } from '../../refactor/scripts/releases.mjs' import { verifyInstalledArtifacts } from '../../scripts/installed-artifacts.mjs' import { getEntryFile } from '../../scripts/projects.js' export async function ambilightCandidate() { const root = fileURLToPath(new URL('../../', import.meta.url)) if (process.env.ARTPLAYER_BROWSER_ARTIFACTS) { assert.notEqual(process.env.ARTPLAYER_AMBILIGHT_BASELINE, '1', 'Installed candidate cannot use the frozen workspace') const { inputs } = verifyInstalledArtifacts(root, process.env.ARTPLAYER_BROWSER_ARTIFACTS, ['artplayer', 'artplayer-plugin-chapter', 'artplayer-plugin-ambilight']) const input = inputs.find(item => item.name === 'artplayer-plugin-ambilight') return { name: 'candidate-installed', source: fs.readFileSync(input.file, 'utf8'), format: 'artifact', provenance: input } } if (process.env.ARTPLAYER_AMBILIGHT_BASELINE === '1') return (await ambilightHistorical()).find(item => item.name === 'frozen-workspace') const result = await build({ entryPoints: [getEntryFile(path.join(root, 'packages/artplayer-plugin-ambilight'))], bundle: true, write: false, platform: 'browser', format: 'cjs', target: 'es2020' }) return { name: 'candidate-source', source: result.outputFiles[0].text, format: 'artifact' } } export async function ambilightHistorical() { const contract = await verifyAmbilightContract() return [ ...[contract.baseline.release, ...contract.baseline.previous].map(release => ({ name: `published-${release.version}`, source: readMember(contract.archives.get(release.version), `package/${release.manifest.main.replace(/^\.\//, '')}`).toString(), format: 'artifact' })), { name: 'frozen-workspace', source: contract.sources.get('packages/artplayer-plugin-ambilight/src/index.js'), format: 'source' }, ] } export async function ambilightEnvironment(implementation, settings = {}) { let time = 0 let nextFrame = settings.firstFrame ?? 1 const frames = new Map() const draws = [] const cancelled = [] const nodes = [] const listeners = new Map() const state = { drawError: null, readError: null, draws, frames, cancelled, nodes, time: value => time = value } const context = settings.noContext ? null : { drawImage(...args) { draws.push(args) settings.onDraw?.() if (state.drawError) throw state.drawError }, getImageData() { if (state.readError) throw state.readError return { data: [draws.length, 20, 30, 255] } }, } function node(tag) { let markup = '' const value = { tag, children: [], parentNode: null, style: {}, className: '', width: 300, height: 150, get innerHTML() { return markup }, set innerHTML(value) { markup = value this.children = Array.from({ length: (value.match(/