npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vpbox

v1.2.1

Published

Video encryption & HLS packaging toolkit (PBOX format) with TypeScript support

Readme

vpbox

视频加密与 HLS 打包工具包(PBOX 格式),TypeScript 实现。

把一个视频文件转成 AES 加密的 HLS 分片,打乱分片文件名,生成缩略图,最后把视频信息、密钥、m3u8、缩略图打包进一个用密码加密的 .pbox 容器;同样支持用密码解密还原。

特性

  • HLS 转封装:基于 ffmpeg,支持流复制与重编码、自定义分片时长、AES-128 加密
  • 分片名打乱:用 md5(uuid) 重命名每个分片,并生成新旧名称映射 map.json
  • 缩略图生成:ffmpeg 截图 + sharp 压缩,输出大图与小图
  • PBOX 容器:自研二进制格式,scrypt 派生密钥 + AES-256-GCM 认证加密
  • 视频信息探测:通过 ffprobe 获取分辨率、帧率、码率、编码等
  • 视频压缩:按上限阈值条件性重编码(分辨率 / 帧率 / 码率 / 编码)
  • 进度回调:HLS 转换与视频压缩均支持进度回调

环境依赖

  • Node.js >= 18
  • 系统已安装 ffmpeg 与 ffprobe,并在 PATH 中可用

安装

npm install vpbox

快速开始

import path from 'node:path';
import { setConfig, encrypt, decrypt, getVideoInfo } from 'vpbox';

// 可选:设置 m3u8 中分片的 base url 前缀
setConfig({
    M3U8_BASE_URL: 'https://example.com',
});
const input = path.resolve('input.mp4');

(async () => {
  // 1. 探测视频信息
  const videoInfo = await getVideoInfo(input);
  console.log(videoInfo);

  // 2. 加密打包
  const encrypted = await encrypt({
    inputPath: input,
    password: 'your-password',
    outputPath: path.resolve('temps'),
    hlsOptions: {
      hlsTime: 10,
      onProgress: (info) => console.log(`${info.percent ?? 0}%`),
    },
  });
  console.log(encrypted);

  // 3. 解密还原(不传 outputPath 时仅返回文件列表,不写盘)
  const decrypted = await decrypt({
    inputPath: path.resolve('temps', encrypted.path),
    password: 'your-password',
    // outputPath: path.resolve('outputs'),
  });
  console.log(decrypted);
})();

API

encrypt(options): Promise<AssemblePboxResult>

完整加密流程,内部依次执行:探测视频信息 → 生成 AES key → 转 HLS(带加密)→ 打乱分片名 → 生成缩略图 → 组装 .pbox。

| 参数 | 类型 | 说明 | | --- | --- | --- | | inputPath | string | 输入视频文件路径 | | password | string | PBOX 容器加密密码 | | outputPath | string | 输出目录 | | hlsOptions | Partial<ToHlsOptions> | HLS 转封装选项,见下表 |

返回值包含 hash、name、path、filename、videoInfo、thumbnail 等字段。

decrypt(options): Promise<PboxDecryptedFile[]>

解密 .pbox 文件。

| 参数 | 类型 | 说明 | | --- | --- | --- | | inputPath | string | .pbox 文件路径 | | password | string | 加密时使用的密码 | | outputPath | string(可选) | 输出目录;不传时仅返回文件列表,其中 m3u8/json 内容会转成字符串 |

getVideoInfo(inputPath): Promise<VideoInfo>

通过 ffprobe 获取视频信息,返回时长、宽高、帧率、码率、编码、像素格式等。

compressVideo(inputPath, options?): Promise<string>

按上限阈值条件性重编码压缩视频:分辨率、帧率、视频码率、视频编码任一不达标则重编码视频流;音频编码不一致或码率超标则重编码音频流;全部达标时直接返回原路径。仅重编码不达标的部分,避免无谓重写。

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | inputPath | string | — | 输入视频文件路径 | | options.maxWidth | number | 1080 | 最大宽度(像素),超过则等比缩小 | | options.maxHeight | number | 1080 | 最大高度(像素),超过则等比缩小 | | options.maxFrameRate | number | 60 | 最大帧率(fps),超过则降帧 | | options.maxVideoBitRate | number | 8000000 | 最大视频码率(bps),超过则限流重编码 | | options.allowedVideoCodecs | string[] | config.ALLOWED_VIDEO_CODECS | 允许的视频编码(小写),命中则视频流可走 copy | | options.outputVideoCodec | string | 'libx264' | 输出视频编码 | | options.crf | number | 23 | 重编码质量(CRF),值越小质量越高;仅在视频码率未超限时生效 | | options.preset | string | 'medium' | x264 编码预设,越慢压缩率越高 | | options.audioCodec | string | 'aac' | 输出音频编码 | | options.audioBitRate | string | '160k' | 输出音频码率;源码率更低时按源码率重编码 | | options.audioChannels | number | 2 | 输出音频声道数 | | options.outputFormat | string | 'mp4' | 输出容器格式(扩展名,如 mp4/avi/mkv/mov);mp4/m4v/mov 自动加 +faststart | | options.outputDir | string | 源文件所在目录 | 输出目录 | | options.onProgress | (p: CompressProgress) => void | — | 进度回调;源文件已满足要求直接返回时会回调一次 100% |

返回值为压缩后的视频文件路径(满足要求时为原路径)。

import { compressVideo } from 'vpbox';

const out = await compressVideo(inputPath, {
  maxWidth: 720,
  maxVideoBitRate: 2_000_000,
  outputFormat: 'mp4',
  onProgress: (p) => console.log(`${p.percent}% @ ${p.timemark}`),
});

setConfig(config) => void

全局可配置常量,直接修改即可生效:

import { setConfig } from 'vpbox';

setConfig({
    M3U8_BASE_URL: 'https://cdn.example.com/',
    THUMBNAIL_WIDTH: 320,
    THUMBNAIL_HEIGHT: 180,
});

| 字段 | 默认值 | 说明 | | --- | --- | --- | | ENC_NAME | enc.key | AES 加密 key 文件名 | | KEY_INFO_NAME | key_info | ffmpeg 用的 key_info 文件名 | | VIDEO_INFO_NAME | video.json | 视频信息 json 文件名 | | THUMBNAIL_NAME | thumbnail.jpg | 压缩后缩略图文件名 | | THUMBNAIL_BIG_NAME | thumbnail_big.jpg | 原始截图文件名 | | M3U8_NAME | index.m3u8 | m3u8 播放列表文件名 | | M3U8_BASE_URL | '' | m3u8 中分片的 base url 前缀 | | THUMBNAIL_TIMESTAMP | 1 | 截图时间点(秒) | | THUMBNAIL_FRAME | cover | sharp 缩放模式 | | THUMBNAIL_QUALITY | 60 | 缩略图压缩质量 1-100 | | THUMBNAIL_WIDTH | 210 | 缩略图宽度 | | THUMBNAIL_HEIGHT | 110 | 缩略图高度 |

HLS 选项(hlsOptions)

| 参数 | 类型 | 默认值 | 说明 | | --- | --- | --- | --- | | hlsTime | number | 30 | 每个分片时长(秒) | | playlistType | 'vod' \| 'event' | vod | 播放列表类型 | | segmentFilename | string | %05d | 分片文件名模板 | | baseUrl | string | — | m3u8 中分片的 base url | | hlsListSize | number | 0 | 播放列表条目数,0 为全部 | | copyStream | boolean | true | 是否使用流复制模式(-c copy) | | onProgress | (p: HlsProgress) => void | — | 进度回调 |

PBOX 文件格式

二进制布局:

MAGIC(4) | VERSION(1) | SALT(16) | NONCE(12) | CIPHERTEXT | AUTH_TAG(16)
  • MAGIC:固定字符串 PBOX
  • VERSION:版本号,当前为 1
  • SALT:16 字节随机盐
  • NONCE:12 字节随机 nonce
  • CIPHERTEXT:AES-256-GCM 加密后的明文(JSON 数组,每项含 name 与 base64 编码的 data)
  • AUTH_TAG:16 字节 GCM 认证标签

密钥派生:scrypt(password, salt, 32),参数 N=16384, r=8, p=1。

构建

npm run build     # 使用 tsup 构建
npm run dev       # 通过 tsx 运行 example.ts

License

ISC