Files
oxmcandClaude Sonnet 5 7e995693b0 Upgrade to video.js 8, add real ads/EME, fix v8-incompatible plugins
- Bump video.js 7 -> 8.24.0 and all plugins to v8-compatible latest
  (contrib-ads, contrib-eme, errors, youtube, vjsdownload, playlist-ui,
  http-streaming, hls-quality-selector, hotkeys); drop unused/dead deps
  (videojs-flash, videojs-ads-markers, videojs-ssa's old dead entry).
- Add real ad support in src/module/ads/ad.js: Google IMA (videojs-ima)
  and a hand-rolled VAST-parsing 'ownAds' provider for a self-hosted ad
  server, replacing the old fake JSON-inventory exampleAds scaffold.
- Make videojs-contrib-eme genuinely optional: built as its own lazy-loaded
  chunk (bundle/vjs-player-bundle-eme.min.js), only fetched when a video
  actually requests DRM (data-eme="true").
- Add a singleInstance player mode: one reused Video.js player across many
  <video> elements (poster-thumbnail triggers swap src into it) vs the
  default one-player-per-element behavior.
- Rewrite src/module/share, src/module/overlay, src/module/ssa from their
  real ES6 sources (or manually de-transpiled dist, for ssa) because
  video.js 8's Component/Plugin are now native ES6 classes and the
  published dist builds invoke them via the old Babel `Class.call(this)`
  down-level pattern, which throws under v8. Verified all three in a real
  video.js 8 runtime via headless Chrome.
- Fix a watermark.js bug where a module-scoped DOM node was shared across
  every player on a page, so only the last-initialized one kept its mark.
- Split player.js out of the plugin bundle into its own file
  (bundle/vjs-player.min.js), loaded as a separate final script by
  player-init.js, fixing a double-declaration crash when a page loaded
  both the bundle and a separately-hosted player.js.
- Add bundle-files.js as the single source of truth for both bundlers;
  bundle-dev.js now produces an unminified build for local debugging.
  bundle-prod.js strips license comments from minified output and writes
  them to bundle/LICENSES.txt instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 02:49:35 -07:00

97 lines
4.0 KiB
JavaScript
Executable File

const minify = require('@node-minify/core');
const csso = require('@node-minify/csso');
const terser = require('@node-minify/terser');
const path = require('path');
const fs = require('fs');
const { jsFiles, cssFiles, emeJsFiles, playerJsFile, bundleFileName, playerFileName } = require('./bundle-files');
// Matches /** @license ... */ and /*! ... */ header comments so they can be
// pulled out into LICENSES.txt before the minifiers strip them from the
// shipped bundle.
const LICENSE_COMMENT = /\/\*[!*][\s\S]*?\*\//g;
const collectedLicenses = [];
const collectLicenses = (file, content) => {
const matches = content.match(LICENSE_COMMENT);
if (matches) {
matches.forEach((comment) => collectedLicenses.push(`# ${file}\n${comment}`));
}
};
// Function to concatenate files and minify the combined file
const concatenateAndMinify = (files, minifier, outputFile, minifierOptions, banner) => {
const fileType = path.extname(files[0]).slice(1); // Get the file type dynamically (js or css)
const combinedFilePath = path.join(__dirname, 'bundle', `combined-${outputFile}.${fileType}`);
// Concatenate content of each file and write to combined file
let combinedContent = '';
files.forEach(file => {
const content = fs.readFileSync(path.join(__dirname, file), 'utf-8');
collectLicenses(file, content);
combinedContent += content + '\n'; // Add file content with newline
});
// Write the concatenated content to the combined file
fs.writeFileSync(combinedFilePath, combinedContent, 'utf-8');
console.log(`Combined ${fileType} file created: ${combinedFilePath}`);
// Now minify the combined file
minify({
compressor: minifier,
input: combinedFilePath,
output: path.join(__dirname, 'bundle', outputFile),
options: minifierOptions,
callback: (err, min) => {
if (err) {
console.error(`Error minifying ${outputFile}:`, err);
return;
}
console.log(`${outputFile} minified successfully!`);
// Optionally delete the combined file after minification
fs.unlinkSync(combinedFilePath);
// csso has no built-in banner/preamble option (unlike terser),
// so prepend it ourselves once minification is done.
if (banner) {
const outputPath = path.join(__dirname, 'bundle', outputFile);
fs.writeFileSync(outputPath, `${banner}\n${fs.readFileSync(outputPath, 'utf-8')}`, 'utf-8');
}
}
});
};
// Ensure the bundle directory exists
const bundleDir = path.join(__dirname, 'bundle');
if (!fs.existsSync(bundleDir)) {
fs.mkdirSync(bundleDir);
}
// Strip @license/@preserve comments from the shipped output - see LICENSES.txt
// (written below) for the full text of every vendored library's notice. A
// one-line banner replaces them so that pointer survives in the minified file.
const licenseBanner = '/* Licenses for the vendored libraries in this file: see LICENSES.txt */';
const terserOptions = { format: { comments: false, preamble: licenseBanner } };
const cssoOptions = { comments: false };
// Concatenate and minify JS files into one file
concatenateAndMinify(jsFiles, terser, `${bundleFileName}.min.js`, terserOptions);
// Concatenate and minify CSS files into one file
concatenateAndMinify(cssFiles, csso, `${bundleFileName}.min.css`, cssoOptions, licenseBanner);
// Concatenate and minify the optional, lazy-loaded EME chunk
concatenateAndMinify(emeJsFiles, terser, `${bundleFileName}-eme.min.js`, terserOptions);
// Minify player.js on its own - it's loaded as a separate, final script by
// player-init.js, after the plugin bundle above.
concatenateAndMinify(playerJsFile, terser, `${playerFileName}.min.js`, terserOptions);
// Write out every vendored license notice that was stripped from the
// minified output above, so they're still available (just not inline).
fs.writeFileSync(
path.join(__dirname, 'bundle', 'LICENSES.txt'),
collectedLicenses.join('\n\n'),
'utf-8'
);
console.log('LICENSES.txt written');