@karsten_zhou/vite-plugin-hls 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -165,20 +165,25 @@ function hlsMuxerOptions(outputDirectory, options) {
165
165
  };
166
166
  if (options.segmentType === "fmp4") {
167
167
  hls.hls_segment_type = "fmp4";
168
- hls.hls_fmp4_init_filename = (0, import_node_path2.join)(outputDirectory, "init.mp4");
168
+ hls.hls_fmp4_init_filename = "init.mp4";
169
169
  }
170
170
  return hls;
171
171
  }
172
- async function relativizePlaylist(playlist, outputDirectory) {
173
- let text;
172
+ async function ensureInitSegment(outputDirectory) {
173
+ const target = (0, import_node_path2.join)(outputDirectory, "init.mp4");
174
174
  try {
175
- text = await (0, import_promises.readFile)(playlist, "utf8");
175
+ await (0, import_promises.access)(target);
176
+ return;
177
+ } catch {
178
+ }
179
+ const leaked = (0, import_node_path2.join)(process.cwd(), "init.mp4");
180
+ try {
181
+ await (0, import_promises.access)(leaked);
176
182
  } catch {
177
183
  return;
178
184
  }
179
- const prefix = outputDirectory.replace(/[\\/]+$/, "");
180
- text = text.split(prefix + "\\").join("").split(prefix + "/").join("");
181
- await (0, import_promises.writeFile)(playlist, text, "utf8");
185
+ await (0, import_promises.copyFile)(leaked, target);
186
+ await (0, import_promises.rm)(leaked, { force: true });
182
187
  }
183
188
  async function remuxToHls(source, playlist, hls) {
184
189
  var _stack = [];
@@ -209,7 +214,6 @@ async function remuxToHls(source, playlist, hls) {
209
214
  packet.free();
210
215
  }
211
216
  await output.close();
212
- await relativizePlaylist(playlist, (0, import_node_path2.dirname)(playlist));
213
217
  } catch (_) {
214
218
  var _error = _, _hasError = true;
215
219
  } finally {
@@ -303,7 +307,6 @@ async function transcodeToHls(source, playlist, hls, options, variant) {
303
307
  }
304
308
  await Promise.all(tasks);
305
309
  await output.close();
306
- await relativizePlaylist(playlist, (0, import_node_path2.dirname)(playlist));
307
310
  } catch (_) {
308
311
  var _error = _, _hasError = true;
309
312
  } finally {
@@ -320,6 +323,9 @@ async function encodeVariant(source, outputDirectory, options, variant = {}) {
320
323
  } else {
321
324
  await transcodeToHls(source, playlist, hls, options, variant);
322
325
  }
326
+ if (options.segmentType === "fmp4") {
327
+ await ensureInitSegment(outputDirectory);
328
+ }
323
329
  }
324
330
  async function createEncodeDirectory() {
325
331
  return (0, import_promises.mkdtemp)((0, import_node_path2.join)((0, import_node_os.tmpdir)(), "vite-plugin-hls-"));
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/options.ts","../src/resolve.ts","../src/hls.ts","../src/encoder.ts","../src/bitrate.ts","../src/cache.ts","../src/fs.ts","../src/playlist.ts","../src/assets.ts","../src/plugin.ts"],"sourcesContent":["import { hlsVideos } from \"./plugin\";\n\nexport { hlsVideos };\nexport default hlsVideos;\n\nexport type { HlsPluginOptions, HlsVariant } from \"./types\";\n","import type { HlsPluginOptions, ResolvedHlsOptions } from \"./types\";\n\nexport function resolveOptions(\n input: HlsPluginOptions = {},\n): ResolvedHlsOptions {\n const common = {\n segmentDuration: input.segmentDuration ?? 4,\n\n segmentType: input.segmentType ?? \"fmp4\",\n\n outputDir: input.outputDir ?? \"assets/hls\",\n\n preset: input.preset ?? \"medium\",\n\n crf: input.crf ?? 23,\n };\n\n if (input.mode === \"adaptive\") {\n if (!input.variants || input.variants.length === 0) {\n throw new Error(\n \"[vite-plugin-hls] Adaptive mode requires at least one variant.\",\n );\n }\n\n return {\n ...common,\n mode: \"adaptive\",\n variants: input.variants,\n };\n }\n\n return {\n ...common,\n mode: \"single\",\n };\n}\n","import { extname } from \"node:path\";\n\nimport type { PluginContext } from \"rolldown\";\n\nconst VIDEO_EXTENSIONS = new Set([\n \".mp4\",\n \".mov\",\n \".m4v\",\n \".webm\",\n \".mkv\",\n \".avi\",\n]);\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function isVideoSource(source: string): boolean {\n const pathname = source.split(\"?\")[0] ?? source;\n\n return VIDEO_EXTENSIONS.has(extname(pathname).toLowerCase());\n}\n\nexport function virtualIdForSource(source: string): string {\n return `${VIRTUAL_PREFIX}${encodeURIComponent(source)}`;\n}\n\nexport function sourceFromVirtualId(id: string): string {\n return decodeURIComponent(id.slice(VIRTUAL_PREFIX.length));\n}\n\nexport async function resolveVideoSource(\n source: string,\n importer: string,\n context: PluginContext,\n): Promise<string | undefined> {\n if (!isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await context.resolve(source, importer, {\n skipSelf: true,\n });\n\n if (!resolved || resolved.external) {\n return undefined;\n }\n\n /*\n * Queries such as ?url are irrelevant here.\n * FFmpeg needs the physical file.\n */\n return resolved.id.split(\"?\", 1)[0];\n}\n","import { basename, extname, join } from \"node:path\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport {\n encodeVariant,\n createEncodeDirectory,\n removeEncodeDirectory,\n} from \"./encoder\";\nimport { readCache, getCacheKey, writeCache } from \"./cache\";\nimport { collectFiles } from \"./fs\";\nimport { slugify, createMasterPlaylist } from \"./playlist\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport async function generateHls(\n source: string,\n cacheRoot: string,\n options: ResolvedHlsOptions,\n): Promise<CachedHls> {\n const key = await getCacheKey(source, options);\n\n const cached = await readCache(cacheRoot, key);\n\n if (cached) {\n console.log(`[vite-plugin-hls] cache hit ${source}`);\n\n return cached;\n }\n\n console.log(`[vite-plugin-hls] encoding ${source}`);\n\n const temporaryDirectory = await createEncodeDirectory();\n\n try {\n const videoName = slugify(basename(source, extname(source)));\n\n const directoryName = `${videoName}-${key.slice(0, 12)}`;\n\n let manifest: string;\n\n if (options.mode === \"single\") {\n await encodeVariant(source, temporaryDirectory, options);\n\n manifest = \"index.m3u8\";\n } else {\n for (const variant of options.variants) {\n await encodeVariant(\n source,\n join(temporaryDirectory, `${variant.height}p`),\n options,\n {\n height: variant.height,\n bitrate: variant.bitrate,\n },\n );\n }\n\n const master = createMasterPlaylist(options.variants);\n\n await writeFile(join(temporaryDirectory, \"master.m3u8\"), master, \"utf8\");\n\n manifest = \"master.m3u8\";\n }\n\n const result: CachedHls = {\n directoryName,\n manifest,\n files: await collectFiles(temporaryDirectory),\n };\n\n await writeCache(cacheRoot, key, result);\n\n console.log(`[vite-plugin-hls] generated ${directoryName}/${manifest}`);\n\n return result;\n } finally {\n await removeEncodeDirectory(temporaryDirectory);\n }\n}\n","import { mkdir, mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport { Decoder, Demuxer, Encoder, FilterAPI, Muxer } from \"node-av/api\";\nimport { FF_ENCODER_AAC, FF_ENCODER_LIBX264 } from \"node-av/constants\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { ResolvedHlsOptions } from \"./types\";\n\ninterface EncodeVariantOptions {\n height?: number;\n bitrate?: string;\n}\n\nconst PLAYLIST = \"index.m3u8\";\n\ntype HlsOptions = {\n hls_time: string;\n hls_playlist_type: \"vod\";\n hls_segment_filename: string;\n hls_segment_type?: \"mpegts\" | \"fmp4\";\n hls_fmp4_init_filename?: string;\n};\n\nfunction hlsMuxerOptions(\n outputDirectory: string,\n options: ResolvedHlsOptions,\n): HlsOptions {\n const extension = options.segmentType === \"fmp4\" ? \"m4s\" : \"ts\";\n\n const hls: HlsOptions = {\n hls_time: String(options.segmentDuration),\n hls_playlist_type: \"vod\",\n hls_segment_filename: join(outputDirectory, `segment-%05d.${extension}`),\n };\n\n if (options.segmentType === \"fmp4\") {\n hls.hls_segment_type = \"fmp4\";\n\n /*\n * The init filename must be absolute so the file lands next to the\n * playlist. A relative name would be resolved against the process CWD\n * (the project root) and leak there. The playlist is relativized after\n * encoding (see relativizePlaylist).\n */\n hls.hls_fmp4_init_filename = join(outputDirectory, \"init.mp4\");\n }\n\n return hls;\n}\n\n/*\n * ffmpeg references an absolute init path literally in EXT-X-MAP (segment\n * URIs are already emitted as basenames). Rewrite it to a path relative to\n * the output directory so the playlist stays portable.\n */\nasync function relativizePlaylist(\n playlist: string,\n outputDirectory: string,\n): Promise<void> {\n let text: string;\n try {\n text = await readFile(playlist, \"utf8\");\n } catch {\n return; // nothing written (e.g. mocked in tests)\n }\n\n const prefix = outputDirectory.replace(/[\\\\/]+$/, \"\");\n\n text = text\n .split(prefix + \"\\\\\")\n .join(\"\")\n .split(prefix + \"/\")\n .join(\"\");\n\n await writeFile(playlist, text, \"utf8\");\n}\n\n/*\n * SINGLE MODE (remux): copy the streams, only repackage into HLS.\n */\nasync function remuxToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n): Promise<void> {\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const routed = new Map<number, number>();\n\n const video = input.video();\n if (video) {\n routed.set(video.index, output.addStream(video));\n }\n\n const audio = input.audio();\n if (audio) {\n routed.set(audio.index, output.addStream(audio));\n }\n\n for await (const packet of input.packets()) {\n if (packet === null) {\n break;\n }\n\n const index = routed.get(packet.streamIndex);\n\n if (index !== undefined) {\n await output.writePacket(packet, index);\n }\n\n packet.free();\n }\n\n await output.close();\n\n await relativizePlaylist(playlist, dirname(playlist));\n}\n\n/*\n * ADAPTIVE MODE (transcode): re-encode each rendition's video (scaled,\n * libx264) and audio (aac) into its HLS output.\n */\nasync function transcodeToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions,\n): Promise<void> {\n if (options.mode !== \"adaptive\") {\n throw new Error(\n \"[vite-plugin-hls] internal: transcode requires adaptive mode\",\n );\n }\n\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const tasks: Promise<void>[] = [];\n\n const video = input.video();\n if (video) {\n const decoder = await Decoder.create(video);\n\n const scale = variant.height\n ? `scale=-2:${variant.height}:force_original_aspect_ratio=decrease,format=yuv420p`\n : \"format=yuv420p\";\n\n const filter = FilterAPI.create(scale);\n\n const encoderOptions: Record<string, string | number> = {\n preset: options.preset,\n crf: String(options.crf),\n };\n\n const encoderBase: Record<string, unknown> = {\n options: encoderOptions,\n };\n\n if (variant.bitrate !== undefined) {\n const bitrate = bitrateToNumber(variant.bitrate);\n\n encoderOptions.maxrate = bitrate;\n encoderOptions.bufsize = Math.round(bitrate * 1.5);\n encoderBase.bitrate = bitrate;\n }\n\n const encoder = await Encoder.create(\n FF_ENCODER_LIBX264,\n encoderBase as Parameters<typeof Encoder.create>[1],\n );\n\n const index = output.addStream(encoder, { inputStream: video });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(video.index));\n const scaled = filter.frames(frames);\n\n for await (const packet of encoder.packets(scaled)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n filter.close();\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n const audio = input.audio();\n if (audio) {\n const decoder = await Decoder.create(audio);\n\n const encoder = await Encoder.create(FF_ENCODER_AAC, {\n decoder,\n bitrate: 128_000,\n });\n\n const index = output.addStream(encoder, { inputStream: audio });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(audio.index));\n\n for await (const packet of encoder.packets(frames)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n await Promise.all(tasks);\n await output.close();\n\n await relativizePlaylist(playlist, dirname(playlist));\n}\n\nexport async function encodeVariant(\n source: string,\n outputDirectory: string,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions = {},\n): Promise<void> {\n const hls = hlsMuxerOptions(outputDirectory, options);\n const playlist = join(outputDirectory, PLAYLIST);\n\n /*\n * FFmpeg's HLS muxer does not create the output directory.\n * Ensure it exists so segments/playlist can be written.\n */\n await mkdir(outputDirectory, { recursive: true });\n\n if (options.mode === \"single\") {\n await remuxToHls(source, playlist, hls);\n } else {\n await transcodeToHls(source, playlist, hls, options, variant);\n }\n}\n\nexport async function createEncodeDirectory(): Promise<string> {\n return mkdtemp(join(tmpdir(), \"vite-plugin-hls-\"));\n}\n\nexport async function removeEncodeDirectory(directory: string): Promise<void> {\n await rm(directory, {\n recursive: true,\n force: true,\n });\n}\n","/**\n * Converts a human-readable bitrate such as \"1200k\", \"2.5M\" or \"1G\"\n * into the equivalent number of bits per second.\n */\nexport function bitrateToNumber(bitrate: string): number {\n const match = /^([\\d.]+)\\s*([kKmMgG]?)$/.exec(bitrate.trim());\n\n if (!match) {\n throw new Error(`[vite-plugin-hls] Invalid bitrate: ${bitrate}`);\n }\n\n const amount = Number(match[1]);\n\n const suffix = (match[2] ?? \"\").toLowerCase();\n\n const multiplier =\n suffix === \"g\"\n ? 1_000_000_000\n : suffix === \"m\"\n ? 1_000_000\n : suffix === \"k\"\n ? 1_000\n : 1;\n\n return Math.round(amount * multiplier);\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { collectFiles } from \"./fs\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\ninterface CacheManifest {\n directoryName: string;\n manifest: string;\n}\n\n/*\n * Bump whenever the encoder's output layout changes (e.g. a bug fix alters\n * which files are produced). Old cache entries are keyed only on source +\n * options and would otherwise be served forever, so the version is folded\n * into the key to invalidate them.\n */\nconst CACHE_VERSION = \"2\";\n\nexport async function getCacheKey(\n source: string,\n options: ResolvedHlsOptions,\n): Promise<string> {\n const sourceData = await readFile(source);\n\n return createHash(\"sha256\")\n .update(CACHE_VERSION)\n .update(sourceData)\n .update(JSON.stringify(options))\n .digest(\"hex\");\n}\n\nexport async function readCache(\n cacheRoot: string,\n key: string,\n): Promise<CachedHls | undefined> {\n const directory = join(cacheRoot, \"hls\", key);\n\n try {\n await stat(directory);\n } catch {\n return undefined;\n }\n\n const metadata = JSON.parse(\n await readFile(join(directory, \"manifest.json\"), \"utf8\"),\n ) as CacheManifest;\n\n const files = await collectFiles(directory);\n\n // manifest.json is internal bookkeeping, never an emitted asset.\n files.delete(\"manifest.json\");\n\n return {\n directoryName: metadata.directoryName,\n\n manifest: metadata.manifest,\n\n files,\n };\n}\n\nexport async function writeCache(\n cacheRoot: string,\n key: string,\n result: CachedHls,\n): Promise<void> {\n const temporaryDirectory = join(cacheRoot, \"hls\", `${key}.tmp`);\n\n const finalDirectory = join(cacheRoot, \"hls\", key);\n\n await rm(temporaryDirectory, {\n recursive: true,\n force: true,\n });\n\n await mkdir(temporaryDirectory, {\n recursive: true,\n });\n\n for (const [filename, data] of result.files) {\n const destination = join(temporaryDirectory, filename);\n\n await mkdir(resolve(destination, \"..\"), {\n recursive: true,\n });\n\n await writeFile(destination, data);\n }\n\n await writeFile(\n join(temporaryDirectory, \"manifest.json\"),\n JSON.stringify({\n directoryName: result.directoryName,\n manifest: result.manifest,\n } satisfies CacheManifest),\n \"utf8\",\n );\n\n await rm(finalDirectory, {\n recursive: true,\n force: true,\n });\n\n await rename(temporaryDirectory, finalDirectory);\n}\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\n/**\n * Recursively collects every file under `directory` into a map of\n * directory-relative POSIX paths to their buffer contents.\n */\nexport async function collectFiles(\n directory: string,\n): Promise<Map<string, Buffer>> {\n const result = new Map<string, Buffer>();\n\n async function visit(current: string): Promise<void> {\n for (const entry of await readdir(current, { withFileTypes: true })) {\n const filename = join(current, entry.name);\n\n if (entry.isDirectory()) {\n await visit(filename);\n continue;\n }\n\n result.set(\n relative(directory, filename).replaceAll(\"\\\\\", \"/\"),\n await readFile(filename),\n );\n }\n }\n\n await visit(directory);\n\n return result;\n}\n","import { extname } from \"node:path\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { HlsVariant } from \"./types\";\n\n/** Turns a filename into a filesystem-safe slug used for the output folder. */\nexport function slugify(filename: string): string {\n return (\n filename\n .replace(extname(filename), \"\")\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"video\"\n );\n}\n\n/** Builds the adaptive master playlist pointing at each rendition. */\nexport function createMasterPlaylist(variants: readonly HlsVariant[]): string {\n const lines = [\"#EXTM3U\", \"#EXT-X-VERSION:7\"];\n\n for (const variant of variants) {\n // BANDWIDTH is an estimate derived from the configured bitrate.\n const bandwidth = Math.round(bitrateToNumber(variant.bitrate) * 1.15);\n\n lines.push(\n `#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth}`,\n `${variant.height}p/index.m3u8`,\n );\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n","import type { PluginContext } from \"rolldown\";\n\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport function emitHls(\n context: PluginContext,\n result: CachedHls,\n options: ResolvedHlsOptions,\n): void {\n const prefix = `${options.outputDir}/${result.directoryName}`;\n\n const manifestSource = result.files.get(result.manifest);\n\n if (!manifestSource) {\n throw new Error(`[vite-plugin-hls] Missing manifest ${result.manifest}`);\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${result.manifest}`,\n source: manifestSource,\n });\n\n for (const [filename, data] of result.files) {\n if (filename === result.manifest) {\n continue;\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${filename}`,\n source: data,\n });\n }\n}\n\nexport function publicManifestExpression(\n result: CachedHls,\n options: ResolvedHlsOptions,\n base: string,\n): string {\n const path = `${options.outputDir}/${result.directoryName}/${result.manifest}`;\n\n /*\n * Bake Vite's resolved base straight into the module. Vite does not always\n * statically replace import.meta.env.BASE_URL (e.g. in SSR bundles), where\n * import.meta.env is undefined at runtime and crashes. Emitting the base as\n * a plain string is equivalent and works for client and SSR alike.\n *\n * Examples (base -> export):\n *\n * \"/\" -> \"/assets/hls/...\"\n * \"/notes/\" -> \"/notes/assets/hls/...\"\n */\n return JSON.stringify(`${base}${path}`);\n}\n","import type { Plugin, ResolvedConfig } from \"vite\";\n\nimport { resolveOptions } from \"./options\";\nimport {\n isVideoSource,\n resolveVideoSource,\n sourceFromVirtualId,\n virtualIdForSource,\n} from \"./resolve\";\nimport { generateHls } from \"./hls\";\nimport { emitHls, publicManifestExpression } from \"./assets\";\nimport type { HlsPluginOptions } from \"./types\";\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function hlsVideos(input?: HlsPluginOptions): Plugin {\n const options = resolveOptions(input);\n\n let config: ResolvedConfig;\n\n const resolvedSources = new Map<string, string>();\n\n /*\n * This only caches inside the current Vite build.\n *\n * The persistent cache in cache.ts handles the\n * client/server build boundary.\n */\n const generated = new Map<string, Awaited<ReturnType<typeof generateHls>>>();\n\n return {\n name: \"vite-plugin-hls\",\n\n apply: \"build\",\n\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved;\n },\n\n async resolveId(source, importer) {\n if (!importer || !isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await resolveVideoSource(source, importer, this);\n\n if (!resolved) {\n return undefined;\n }\n\n const id = virtualIdForSource(resolved);\n\n resolvedSources.set(id, resolved);\n\n return id;\n },\n\n async load(id, loadOptions) {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return undefined;\n }\n\n const source = resolvedSources.get(id) ?? sourceFromVirtualId(id);\n\n let result = generated.get(source);\n\n if (!result) {\n result = await generateHls(source, config.cacheDir, options);\n\n generated.set(source, result);\n }\n\n /*\n * Important:\n *\n * The SSR build must NOT use Vite's emitted-file\n * URL because that resolves to a file:// URL.\n *\n * We only emit the actual files during the client\n * build. SSR receives the public URL directly.\n */\n if (!loadOptions?.ssr) {\n emitHls(this, result, options);\n }\n\n const manifest = publicManifestExpression(result, options, config.base);\n\n return `\n export default ${manifest};\n `;\n },\n };\n}\n"],"mappings":"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","names":["import_node_path","import_promises","import_node_path","import_promises","import_node_path","import_promises","import_node_path","import_node_path","VIRTUAL_PREFIX"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/options.ts","../src/resolve.ts","../src/hls.ts","../src/encoder.ts","../src/bitrate.ts","../src/cache.ts","../src/fs.ts","../src/playlist.ts","../src/assets.ts","../src/plugin.ts"],"sourcesContent":["import { hlsVideos } from \"./plugin\";\n\nexport { hlsVideos };\nexport default hlsVideos;\n\nexport type { HlsPluginOptions, HlsVariant } from \"./types\";\n","import type { HlsPluginOptions, ResolvedHlsOptions } from \"./types\";\n\nexport function resolveOptions(\n input: HlsPluginOptions = {},\n): ResolvedHlsOptions {\n const common = {\n segmentDuration: input.segmentDuration ?? 4,\n\n segmentType: input.segmentType ?? \"fmp4\",\n\n outputDir: input.outputDir ?? \"assets/hls\",\n\n preset: input.preset ?? \"medium\",\n\n crf: input.crf ?? 23,\n };\n\n if (input.mode === \"adaptive\") {\n if (!input.variants || input.variants.length === 0) {\n throw new Error(\n \"[vite-plugin-hls] Adaptive mode requires at least one variant.\",\n );\n }\n\n return {\n ...common,\n mode: \"adaptive\",\n variants: input.variants,\n };\n }\n\n return {\n ...common,\n mode: \"single\",\n };\n}\n","import { extname } from \"node:path\";\n\nimport type { PluginContext } from \"rolldown\";\n\nconst VIDEO_EXTENSIONS = new Set([\n \".mp4\",\n \".mov\",\n \".m4v\",\n \".webm\",\n \".mkv\",\n \".avi\",\n]);\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function isVideoSource(source: string): boolean {\n const pathname = source.split(\"?\")[0] ?? source;\n\n return VIDEO_EXTENSIONS.has(extname(pathname).toLowerCase());\n}\n\nexport function virtualIdForSource(source: string): string {\n return `${VIRTUAL_PREFIX}${encodeURIComponent(source)}`;\n}\n\nexport function sourceFromVirtualId(id: string): string {\n return decodeURIComponent(id.slice(VIRTUAL_PREFIX.length));\n}\n\nexport async function resolveVideoSource(\n source: string,\n importer: string,\n context: PluginContext,\n): Promise<string | undefined> {\n if (!isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await context.resolve(source, importer, {\n skipSelf: true,\n });\n\n if (!resolved || resolved.external) {\n return undefined;\n }\n\n /*\n * Queries such as ?url are irrelevant here.\n * FFmpeg needs the physical file.\n */\n return resolved.id.split(\"?\", 1)[0];\n}\n","import { basename, extname, join } from \"node:path\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport {\n encodeVariant,\n createEncodeDirectory,\n removeEncodeDirectory,\n} from \"./encoder\";\nimport { readCache, getCacheKey, writeCache } from \"./cache\";\nimport { collectFiles } from \"./fs\";\nimport { slugify, createMasterPlaylist } from \"./playlist\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport async function generateHls(\n source: string,\n cacheRoot: string,\n options: ResolvedHlsOptions,\n): Promise<CachedHls> {\n const key = await getCacheKey(source, options);\n\n const cached = await readCache(cacheRoot, key);\n\n if (cached) {\n console.log(`[vite-plugin-hls] cache hit ${source}`);\n\n return cached;\n }\n\n console.log(`[vite-plugin-hls] encoding ${source}`);\n\n const temporaryDirectory = await createEncodeDirectory();\n\n try {\n const videoName = slugify(basename(source, extname(source)));\n\n const directoryName = `${videoName}-${key.slice(0, 12)}`;\n\n let manifest: string;\n\n if (options.mode === \"single\") {\n await encodeVariant(source, temporaryDirectory, options);\n\n manifest = \"index.m3u8\";\n } else {\n for (const variant of options.variants) {\n await encodeVariant(\n source,\n join(temporaryDirectory, `${variant.height}p`),\n options,\n {\n height: variant.height,\n bitrate: variant.bitrate,\n },\n );\n }\n\n const master = createMasterPlaylist(options.variants);\n\n await writeFile(join(temporaryDirectory, \"master.m3u8\"), master, \"utf8\");\n\n manifest = \"master.m3u8\";\n }\n\n const result: CachedHls = {\n directoryName,\n manifest,\n files: await collectFiles(temporaryDirectory),\n };\n\n await writeCache(cacheRoot, key, result);\n\n console.log(`[vite-plugin-hls] generated ${directoryName}/${manifest}`);\n\n return result;\n } finally {\n await removeEncodeDirectory(temporaryDirectory);\n }\n}\n","import { access, copyFile, mkdir, mkdtemp, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport { Decoder, Demuxer, Encoder, FilterAPI, Muxer } from \"node-av/api\";\nimport { FF_ENCODER_AAC, FF_ENCODER_LIBX264 } from \"node-av/constants\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { ResolvedHlsOptions } from \"./types\";\n\ninterface EncodeVariantOptions {\n height?: number;\n bitrate?: string;\n}\n\nconst PLAYLIST = \"index.m3u8\";\n\ntype HlsOptions = {\n hls_time: string;\n hls_playlist_type: \"vod\";\n hls_segment_filename: string;\n hls_segment_type?: \"mpegts\" | \"fmp4\";\n hls_fmp4_init_filename?: string;\n};\n\nfunction hlsMuxerOptions(\n outputDirectory: string,\n options: ResolvedHlsOptions,\n): HlsOptions {\n const extension = options.segmentType === \"fmp4\" ? \"m4s\" : \"ts\";\n\n const hls: HlsOptions = {\n hls_time: String(options.segmentDuration),\n hls_playlist_type: \"vod\",\n hls_segment_filename: join(outputDirectory, `segment-%05d.${extension}`),\n };\n\n if (options.segmentType === \"fmp4\") {\n hls.hls_segment_type = \"fmp4\";\n\n /*\n * ffmpeg base-joins hls_fmp4_init_filename onto the HLS output dir, so an\n * absolute path is doubled (e.g. on POSIX). Keep it relative and rely on\n * ensureInitSegment() to place it correctly.\n */\n hls.hls_fmp4_init_filename = \"init.mp4\";\n }\n\n return hls;\n}\n\n/*\n * ffmpeg writes the relative init filename into the HLS output directory on\n * POSIX, but on some platforms (e.g. Windows) it can instead land in the\n * process CWD. Make sure it ends up next to the playlist.\n */\nasync function ensureInitSegment(outputDirectory: string): Promise<void> {\n const target = join(outputDirectory, \"init.mp4\");\n\n try {\n await access(target);\n return;\n } catch {\n // fall through\n }\n\n const leaked = join(process.cwd(), \"init.mp4\");\n\n try {\n await access(leaked);\n } catch {\n return;\n }\n\n await copyFile(leaked, target);\n await rm(leaked, { force: true });\n}\n\n/*\n * SINGLE MODE (remux): copy the streams, only repackage into HLS.\n */\nasync function remuxToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n): Promise<void> {\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const routed = new Map<number, number>();\n\n const video = input.video();\n if (video) {\n routed.set(video.index, output.addStream(video));\n }\n\n const audio = input.audio();\n if (audio) {\n routed.set(audio.index, output.addStream(audio));\n }\n\n for await (const packet of input.packets()) {\n if (packet === null) {\n break;\n }\n\n const index = routed.get(packet.streamIndex);\n\n if (index !== undefined) {\n await output.writePacket(packet, index);\n }\n\n packet.free();\n }\n\n await output.close();\n}\n\n/*\n * ADAPTIVE MODE (transcode): re-encode each rendition's video (scaled,\n * libx264) and audio (aac) into its HLS output.\n */\nasync function transcodeToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions,\n): Promise<void> {\n if (options.mode !== \"adaptive\") {\n throw new Error(\n \"[vite-plugin-hls] internal: transcode requires adaptive mode\",\n );\n }\n\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const tasks: Promise<void>[] = [];\n\n const video = input.video();\n if (video) {\n const decoder = await Decoder.create(video);\n\n const scale = variant.height\n ? `scale=-2:${variant.height}:force_original_aspect_ratio=decrease,format=yuv420p`\n : \"format=yuv420p\";\n\n const filter = FilterAPI.create(scale);\n\n const encoderOptions: Record<string, string | number> = {\n preset: options.preset,\n crf: String(options.crf),\n };\n\n const encoderBase: Record<string, unknown> = {\n options: encoderOptions,\n };\n\n if (variant.bitrate !== undefined) {\n const bitrate = bitrateToNumber(variant.bitrate);\n\n encoderOptions.maxrate = bitrate;\n encoderOptions.bufsize = Math.round(bitrate * 1.5);\n encoderBase.bitrate = bitrate;\n }\n\n const encoder = await Encoder.create(\n FF_ENCODER_LIBX264,\n encoderBase as Parameters<typeof Encoder.create>[1],\n );\n\n const index = output.addStream(encoder, { inputStream: video });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(video.index));\n const scaled = filter.frames(frames);\n\n for await (const packet of encoder.packets(scaled)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n filter.close();\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n const audio = input.audio();\n if (audio) {\n const decoder = await Decoder.create(audio);\n\n const encoder = await Encoder.create(FF_ENCODER_AAC, {\n decoder,\n bitrate: 128_000,\n });\n\n const index = output.addStream(encoder, { inputStream: audio });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(audio.index));\n\n for await (const packet of encoder.packets(frames)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n await Promise.all(tasks);\n await output.close();\n}\n\nexport async function encodeVariant(\n source: string,\n outputDirectory: string,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions = {},\n): Promise<void> {\n const hls = hlsMuxerOptions(outputDirectory, options);\n const playlist = join(outputDirectory, PLAYLIST);\n\n /*\n * FFmpeg's HLS muxer does not create the output directory.\n * Ensure it exists so segments/playlist can be written.\n */\n await mkdir(outputDirectory, { recursive: true });\n\n if (options.mode === \"single\") {\n await remuxToHls(source, playlist, hls);\n } else {\n await transcodeToHls(source, playlist, hls, options, variant);\n }\n\n if (options.segmentType === \"fmp4\") {\n await ensureInitSegment(outputDirectory);\n }\n}\n\nexport async function createEncodeDirectory(): Promise<string> {\n return mkdtemp(join(tmpdir(), \"vite-plugin-hls-\"));\n}\n\nexport async function removeEncodeDirectory(directory: string): Promise<void> {\n await rm(directory, {\n recursive: true,\n force: true,\n });\n}\n","/**\n * Converts a human-readable bitrate such as \"1200k\", \"2.5M\" or \"1G\"\n * into the equivalent number of bits per second.\n */\nexport function bitrateToNumber(bitrate: string): number {\n const match = /^([\\d.]+)\\s*([kKmMgG]?)$/.exec(bitrate.trim());\n\n if (!match) {\n throw new Error(`[vite-plugin-hls] Invalid bitrate: ${bitrate}`);\n }\n\n const amount = Number(match[1]);\n\n const suffix = (match[2] ?? \"\").toLowerCase();\n\n const multiplier =\n suffix === \"g\"\n ? 1_000_000_000\n : suffix === \"m\"\n ? 1_000_000\n : suffix === \"k\"\n ? 1_000\n : 1;\n\n return Math.round(amount * multiplier);\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { collectFiles } from \"./fs\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\ninterface CacheManifest {\n directoryName: string;\n manifest: string;\n}\n\n/*\n * Bump whenever the encoder's output layout changes (e.g. a bug fix alters\n * which files are produced). Old cache entries are keyed only on source +\n * options and would otherwise be served forever, so the version is folded\n * into the key to invalidate them.\n */\nconst CACHE_VERSION = \"2\";\n\nexport async function getCacheKey(\n source: string,\n options: ResolvedHlsOptions,\n): Promise<string> {\n const sourceData = await readFile(source);\n\n return createHash(\"sha256\")\n .update(CACHE_VERSION)\n .update(sourceData)\n .update(JSON.stringify(options))\n .digest(\"hex\");\n}\n\nexport async function readCache(\n cacheRoot: string,\n key: string,\n): Promise<CachedHls | undefined> {\n const directory = join(cacheRoot, \"hls\", key);\n\n try {\n await stat(directory);\n } catch {\n return undefined;\n }\n\n const metadata = JSON.parse(\n await readFile(join(directory, \"manifest.json\"), \"utf8\"),\n ) as CacheManifest;\n\n const files = await collectFiles(directory);\n\n // manifest.json is internal bookkeeping, never an emitted asset.\n files.delete(\"manifest.json\");\n\n return {\n directoryName: metadata.directoryName,\n\n manifest: metadata.manifest,\n\n files,\n };\n}\n\nexport async function writeCache(\n cacheRoot: string,\n key: string,\n result: CachedHls,\n): Promise<void> {\n const temporaryDirectory = join(cacheRoot, \"hls\", `${key}.tmp`);\n\n const finalDirectory = join(cacheRoot, \"hls\", key);\n\n await rm(temporaryDirectory, {\n recursive: true,\n force: true,\n });\n\n await mkdir(temporaryDirectory, {\n recursive: true,\n });\n\n for (const [filename, data] of result.files) {\n const destination = join(temporaryDirectory, filename);\n\n await mkdir(resolve(destination, \"..\"), {\n recursive: true,\n });\n\n await writeFile(destination, data);\n }\n\n await writeFile(\n join(temporaryDirectory, \"manifest.json\"),\n JSON.stringify({\n directoryName: result.directoryName,\n manifest: result.manifest,\n } satisfies CacheManifest),\n \"utf8\",\n );\n\n await rm(finalDirectory, {\n recursive: true,\n force: true,\n });\n\n await rename(temporaryDirectory, finalDirectory);\n}\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\n/**\n * Recursively collects every file under `directory` into a map of\n * directory-relative POSIX paths to their buffer contents.\n */\nexport async function collectFiles(\n directory: string,\n): Promise<Map<string, Buffer>> {\n const result = new Map<string, Buffer>();\n\n async function visit(current: string): Promise<void> {\n for (const entry of await readdir(current, { withFileTypes: true })) {\n const filename = join(current, entry.name);\n\n if (entry.isDirectory()) {\n await visit(filename);\n continue;\n }\n\n result.set(\n relative(directory, filename).replaceAll(\"\\\\\", \"/\"),\n await readFile(filename),\n );\n }\n }\n\n await visit(directory);\n\n return result;\n}\n","import { extname } from \"node:path\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { HlsVariant } from \"./types\";\n\n/** Turns a filename into a filesystem-safe slug used for the output folder. */\nexport function slugify(filename: string): string {\n return (\n filename\n .replace(extname(filename), \"\")\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"video\"\n );\n}\n\n/** Builds the adaptive master playlist pointing at each rendition. */\nexport function createMasterPlaylist(variants: readonly HlsVariant[]): string {\n const lines = [\"#EXTM3U\", \"#EXT-X-VERSION:7\"];\n\n for (const variant of variants) {\n // BANDWIDTH is an estimate derived from the configured bitrate.\n const bandwidth = Math.round(bitrateToNumber(variant.bitrate) * 1.15);\n\n lines.push(\n `#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth}`,\n `${variant.height}p/index.m3u8`,\n );\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n","import type { PluginContext } from \"rolldown\";\n\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport function emitHls(\n context: PluginContext,\n result: CachedHls,\n options: ResolvedHlsOptions,\n): void {\n const prefix = `${options.outputDir}/${result.directoryName}`;\n\n const manifestSource = result.files.get(result.manifest);\n\n if (!manifestSource) {\n throw new Error(`[vite-plugin-hls] Missing manifest ${result.manifest}`);\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${result.manifest}`,\n source: manifestSource,\n });\n\n for (const [filename, data] of result.files) {\n if (filename === result.manifest) {\n continue;\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${filename}`,\n source: data,\n });\n }\n}\n\nexport function publicManifestExpression(\n result: CachedHls,\n options: ResolvedHlsOptions,\n base: string,\n): string {\n const path = `${options.outputDir}/${result.directoryName}/${result.manifest}`;\n\n /*\n * Bake Vite's resolved base straight into the module. Vite does not always\n * statically replace import.meta.env.BASE_URL (e.g. in SSR bundles), where\n * import.meta.env is undefined at runtime and crashes. Emitting the base as\n * a plain string is equivalent and works for client and SSR alike.\n *\n * Examples (base -> export):\n *\n * \"/\" -> \"/assets/hls/...\"\n * \"/notes/\" -> \"/notes/assets/hls/...\"\n */\n return JSON.stringify(`${base}${path}`);\n}\n","import type { Plugin, ResolvedConfig } from \"vite\";\n\nimport { resolveOptions } from \"./options\";\nimport {\n isVideoSource,\n resolveVideoSource,\n sourceFromVirtualId,\n virtualIdForSource,\n} from \"./resolve\";\nimport { generateHls } from \"./hls\";\nimport { emitHls, publicManifestExpression } from \"./assets\";\nimport type { HlsPluginOptions } from \"./types\";\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function hlsVideos(input?: HlsPluginOptions): Plugin {\n const options = resolveOptions(input);\n\n let config: ResolvedConfig;\n\n const resolvedSources = new Map<string, string>();\n\n /*\n * This only caches inside the current Vite build.\n *\n * The persistent cache in cache.ts handles the\n * client/server build boundary.\n */\n const generated = new Map<string, Awaited<ReturnType<typeof generateHls>>>();\n\n return {\n name: \"vite-plugin-hls\",\n\n apply: \"build\",\n\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved;\n },\n\n async resolveId(source, importer) {\n if (!importer || !isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await resolveVideoSource(source, importer, this);\n\n if (!resolved) {\n return undefined;\n }\n\n const id = virtualIdForSource(resolved);\n\n resolvedSources.set(id, resolved);\n\n return id;\n },\n\n async load(id, loadOptions) {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return undefined;\n }\n\n const source = resolvedSources.get(id) ?? sourceFromVirtualId(id);\n\n let result = generated.get(source);\n\n if (!result) {\n result = await generateHls(source, config.cacheDir, options);\n\n generated.set(source, result);\n }\n\n /*\n * Important:\n *\n * The SSR build must NOT use Vite's emitted-file\n * URL because that resolves to a file:// URL.\n *\n * We only emit the actual files during the client\n * build. SSR receives the public URL directly.\n */\n if (!loadOptions?.ssr) {\n emitHls(this, result, options);\n }\n\n const manifest = publicManifestExpression(result, options, config.base);\n\n return `\n export default ${manifest};\n `;\n },\n };\n}\n"],"mappings":"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","names":["import_node_path","import_promises","import_node_path","import_promises","import_node_path","import_promises","import_node_path","import_node_path","VIRTUAL_PREFIX"]}
package/dist/index.js CHANGED
@@ -107,11 +107,11 @@ async function resolveVideoSource(source, importer, context) {
107
107
 
108
108
  // src/hls.ts
109
109
  import { basename, extname as extname3, join as join4 } from "path";
110
- import { writeFile as writeFile3 } from "fs/promises";
110
+ import { writeFile as writeFile2 } from "fs/promises";
111
111
 
112
112
  // src/encoder.ts
113
- import { mkdir, mkdtemp, readFile, rm, writeFile } from "fs/promises";
114
- import { dirname, join } from "path";
113
+ import { access, copyFile, mkdir, mkdtemp, rm } from "fs/promises";
114
+ import { join } from "path";
115
115
  import { tmpdir } from "os";
116
116
  import { Decoder, Demuxer, Encoder, FilterAPI, Muxer } from "node-av/api";
117
117
  import { FF_ENCODER_AAC, FF_ENCODER_LIBX264 } from "node-av/constants";
@@ -139,20 +139,25 @@ function hlsMuxerOptions(outputDirectory, options) {
139
139
  };
140
140
  if (options.segmentType === "fmp4") {
141
141
  hls.hls_segment_type = "fmp4";
142
- hls.hls_fmp4_init_filename = join(outputDirectory, "init.mp4");
142
+ hls.hls_fmp4_init_filename = "init.mp4";
143
143
  }
144
144
  return hls;
145
145
  }
146
- async function relativizePlaylist(playlist, outputDirectory) {
147
- let text;
146
+ async function ensureInitSegment(outputDirectory) {
147
+ const target = join(outputDirectory, "init.mp4");
148
148
  try {
149
- text = await readFile(playlist, "utf8");
149
+ await access(target);
150
+ return;
151
+ } catch {
152
+ }
153
+ const leaked = join(process.cwd(), "init.mp4");
154
+ try {
155
+ await access(leaked);
150
156
  } catch {
151
157
  return;
152
158
  }
153
- const prefix = outputDirectory.replace(/[\\/]+$/, "");
154
- text = text.split(prefix + "\\").join("").split(prefix + "/").join("");
155
- await writeFile(playlist, text, "utf8");
159
+ await copyFile(leaked, target);
160
+ await rm(leaked, { force: true });
156
161
  }
157
162
  async function remuxToHls(source, playlist, hls) {
158
163
  var _stack = [];
@@ -183,7 +188,6 @@ async function remuxToHls(source, playlist, hls) {
183
188
  packet.free();
184
189
  }
185
190
  await output.close();
186
- await relativizePlaylist(playlist, dirname(playlist));
187
191
  } catch (_) {
188
192
  var _error = _, _hasError = true;
189
193
  } finally {
@@ -277,7 +281,6 @@ async function transcodeToHls(source, playlist, hls, options, variant) {
277
281
  }
278
282
  await Promise.all(tasks);
279
283
  await output.close();
280
- await relativizePlaylist(playlist, dirname(playlist));
281
284
  } catch (_) {
282
285
  var _error = _, _hasError = true;
283
286
  } finally {
@@ -294,6 +297,9 @@ async function encodeVariant(source, outputDirectory, options, variant = {}) {
294
297
  } else {
295
298
  await transcodeToHls(source, playlist, hls, options, variant);
296
299
  }
300
+ if (options.segmentType === "fmp4") {
301
+ await ensureInitSegment(outputDirectory);
302
+ }
297
303
  }
298
304
  async function createEncodeDirectory() {
299
305
  return mkdtemp(join(tmpdir(), "vite-plugin-hls-"));
@@ -307,11 +313,11 @@ async function removeEncodeDirectory(directory) {
307
313
 
308
314
  // src/cache.ts
309
315
  import { createHash } from "crypto";
310
- import { mkdir as mkdir2, readFile as readFile3, rename, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
316
+ import { mkdir as mkdir2, readFile as readFile2, rename, rm as rm2, stat, writeFile } from "fs/promises";
311
317
  import { join as join3, resolve } from "path";
312
318
 
313
319
  // src/fs.ts
314
- import { readFile as readFile2, readdir } from "fs/promises";
320
+ import { readFile, readdir } from "fs/promises";
315
321
  import { join as join2, relative } from "path";
316
322
  async function collectFiles(directory) {
317
323
  const result = /* @__PURE__ */ new Map();
@@ -324,7 +330,7 @@ async function collectFiles(directory) {
324
330
  }
325
331
  result.set(
326
332
  relative(directory, filename).replaceAll("\\", "/"),
327
- await readFile2(filename)
333
+ await readFile(filename)
328
334
  );
329
335
  }
330
336
  }
@@ -335,7 +341,7 @@ async function collectFiles(directory) {
335
341
  // src/cache.ts
336
342
  var CACHE_VERSION = "2";
337
343
  async function getCacheKey(source, options) {
338
- const sourceData = await readFile3(source);
344
+ const sourceData = await readFile2(source);
339
345
  return createHash("sha256").update(CACHE_VERSION).update(sourceData).update(JSON.stringify(options)).digest("hex");
340
346
  }
341
347
  async function readCache(cacheRoot, key) {
@@ -346,7 +352,7 @@ async function readCache(cacheRoot, key) {
346
352
  return void 0;
347
353
  }
348
354
  const metadata = JSON.parse(
349
- await readFile3(join3(directory, "manifest.json"), "utf8")
355
+ await readFile2(join3(directory, "manifest.json"), "utf8")
350
356
  );
351
357
  const files = await collectFiles(directory);
352
358
  files.delete("manifest.json");
@@ -371,9 +377,9 @@ async function writeCache(cacheRoot, key, result) {
371
377
  await mkdir2(resolve(destination, ".."), {
372
378
  recursive: true
373
379
  });
374
- await writeFile2(destination, data);
380
+ await writeFile(destination, data);
375
381
  }
376
- await writeFile2(
382
+ await writeFile(
377
383
  join3(temporaryDirectory, "manifest.json"),
378
384
  JSON.stringify({
379
385
  directoryName: result.directoryName,
@@ -436,7 +442,7 @@ async function generateHls(source, cacheRoot, options) {
436
442
  );
437
443
  }
438
444
  const master = createMasterPlaylist(options.variants);
439
- await writeFile3(join4(temporaryDirectory, "master.m3u8"), master, "utf8");
445
+ await writeFile2(join4(temporaryDirectory, "master.m3u8"), master, "utf8");
440
446
  manifest = "master.m3u8";
441
447
  }
442
448
  const result = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/options.ts","../src/resolve.ts","../src/hls.ts","../src/encoder.ts","../src/bitrate.ts","../src/cache.ts","../src/fs.ts","../src/playlist.ts","../src/assets.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import type { HlsPluginOptions, ResolvedHlsOptions } from \"./types\";\n\nexport function resolveOptions(\n input: HlsPluginOptions = {},\n): ResolvedHlsOptions {\n const common = {\n segmentDuration: input.segmentDuration ?? 4,\n\n segmentType: input.segmentType ?? \"fmp4\",\n\n outputDir: input.outputDir ?? \"assets/hls\",\n\n preset: input.preset ?? \"medium\",\n\n crf: input.crf ?? 23,\n };\n\n if (input.mode === \"adaptive\") {\n if (!input.variants || input.variants.length === 0) {\n throw new Error(\n \"[vite-plugin-hls] Adaptive mode requires at least one variant.\",\n );\n }\n\n return {\n ...common,\n mode: \"adaptive\",\n variants: input.variants,\n };\n }\n\n return {\n ...common,\n mode: \"single\",\n };\n}\n","import { extname } from \"node:path\";\n\nimport type { PluginContext } from \"rolldown\";\n\nconst VIDEO_EXTENSIONS = new Set([\n \".mp4\",\n \".mov\",\n \".m4v\",\n \".webm\",\n \".mkv\",\n \".avi\",\n]);\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function isVideoSource(source: string): boolean {\n const pathname = source.split(\"?\")[0] ?? source;\n\n return VIDEO_EXTENSIONS.has(extname(pathname).toLowerCase());\n}\n\nexport function virtualIdForSource(source: string): string {\n return `${VIRTUAL_PREFIX}${encodeURIComponent(source)}`;\n}\n\nexport function sourceFromVirtualId(id: string): string {\n return decodeURIComponent(id.slice(VIRTUAL_PREFIX.length));\n}\n\nexport async function resolveVideoSource(\n source: string,\n importer: string,\n context: PluginContext,\n): Promise<string | undefined> {\n if (!isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await context.resolve(source, importer, {\n skipSelf: true,\n });\n\n if (!resolved || resolved.external) {\n return undefined;\n }\n\n /*\n * Queries such as ?url are irrelevant here.\n * FFmpeg needs the physical file.\n */\n return resolved.id.split(\"?\", 1)[0];\n}\n","import { basename, extname, join } from \"node:path\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport {\n encodeVariant,\n createEncodeDirectory,\n removeEncodeDirectory,\n} from \"./encoder\";\nimport { readCache, getCacheKey, writeCache } from \"./cache\";\nimport { collectFiles } from \"./fs\";\nimport { slugify, createMasterPlaylist } from \"./playlist\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport async function generateHls(\n source: string,\n cacheRoot: string,\n options: ResolvedHlsOptions,\n): Promise<CachedHls> {\n const key = await getCacheKey(source, options);\n\n const cached = await readCache(cacheRoot, key);\n\n if (cached) {\n console.log(`[vite-plugin-hls] cache hit ${source}`);\n\n return cached;\n }\n\n console.log(`[vite-plugin-hls] encoding ${source}`);\n\n const temporaryDirectory = await createEncodeDirectory();\n\n try {\n const videoName = slugify(basename(source, extname(source)));\n\n const directoryName = `${videoName}-${key.slice(0, 12)}`;\n\n let manifest: string;\n\n if (options.mode === \"single\") {\n await encodeVariant(source, temporaryDirectory, options);\n\n manifest = \"index.m3u8\";\n } else {\n for (const variant of options.variants) {\n await encodeVariant(\n source,\n join(temporaryDirectory, `${variant.height}p`),\n options,\n {\n height: variant.height,\n bitrate: variant.bitrate,\n },\n );\n }\n\n const master = createMasterPlaylist(options.variants);\n\n await writeFile(join(temporaryDirectory, \"master.m3u8\"), master, \"utf8\");\n\n manifest = \"master.m3u8\";\n }\n\n const result: CachedHls = {\n directoryName,\n manifest,\n files: await collectFiles(temporaryDirectory),\n };\n\n await writeCache(cacheRoot, key, result);\n\n console.log(`[vite-plugin-hls] generated ${directoryName}/${manifest}`);\n\n return result;\n } finally {\n await removeEncodeDirectory(temporaryDirectory);\n }\n}\n","import { mkdir, mkdtemp, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport { Decoder, Demuxer, Encoder, FilterAPI, Muxer } from \"node-av/api\";\nimport { FF_ENCODER_AAC, FF_ENCODER_LIBX264 } from \"node-av/constants\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { ResolvedHlsOptions } from \"./types\";\n\ninterface EncodeVariantOptions {\n height?: number;\n bitrate?: string;\n}\n\nconst PLAYLIST = \"index.m3u8\";\n\ntype HlsOptions = {\n hls_time: string;\n hls_playlist_type: \"vod\";\n hls_segment_filename: string;\n hls_segment_type?: \"mpegts\" | \"fmp4\";\n hls_fmp4_init_filename?: string;\n};\n\nfunction hlsMuxerOptions(\n outputDirectory: string,\n options: ResolvedHlsOptions,\n): HlsOptions {\n const extension = options.segmentType === \"fmp4\" ? \"m4s\" : \"ts\";\n\n const hls: HlsOptions = {\n hls_time: String(options.segmentDuration),\n hls_playlist_type: \"vod\",\n hls_segment_filename: join(outputDirectory, `segment-%05d.${extension}`),\n };\n\n if (options.segmentType === \"fmp4\") {\n hls.hls_segment_type = \"fmp4\";\n\n /*\n * The init filename must be absolute so the file lands next to the\n * playlist. A relative name would be resolved against the process CWD\n * (the project root) and leak there. The playlist is relativized after\n * encoding (see relativizePlaylist).\n */\n hls.hls_fmp4_init_filename = join(outputDirectory, \"init.mp4\");\n }\n\n return hls;\n}\n\n/*\n * ffmpeg references an absolute init path literally in EXT-X-MAP (segment\n * URIs are already emitted as basenames). Rewrite it to a path relative to\n * the output directory so the playlist stays portable.\n */\nasync function relativizePlaylist(\n playlist: string,\n outputDirectory: string,\n): Promise<void> {\n let text: string;\n try {\n text = await readFile(playlist, \"utf8\");\n } catch {\n return; // nothing written (e.g. mocked in tests)\n }\n\n const prefix = outputDirectory.replace(/[\\\\/]+$/, \"\");\n\n text = text\n .split(prefix + \"\\\\\")\n .join(\"\")\n .split(prefix + \"/\")\n .join(\"\");\n\n await writeFile(playlist, text, \"utf8\");\n}\n\n/*\n * SINGLE MODE (remux): copy the streams, only repackage into HLS.\n */\nasync function remuxToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n): Promise<void> {\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const routed = new Map<number, number>();\n\n const video = input.video();\n if (video) {\n routed.set(video.index, output.addStream(video));\n }\n\n const audio = input.audio();\n if (audio) {\n routed.set(audio.index, output.addStream(audio));\n }\n\n for await (const packet of input.packets()) {\n if (packet === null) {\n break;\n }\n\n const index = routed.get(packet.streamIndex);\n\n if (index !== undefined) {\n await output.writePacket(packet, index);\n }\n\n packet.free();\n }\n\n await output.close();\n\n await relativizePlaylist(playlist, dirname(playlist));\n}\n\n/*\n * ADAPTIVE MODE (transcode): re-encode each rendition's video (scaled,\n * libx264) and audio (aac) into its HLS output.\n */\nasync function transcodeToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions,\n): Promise<void> {\n if (options.mode !== \"adaptive\") {\n throw new Error(\n \"[vite-plugin-hls] internal: transcode requires adaptive mode\",\n );\n }\n\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const tasks: Promise<void>[] = [];\n\n const video = input.video();\n if (video) {\n const decoder = await Decoder.create(video);\n\n const scale = variant.height\n ? `scale=-2:${variant.height}:force_original_aspect_ratio=decrease,format=yuv420p`\n : \"format=yuv420p\";\n\n const filter = FilterAPI.create(scale);\n\n const encoderOptions: Record<string, string | number> = {\n preset: options.preset,\n crf: String(options.crf),\n };\n\n const encoderBase: Record<string, unknown> = {\n options: encoderOptions,\n };\n\n if (variant.bitrate !== undefined) {\n const bitrate = bitrateToNumber(variant.bitrate);\n\n encoderOptions.maxrate = bitrate;\n encoderOptions.bufsize = Math.round(bitrate * 1.5);\n encoderBase.bitrate = bitrate;\n }\n\n const encoder = await Encoder.create(\n FF_ENCODER_LIBX264,\n encoderBase as Parameters<typeof Encoder.create>[1],\n );\n\n const index = output.addStream(encoder, { inputStream: video });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(video.index));\n const scaled = filter.frames(frames);\n\n for await (const packet of encoder.packets(scaled)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n filter.close();\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n const audio = input.audio();\n if (audio) {\n const decoder = await Decoder.create(audio);\n\n const encoder = await Encoder.create(FF_ENCODER_AAC, {\n decoder,\n bitrate: 128_000,\n });\n\n const index = output.addStream(encoder, { inputStream: audio });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(audio.index));\n\n for await (const packet of encoder.packets(frames)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n await Promise.all(tasks);\n await output.close();\n\n await relativizePlaylist(playlist, dirname(playlist));\n}\n\nexport async function encodeVariant(\n source: string,\n outputDirectory: string,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions = {},\n): Promise<void> {\n const hls = hlsMuxerOptions(outputDirectory, options);\n const playlist = join(outputDirectory, PLAYLIST);\n\n /*\n * FFmpeg's HLS muxer does not create the output directory.\n * Ensure it exists so segments/playlist can be written.\n */\n await mkdir(outputDirectory, { recursive: true });\n\n if (options.mode === \"single\") {\n await remuxToHls(source, playlist, hls);\n } else {\n await transcodeToHls(source, playlist, hls, options, variant);\n }\n}\n\nexport async function createEncodeDirectory(): Promise<string> {\n return mkdtemp(join(tmpdir(), \"vite-plugin-hls-\"));\n}\n\nexport async function removeEncodeDirectory(directory: string): Promise<void> {\n await rm(directory, {\n recursive: true,\n force: true,\n });\n}\n","/**\n * Converts a human-readable bitrate such as \"1200k\", \"2.5M\" or \"1G\"\n * into the equivalent number of bits per second.\n */\nexport function bitrateToNumber(bitrate: string): number {\n const match = /^([\\d.]+)\\s*([kKmMgG]?)$/.exec(bitrate.trim());\n\n if (!match) {\n throw new Error(`[vite-plugin-hls] Invalid bitrate: ${bitrate}`);\n }\n\n const amount = Number(match[1]);\n\n const suffix = (match[2] ?? \"\").toLowerCase();\n\n const multiplier =\n suffix === \"g\"\n ? 1_000_000_000\n : suffix === \"m\"\n ? 1_000_000\n : suffix === \"k\"\n ? 1_000\n : 1;\n\n return Math.round(amount * multiplier);\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { collectFiles } from \"./fs\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\ninterface CacheManifest {\n directoryName: string;\n manifest: string;\n}\n\n/*\n * Bump whenever the encoder's output layout changes (e.g. a bug fix alters\n * which files are produced). Old cache entries are keyed only on source +\n * options and would otherwise be served forever, so the version is folded\n * into the key to invalidate them.\n */\nconst CACHE_VERSION = \"2\";\n\nexport async function getCacheKey(\n source: string,\n options: ResolvedHlsOptions,\n): Promise<string> {\n const sourceData = await readFile(source);\n\n return createHash(\"sha256\")\n .update(CACHE_VERSION)\n .update(sourceData)\n .update(JSON.stringify(options))\n .digest(\"hex\");\n}\n\nexport async function readCache(\n cacheRoot: string,\n key: string,\n): Promise<CachedHls | undefined> {\n const directory = join(cacheRoot, \"hls\", key);\n\n try {\n await stat(directory);\n } catch {\n return undefined;\n }\n\n const metadata = JSON.parse(\n await readFile(join(directory, \"manifest.json\"), \"utf8\"),\n ) as CacheManifest;\n\n const files = await collectFiles(directory);\n\n // manifest.json is internal bookkeeping, never an emitted asset.\n files.delete(\"manifest.json\");\n\n return {\n directoryName: metadata.directoryName,\n\n manifest: metadata.manifest,\n\n files,\n };\n}\n\nexport async function writeCache(\n cacheRoot: string,\n key: string,\n result: CachedHls,\n): Promise<void> {\n const temporaryDirectory = join(cacheRoot, \"hls\", `${key}.tmp`);\n\n const finalDirectory = join(cacheRoot, \"hls\", key);\n\n await rm(temporaryDirectory, {\n recursive: true,\n force: true,\n });\n\n await mkdir(temporaryDirectory, {\n recursive: true,\n });\n\n for (const [filename, data] of result.files) {\n const destination = join(temporaryDirectory, filename);\n\n await mkdir(resolve(destination, \"..\"), {\n recursive: true,\n });\n\n await writeFile(destination, data);\n }\n\n await writeFile(\n join(temporaryDirectory, \"manifest.json\"),\n JSON.stringify({\n directoryName: result.directoryName,\n manifest: result.manifest,\n } satisfies CacheManifest),\n \"utf8\",\n );\n\n await rm(finalDirectory, {\n recursive: true,\n force: true,\n });\n\n await rename(temporaryDirectory, finalDirectory);\n}\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\n/**\n * Recursively collects every file under `directory` into a map of\n * directory-relative POSIX paths to their buffer contents.\n */\nexport async function collectFiles(\n directory: string,\n): Promise<Map<string, Buffer>> {\n const result = new Map<string, Buffer>();\n\n async function visit(current: string): Promise<void> {\n for (const entry of await readdir(current, { withFileTypes: true })) {\n const filename = join(current, entry.name);\n\n if (entry.isDirectory()) {\n await visit(filename);\n continue;\n }\n\n result.set(\n relative(directory, filename).replaceAll(\"\\\\\", \"/\"),\n await readFile(filename),\n );\n }\n }\n\n await visit(directory);\n\n return result;\n}\n","import { extname } from \"node:path\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { HlsVariant } from \"./types\";\n\n/** Turns a filename into a filesystem-safe slug used for the output folder. */\nexport function slugify(filename: string): string {\n return (\n filename\n .replace(extname(filename), \"\")\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"video\"\n );\n}\n\n/** Builds the adaptive master playlist pointing at each rendition. */\nexport function createMasterPlaylist(variants: readonly HlsVariant[]): string {\n const lines = [\"#EXTM3U\", \"#EXT-X-VERSION:7\"];\n\n for (const variant of variants) {\n // BANDWIDTH is an estimate derived from the configured bitrate.\n const bandwidth = Math.round(bitrateToNumber(variant.bitrate) * 1.15);\n\n lines.push(\n `#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth}`,\n `${variant.height}p/index.m3u8`,\n );\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n","import type { PluginContext } from \"rolldown\";\n\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport function emitHls(\n context: PluginContext,\n result: CachedHls,\n options: ResolvedHlsOptions,\n): void {\n const prefix = `${options.outputDir}/${result.directoryName}`;\n\n const manifestSource = result.files.get(result.manifest);\n\n if (!manifestSource) {\n throw new Error(`[vite-plugin-hls] Missing manifest ${result.manifest}`);\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${result.manifest}`,\n source: manifestSource,\n });\n\n for (const [filename, data] of result.files) {\n if (filename === result.manifest) {\n continue;\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${filename}`,\n source: data,\n });\n }\n}\n\nexport function publicManifestExpression(\n result: CachedHls,\n options: ResolvedHlsOptions,\n base: string,\n): string {\n const path = `${options.outputDir}/${result.directoryName}/${result.manifest}`;\n\n /*\n * Bake Vite's resolved base straight into the module. Vite does not always\n * statically replace import.meta.env.BASE_URL (e.g. in SSR bundles), where\n * import.meta.env is undefined at runtime and crashes. Emitting the base as\n * a plain string is equivalent and works for client and SSR alike.\n *\n * Examples (base -> export):\n *\n * \"/\" -> \"/assets/hls/...\"\n * \"/notes/\" -> \"/notes/assets/hls/...\"\n */\n return JSON.stringify(`${base}${path}`);\n}\n","import type { Plugin, ResolvedConfig } from \"vite\";\n\nimport { resolveOptions } from \"./options\";\nimport {\n isVideoSource,\n resolveVideoSource,\n sourceFromVirtualId,\n virtualIdForSource,\n} from \"./resolve\";\nimport { generateHls } from \"./hls\";\nimport { emitHls, publicManifestExpression } from \"./assets\";\nimport type { HlsPluginOptions } from \"./types\";\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function hlsVideos(input?: HlsPluginOptions): Plugin {\n const options = resolveOptions(input);\n\n let config: ResolvedConfig;\n\n const resolvedSources = new Map<string, string>();\n\n /*\n * This only caches inside the current Vite build.\n *\n * The persistent cache in cache.ts handles the\n * client/server build boundary.\n */\n const generated = new Map<string, Awaited<ReturnType<typeof generateHls>>>();\n\n return {\n name: \"vite-plugin-hls\",\n\n apply: \"build\",\n\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved;\n },\n\n async resolveId(source, importer) {\n if (!importer || !isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await resolveVideoSource(source, importer, this);\n\n if (!resolved) {\n return undefined;\n }\n\n const id = virtualIdForSource(resolved);\n\n resolvedSources.set(id, resolved);\n\n return id;\n },\n\n async load(id, loadOptions) {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return undefined;\n }\n\n const source = resolvedSources.get(id) ?? sourceFromVirtualId(id);\n\n let result = generated.get(source);\n\n if (!result) {\n result = await generateHls(source, config.cacheDir, options);\n\n generated.set(source, result);\n }\n\n /*\n * Important:\n *\n * The SSR build must NOT use Vite's emitted-file\n * URL because that resolves to a file:// URL.\n *\n * We only emit the actual files during the client\n * build. SSR receives the public URL directly.\n */\n if (!loadOptions?.ssr) {\n emitHls(this, result, options);\n }\n\n const manifest = publicManifestExpression(result, options, config.base);\n\n return `\n export default ${manifest};\n `;\n },\n };\n}\n","import { hlsVideos } from \"./plugin\";\n\nexport { hlsVideos };\nexport default hlsVideos;\n\nexport type { HlsPluginOptions, HlsVariant } from \"./types\";\n"],"mappings":"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","names":["extname","join","writeFile","mkdir","readFile","rm","writeFile","join","readFile","join","readFile","join","rm","mkdir","writeFile","extname","extname","extname","join","writeFile","VIRTUAL_PREFIX"]}
1
+ {"version":3,"sources":["../src/options.ts","../src/resolve.ts","../src/hls.ts","../src/encoder.ts","../src/bitrate.ts","../src/cache.ts","../src/fs.ts","../src/playlist.ts","../src/assets.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import type { HlsPluginOptions, ResolvedHlsOptions } from \"./types\";\n\nexport function resolveOptions(\n input: HlsPluginOptions = {},\n): ResolvedHlsOptions {\n const common = {\n segmentDuration: input.segmentDuration ?? 4,\n\n segmentType: input.segmentType ?? \"fmp4\",\n\n outputDir: input.outputDir ?? \"assets/hls\",\n\n preset: input.preset ?? \"medium\",\n\n crf: input.crf ?? 23,\n };\n\n if (input.mode === \"adaptive\") {\n if (!input.variants || input.variants.length === 0) {\n throw new Error(\n \"[vite-plugin-hls] Adaptive mode requires at least one variant.\",\n );\n }\n\n return {\n ...common,\n mode: \"adaptive\",\n variants: input.variants,\n };\n }\n\n return {\n ...common,\n mode: \"single\",\n };\n}\n","import { extname } from \"node:path\";\n\nimport type { PluginContext } from \"rolldown\";\n\nconst VIDEO_EXTENSIONS = new Set([\n \".mp4\",\n \".mov\",\n \".m4v\",\n \".webm\",\n \".mkv\",\n \".avi\",\n]);\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function isVideoSource(source: string): boolean {\n const pathname = source.split(\"?\")[0] ?? source;\n\n return VIDEO_EXTENSIONS.has(extname(pathname).toLowerCase());\n}\n\nexport function virtualIdForSource(source: string): string {\n return `${VIRTUAL_PREFIX}${encodeURIComponent(source)}`;\n}\n\nexport function sourceFromVirtualId(id: string): string {\n return decodeURIComponent(id.slice(VIRTUAL_PREFIX.length));\n}\n\nexport async function resolveVideoSource(\n source: string,\n importer: string,\n context: PluginContext,\n): Promise<string | undefined> {\n if (!isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await context.resolve(source, importer, {\n skipSelf: true,\n });\n\n if (!resolved || resolved.external) {\n return undefined;\n }\n\n /*\n * Queries such as ?url are irrelevant here.\n * FFmpeg needs the physical file.\n */\n return resolved.id.split(\"?\", 1)[0];\n}\n","import { basename, extname, join } from \"node:path\";\nimport { writeFile } from \"node:fs/promises\";\n\nimport {\n encodeVariant,\n createEncodeDirectory,\n removeEncodeDirectory,\n} from \"./encoder\";\nimport { readCache, getCacheKey, writeCache } from \"./cache\";\nimport { collectFiles } from \"./fs\";\nimport { slugify, createMasterPlaylist } from \"./playlist\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport async function generateHls(\n source: string,\n cacheRoot: string,\n options: ResolvedHlsOptions,\n): Promise<CachedHls> {\n const key = await getCacheKey(source, options);\n\n const cached = await readCache(cacheRoot, key);\n\n if (cached) {\n console.log(`[vite-plugin-hls] cache hit ${source}`);\n\n return cached;\n }\n\n console.log(`[vite-plugin-hls] encoding ${source}`);\n\n const temporaryDirectory = await createEncodeDirectory();\n\n try {\n const videoName = slugify(basename(source, extname(source)));\n\n const directoryName = `${videoName}-${key.slice(0, 12)}`;\n\n let manifest: string;\n\n if (options.mode === \"single\") {\n await encodeVariant(source, temporaryDirectory, options);\n\n manifest = \"index.m3u8\";\n } else {\n for (const variant of options.variants) {\n await encodeVariant(\n source,\n join(temporaryDirectory, `${variant.height}p`),\n options,\n {\n height: variant.height,\n bitrate: variant.bitrate,\n },\n );\n }\n\n const master = createMasterPlaylist(options.variants);\n\n await writeFile(join(temporaryDirectory, \"master.m3u8\"), master, \"utf8\");\n\n manifest = \"master.m3u8\";\n }\n\n const result: CachedHls = {\n directoryName,\n manifest,\n files: await collectFiles(temporaryDirectory),\n };\n\n await writeCache(cacheRoot, key, result);\n\n console.log(`[vite-plugin-hls] generated ${directoryName}/${manifest}`);\n\n return result;\n } finally {\n await removeEncodeDirectory(temporaryDirectory);\n }\n}\n","import { access, copyFile, mkdir, mkdtemp, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport { Decoder, Demuxer, Encoder, FilterAPI, Muxer } from \"node-av/api\";\nimport { FF_ENCODER_AAC, FF_ENCODER_LIBX264 } from \"node-av/constants\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { ResolvedHlsOptions } from \"./types\";\n\ninterface EncodeVariantOptions {\n height?: number;\n bitrate?: string;\n}\n\nconst PLAYLIST = \"index.m3u8\";\n\ntype HlsOptions = {\n hls_time: string;\n hls_playlist_type: \"vod\";\n hls_segment_filename: string;\n hls_segment_type?: \"mpegts\" | \"fmp4\";\n hls_fmp4_init_filename?: string;\n};\n\nfunction hlsMuxerOptions(\n outputDirectory: string,\n options: ResolvedHlsOptions,\n): HlsOptions {\n const extension = options.segmentType === \"fmp4\" ? \"m4s\" : \"ts\";\n\n const hls: HlsOptions = {\n hls_time: String(options.segmentDuration),\n hls_playlist_type: \"vod\",\n hls_segment_filename: join(outputDirectory, `segment-%05d.${extension}`),\n };\n\n if (options.segmentType === \"fmp4\") {\n hls.hls_segment_type = \"fmp4\";\n\n /*\n * ffmpeg base-joins hls_fmp4_init_filename onto the HLS output dir, so an\n * absolute path is doubled (e.g. on POSIX). Keep it relative and rely on\n * ensureInitSegment() to place it correctly.\n */\n hls.hls_fmp4_init_filename = \"init.mp4\";\n }\n\n return hls;\n}\n\n/*\n * ffmpeg writes the relative init filename into the HLS output directory on\n * POSIX, but on some platforms (e.g. Windows) it can instead land in the\n * process CWD. Make sure it ends up next to the playlist.\n */\nasync function ensureInitSegment(outputDirectory: string): Promise<void> {\n const target = join(outputDirectory, \"init.mp4\");\n\n try {\n await access(target);\n return;\n } catch {\n // fall through\n }\n\n const leaked = join(process.cwd(), \"init.mp4\");\n\n try {\n await access(leaked);\n } catch {\n return;\n }\n\n await copyFile(leaked, target);\n await rm(leaked, { force: true });\n}\n\n/*\n * SINGLE MODE (remux): copy the streams, only repackage into HLS.\n */\nasync function remuxToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n): Promise<void> {\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const routed = new Map<number, number>();\n\n const video = input.video();\n if (video) {\n routed.set(video.index, output.addStream(video));\n }\n\n const audio = input.audio();\n if (audio) {\n routed.set(audio.index, output.addStream(audio));\n }\n\n for await (const packet of input.packets()) {\n if (packet === null) {\n break;\n }\n\n const index = routed.get(packet.streamIndex);\n\n if (index !== undefined) {\n await output.writePacket(packet, index);\n }\n\n packet.free();\n }\n\n await output.close();\n}\n\n/*\n * ADAPTIVE MODE (transcode): re-encode each rendition's video (scaled,\n * libx264) and audio (aac) into its HLS output.\n */\nasync function transcodeToHls(\n source: string,\n playlist: string,\n hls: HlsOptions,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions,\n): Promise<void> {\n if (options.mode !== \"adaptive\") {\n throw new Error(\n \"[vite-plugin-hls] internal: transcode requires adaptive mode\",\n );\n }\n\n await using input = await Demuxer.open(source);\n await using output = await Muxer.open(playlist, {\n format: \"hls\",\n input,\n options: hls,\n });\n\n const tasks: Promise<void>[] = [];\n\n const video = input.video();\n if (video) {\n const decoder = await Decoder.create(video);\n\n const scale = variant.height\n ? `scale=-2:${variant.height}:force_original_aspect_ratio=decrease,format=yuv420p`\n : \"format=yuv420p\";\n\n const filter = FilterAPI.create(scale);\n\n const encoderOptions: Record<string, string | number> = {\n preset: options.preset,\n crf: String(options.crf),\n };\n\n const encoderBase: Record<string, unknown> = {\n options: encoderOptions,\n };\n\n if (variant.bitrate !== undefined) {\n const bitrate = bitrateToNumber(variant.bitrate);\n\n encoderOptions.maxrate = bitrate;\n encoderOptions.bufsize = Math.round(bitrate * 1.5);\n encoderBase.bitrate = bitrate;\n }\n\n const encoder = await Encoder.create(\n FF_ENCODER_LIBX264,\n encoderBase as Parameters<typeof Encoder.create>[1],\n );\n\n const index = output.addStream(encoder, { inputStream: video });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(video.index));\n const scaled = filter.frames(frames);\n\n for await (const packet of encoder.packets(scaled)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n filter.close();\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n const audio = input.audio();\n if (audio) {\n const decoder = await Decoder.create(audio);\n\n const encoder = await Encoder.create(FF_ENCODER_AAC, {\n decoder,\n bitrate: 128_000,\n });\n\n const index = output.addStream(encoder, { inputStream: audio });\n\n tasks.push(\n (async () => {\n try {\n const frames = decoder.frames(input.packets(audio.index));\n\n for await (const packet of encoder.packets(frames)) {\n if (packet === null) {\n break;\n }\n await output.writePacket(packet, index);\n packet.free();\n }\n } finally {\n decoder.close();\n encoder.close();\n }\n })(),\n );\n }\n\n await Promise.all(tasks);\n await output.close();\n}\n\nexport async function encodeVariant(\n source: string,\n outputDirectory: string,\n options: ResolvedHlsOptions,\n variant: EncodeVariantOptions = {},\n): Promise<void> {\n const hls = hlsMuxerOptions(outputDirectory, options);\n const playlist = join(outputDirectory, PLAYLIST);\n\n /*\n * FFmpeg's HLS muxer does not create the output directory.\n * Ensure it exists so segments/playlist can be written.\n */\n await mkdir(outputDirectory, { recursive: true });\n\n if (options.mode === \"single\") {\n await remuxToHls(source, playlist, hls);\n } else {\n await transcodeToHls(source, playlist, hls, options, variant);\n }\n\n if (options.segmentType === \"fmp4\") {\n await ensureInitSegment(outputDirectory);\n }\n}\n\nexport async function createEncodeDirectory(): Promise<string> {\n return mkdtemp(join(tmpdir(), \"vite-plugin-hls-\"));\n}\n\nexport async function removeEncodeDirectory(directory: string): Promise<void> {\n await rm(directory, {\n recursive: true,\n force: true,\n });\n}\n","/**\n * Converts a human-readable bitrate such as \"1200k\", \"2.5M\" or \"1G\"\n * into the equivalent number of bits per second.\n */\nexport function bitrateToNumber(bitrate: string): number {\n const match = /^([\\d.]+)\\s*([kKmMgG]?)$/.exec(bitrate.trim());\n\n if (!match) {\n throw new Error(`[vite-plugin-hls] Invalid bitrate: ${bitrate}`);\n }\n\n const amount = Number(match[1]);\n\n const suffix = (match[2] ?? \"\").toLowerCase();\n\n const multiplier =\n suffix === \"g\"\n ? 1_000_000_000\n : suffix === \"m\"\n ? 1_000_000\n : suffix === \"k\"\n ? 1_000\n : 1;\n\n return Math.round(amount * multiplier);\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { collectFiles } from \"./fs\";\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\ninterface CacheManifest {\n directoryName: string;\n manifest: string;\n}\n\n/*\n * Bump whenever the encoder's output layout changes (e.g. a bug fix alters\n * which files are produced). Old cache entries are keyed only on source +\n * options and would otherwise be served forever, so the version is folded\n * into the key to invalidate them.\n */\nconst CACHE_VERSION = \"2\";\n\nexport async function getCacheKey(\n source: string,\n options: ResolvedHlsOptions,\n): Promise<string> {\n const sourceData = await readFile(source);\n\n return createHash(\"sha256\")\n .update(CACHE_VERSION)\n .update(sourceData)\n .update(JSON.stringify(options))\n .digest(\"hex\");\n}\n\nexport async function readCache(\n cacheRoot: string,\n key: string,\n): Promise<CachedHls | undefined> {\n const directory = join(cacheRoot, \"hls\", key);\n\n try {\n await stat(directory);\n } catch {\n return undefined;\n }\n\n const metadata = JSON.parse(\n await readFile(join(directory, \"manifest.json\"), \"utf8\"),\n ) as CacheManifest;\n\n const files = await collectFiles(directory);\n\n // manifest.json is internal bookkeeping, never an emitted asset.\n files.delete(\"manifest.json\");\n\n return {\n directoryName: metadata.directoryName,\n\n manifest: metadata.manifest,\n\n files,\n };\n}\n\nexport async function writeCache(\n cacheRoot: string,\n key: string,\n result: CachedHls,\n): Promise<void> {\n const temporaryDirectory = join(cacheRoot, \"hls\", `${key}.tmp`);\n\n const finalDirectory = join(cacheRoot, \"hls\", key);\n\n await rm(temporaryDirectory, {\n recursive: true,\n force: true,\n });\n\n await mkdir(temporaryDirectory, {\n recursive: true,\n });\n\n for (const [filename, data] of result.files) {\n const destination = join(temporaryDirectory, filename);\n\n await mkdir(resolve(destination, \"..\"), {\n recursive: true,\n });\n\n await writeFile(destination, data);\n }\n\n await writeFile(\n join(temporaryDirectory, \"manifest.json\"),\n JSON.stringify({\n directoryName: result.directoryName,\n manifest: result.manifest,\n } satisfies CacheManifest),\n \"utf8\",\n );\n\n await rm(finalDirectory, {\n recursive: true,\n force: true,\n });\n\n await rename(temporaryDirectory, finalDirectory);\n}\n","import { readFile, readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\n/**\n * Recursively collects every file under `directory` into a map of\n * directory-relative POSIX paths to their buffer contents.\n */\nexport async function collectFiles(\n directory: string,\n): Promise<Map<string, Buffer>> {\n const result = new Map<string, Buffer>();\n\n async function visit(current: string): Promise<void> {\n for (const entry of await readdir(current, { withFileTypes: true })) {\n const filename = join(current, entry.name);\n\n if (entry.isDirectory()) {\n await visit(filename);\n continue;\n }\n\n result.set(\n relative(directory, filename).replaceAll(\"\\\\\", \"/\"),\n await readFile(filename),\n );\n }\n }\n\n await visit(directory);\n\n return result;\n}\n","import { extname } from \"node:path\";\n\nimport { bitrateToNumber } from \"./bitrate\";\nimport type { HlsVariant } from \"./types\";\n\n/** Turns a filename into a filesystem-safe slug used for the output folder. */\nexport function slugify(filename: string): string {\n return (\n filename\n .replace(extname(filename), \"\")\n .replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .toLowerCase() || \"video\"\n );\n}\n\n/** Builds the adaptive master playlist pointing at each rendition. */\nexport function createMasterPlaylist(variants: readonly HlsVariant[]): string {\n const lines = [\"#EXTM3U\", \"#EXT-X-VERSION:7\"];\n\n for (const variant of variants) {\n // BANDWIDTH is an estimate derived from the configured bitrate.\n const bandwidth = Math.round(bitrateToNumber(variant.bitrate) * 1.15);\n\n lines.push(\n `#EXT-X-STREAM-INF:BANDWIDTH=${bandwidth}`,\n `${variant.height}p/index.m3u8`,\n );\n }\n\n return `${lines.join(\"\\n\")}\\n`;\n}\n","import type { PluginContext } from \"rolldown\";\n\nimport type { CachedHls, ResolvedHlsOptions } from \"./types\";\n\nexport function emitHls(\n context: PluginContext,\n result: CachedHls,\n options: ResolvedHlsOptions,\n): void {\n const prefix = `${options.outputDir}/${result.directoryName}`;\n\n const manifestSource = result.files.get(result.manifest);\n\n if (!manifestSource) {\n throw new Error(`[vite-plugin-hls] Missing manifest ${result.manifest}`);\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${result.manifest}`,\n source: manifestSource,\n });\n\n for (const [filename, data] of result.files) {\n if (filename === result.manifest) {\n continue;\n }\n\n context.emitFile({\n type: \"asset\",\n fileName: `${prefix}/${filename}`,\n source: data,\n });\n }\n}\n\nexport function publicManifestExpression(\n result: CachedHls,\n options: ResolvedHlsOptions,\n base: string,\n): string {\n const path = `${options.outputDir}/${result.directoryName}/${result.manifest}`;\n\n /*\n * Bake Vite's resolved base straight into the module. Vite does not always\n * statically replace import.meta.env.BASE_URL (e.g. in SSR bundles), where\n * import.meta.env is undefined at runtime and crashes. Emitting the base as\n * a plain string is equivalent and works for client and SSR alike.\n *\n * Examples (base -> export):\n *\n * \"/\" -> \"/assets/hls/...\"\n * \"/notes/\" -> \"/notes/assets/hls/...\"\n */\n return JSON.stringify(`${base}${path}`);\n}\n","import type { Plugin, ResolvedConfig } from \"vite\";\n\nimport { resolveOptions } from \"./options\";\nimport {\n isVideoSource,\n resolveVideoSource,\n sourceFromVirtualId,\n virtualIdForSource,\n} from \"./resolve\";\nimport { generateHls } from \"./hls\";\nimport { emitHls, publicManifestExpression } from \"./assets\";\nimport type { HlsPluginOptions } from \"./types\";\n\nconst VIRTUAL_PREFIX = \"\\0vite-plugin-hls:\";\n\nexport function hlsVideos(input?: HlsPluginOptions): Plugin {\n const options = resolveOptions(input);\n\n let config: ResolvedConfig;\n\n const resolvedSources = new Map<string, string>();\n\n /*\n * This only caches inside the current Vite build.\n *\n * The persistent cache in cache.ts handles the\n * client/server build boundary.\n */\n const generated = new Map<string, Awaited<ReturnType<typeof generateHls>>>();\n\n return {\n name: \"vite-plugin-hls\",\n\n apply: \"build\",\n\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved;\n },\n\n async resolveId(source, importer) {\n if (!importer || !isVideoSource(source)) {\n return undefined;\n }\n\n const resolved = await resolveVideoSource(source, importer, this);\n\n if (!resolved) {\n return undefined;\n }\n\n const id = virtualIdForSource(resolved);\n\n resolvedSources.set(id, resolved);\n\n return id;\n },\n\n async load(id, loadOptions) {\n if (!id.startsWith(VIRTUAL_PREFIX)) {\n return undefined;\n }\n\n const source = resolvedSources.get(id) ?? sourceFromVirtualId(id);\n\n let result = generated.get(source);\n\n if (!result) {\n result = await generateHls(source, config.cacheDir, options);\n\n generated.set(source, result);\n }\n\n /*\n * Important:\n *\n * The SSR build must NOT use Vite's emitted-file\n * URL because that resolves to a file:// URL.\n *\n * We only emit the actual files during the client\n * build. SSR receives the public URL directly.\n */\n if (!loadOptions?.ssr) {\n emitHls(this, result, options);\n }\n\n const manifest = publicManifestExpression(result, options, config.base);\n\n return `\n export default ${manifest};\n `;\n },\n };\n}\n","import { hlsVideos } from \"./plugin\";\n\nexport { hlsVideos };\nexport default hlsVideos;\n\nexport type { HlsPluginOptions, HlsVariant } from \"./types\";\n"],"mappings":"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","names":["extname","join","writeFile","mkdir","readFile","rm","join","join","readFile","join","rm","mkdir","extname","extname","extname","join","writeFile","VIRTUAL_PREFIX"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karsten_zhou/vite-plugin-hls",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Transcode video files to HLS (HTTP Live Streaming) at Vite build time.",
5
5
  "type": "module",
6
6
  "license": "MIT",