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

@logosw/hls-downloader

v1.1.0

Published

随时随地下载你喜爱的任何 HLS 视频流。Downloads HLS stream whatever and wherever you want.

Downloads

334

Readme

HLS Downloader

随时随地下载你喜爱的任何 HLS 视频流。Downloads HLS stream whatever and wherever you want.

npm version npm downloads License: MIT Node.js GitHub


用于解析 HLS(.m3u8)并下载、合并为可播放文件的 TypeScript 库。通过 **HlsDownloader** 统一入口,按运行环境选择适配器:

  • 浏览器@hls-downloader/adapters/wasm(FFmpeg WASM)
  • Node.js@hls-downloader/adapters/rust(Rust N-API 原生实现,性能与路径处理更适合服务端)

安装

方式一:聚合包 @logosw/hls-downloader(推荐) — 一次安装即可使用与 @hls-downloader/* 相同的 API,子路径与独立子包一一对应:

pnpm add @logosw/hls-downloader

方式二:按需安装子包(减小依赖面或只引用部分能力时):

pnpm add @hls-downloader/core @hls-downloader/shared
# 按需二选一(通常与运行环境一致)
pnpm add @hls-downloader/adapters   # 再通过子路径导入 wasm 或 rust,见下文

@logosw/hls-downloader 依赖 @hls-downloader/core@hls-downloader/shared@hls-downloader/adapters@hls-downloader/core 已依赖 @hls-downloader/shared。使用适配器时(聚合包或独立安装)均需能解析到 **@hls-downloader/adapters** 中的 wasm/rust 实现。

运行环境:Node.js ≥ 20(与 core 及聚合包根 engines 一致)。Rust 适配器在 Node 下会加载 原生 .node 模块,需使用与你平台、Node ABI 匹配的发布产物;若在浏览器打包,请只打包 WASM 子路径,不要把 Node 原生模块打进前端。

基本用法

// 也可:import { HlsDownloader, HlsDownloaderEvent, WasmAdapter } from '@logosw/hls-downloader';
import { HlsDownloader } from '@hls-downloader/core';
import { HlsDownloaderEvent } from '@hls-downloader/shared';
import { WasmAdapter } from '@hls-downloader/adapters/wasm';

const downloader = new HlsDownloader({
  adapter: WasmAdapter,
  option: {
    // 可选:与适配器相关的额外选项,见下文
  },
  onEvent: (event, progress) => {
    if (
      event === HlsDownloaderEvent.DOWNLOADING_SEGMENTS ||
      event === HlsDownloaderEvent.STICHING_SEGMENTS
    ) {
      console.log(progress?.completed, '/', progress?.total);
    }
  },
});

// 下载前必须先 init(WASM 会在此加载 FFmpeg)
await downloader.init();

// 仅解析主/子 playlist,不下载分片
const parsed = await downloader.parseHls({
  url: 'https://example.com/master.m3u8',
  headers: { Authorization: 'Bearer ...' },
});

// 解析并下载合并(filename 等见类型 HlsDownloaderDownloadOption)
const result = await downloader.download({
  url: 'https://example.com/stream.m3u8',
  headers: {},
  filename: 'output.mp4',
});

if (result) {
  // result.blobURL:浏览器侧多为 blob: URL,可用于 <a download> 或创建 Object URL
  console.log(result.totalSegments);
}

// 尝试从流中取封面图 URL(若有)
const poster = await downloader.getPosterUrl({ url: '...' });

Node 侧将 WasmAdapter 换成 RustAdapter 即可,构造方式相同:

import { RustAdapter } from '@hls-downloader/adapters/rust';

const downloader = new HlsDownloader({ adapter: RustAdapter, onEvent: ... });
await downloader.init();

HlsDownloader API 摘要

| 成员 | 说明 | | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | constructor({ adapter, option?, onEvent? }) | option 为「默认请求选项 + 当前适配器专有选项」,会与每次 parseHls / download 传入的 url/headers 等合并 | | init() | 初始化适配器(WASM 会加载 FFmpeg;未完成前勿并发多次下载) | | isInit | 是否已完成初始化 | | setOption(option) | 更新默认选项(不含单次请求的 url) | | parseHls({ url, headers? }) | 返回 ParseHlsResult:主列表 playlist、媒体列表 segmenterror | | download({ url, headers?, filename?, maxRetry?, downloadConcurrency? }) | 下载并合并;成功时返回 { blobURL, totalSegments }(具体语义以适配器实现为准) | | getPosterUrl({ url, headers? }) | 返回封面 URL 字符串,若无则 undefined |

事件 HlsDownloaderEvent

包括但不限于:FFMPEG_LOADING / FFMPEG_LOADEDSTARTING_DOWNLOADSOURCE_PARSEDDOWNLOADINGDOWNLOADING_SEGMENTSSTICHING_SEGMENTS(后两者回调中带 { total, completed })、READY_FOR_DOWNLOADERROR。在 onEvent 中按需监听即可。

WASM 适配器专有选项(init / 构造时的 option

在类型 HlsDownloaderWasmAdapter 上,常见项包括:

  • coreURL / wasmURL / workerURL:自定义 FFmpeg 核心资源地址(默认构建时指向 CDN 上的 UMD 资源)
  • useESM:为 true 时从 CDN 的 esm/ 路径加载 FFmpeg(适合 Vite 等需要 ESM 资源的场景);省略或为 false使用 umd/ 路径(默认)。
  • disableMultiThread:为 true 时使用单线程 FFmpeg 变体(不加载 worker)

类型与扩展

高级用法可从 @hls-downloader/shared 引用 ParseHlsResultHlsDownloaderFetchOptionHlsDownloaderDownloadOptionPlaylistSegment 等。若需自定义适配器,需实现 HlsDownloaderAdapterInternal 并通过 createAdapter 包装后交给 HlsDownloader(与内置适配器相同模式)。

合规

请仅处理您有权访问的流地址,并遵守来源站点条款与适用法律。

许可证

MIT


A TypeScript library for parsing HLS (.m3u8) playlists and downloading/merging streams into playable files. Use the **HlsDownloader** facade and pick an adapter for your runtime:

  • Browser: @hls-downloader/adapters/wasm (FFmpeg WASM)
  • Node.js: @hls-downloader/adapters/rust (Rust N-API; better fit for servers and path handling)

Installation

Option A — umbrella package @logosw/hls-downloader (recommended): one install exposes the same APIs as the scoped packages, with subpaths mirroring @hls-downloader/*:

pnpm add @logosw/hls-downloader

Option B — granular packages (smaller install surface):

pnpm add @hls-downloader/core @hls-downloader/shared
pnpm add @hls-downloader/adapters

The @logosw/hls-downloader package depends on @hls-downloader/core, @hls-downloader/shared, and @hls-downloader/adapters. @hls-downloader/core depends on @hls-downloader/shared. For adapters, the wasm/rust implementations must resolve (via the umbrella or explicit @hls-downloader/adapters).

Runtime: Node.js ≥ 20 (matches engines on core and the root package). The Rust adapter loads a native .node addon on Node—use a build that matches your platform and Node ABI. For browser bundles, only include the WASM subpath; do not bundle the Node native addon into frontend code.

Packages and subpaths

| Package / entry | Role | | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | @logosw/hls-downloader | Umbrella: default export HlsDownloader, re-exports shared, WASM/Rust adapters (same as installing scoped packages) | | @logosw/hls-downloader/core | Same as @hls-downloader/core | | @logosw/hls-downloader/shared | Same as @hls-downloader/shared | | @logosw/hls-downloader/adapters, .../wasm, .../rust | Same as @hls-downloader/adapters and subpaths | | @hls-downloader/core | HlsDownloader class | | @hls-downloader/shared | Types, HlsDownloaderEvent, createAdapter, etc. (pulled in via core/adapters) | | @hls-downloader/adapters/wasm | Browser adapter WasmAdapter | | @hls-downloader/adapters/rust | Node adapter RustAdapter |

Basic usage

// Or: import { HlsDownloader, HlsDownloaderEvent, WasmAdapter } from '@logosw/hls-downloader';
import { HlsDownloader } from '@hls-downloader/core';
import { HlsDownloaderEvent } from '@hls-downloader/shared';
import { WasmAdapter } from '@hls-downloader/adapters/wasm';

const downloader = new HlsDownloader({
  adapter: WasmAdapter,
  option: {
    // Optional: adapter-specific options (see below)
  },
  onEvent: (event, progress) => {
    if (
      event === HlsDownloaderEvent.DOWNLOADING_SEGMENTS ||
      event === HlsDownloaderEvent.STICHING_SEGMENTS
    ) {
      console.log(progress?.completed, '/', progress?.total);
    }
  },
});

// Must call init before download (WASM loads FFmpeg here)
await downloader.init();

// Parse master/media playlist only; does not fetch segments
const parsed = await downloader.parseHls({
  url: 'https://example.com/master.m3u8',
  headers: { Authorization: 'Bearer ...' },
});

// Parse, fetch, and merge (filename etc.: see HlsDownloaderDownloadOption)
const result = await downloader.download({
  url: 'https://example.com/stream.m3u8',
  headers: {},
  filename: 'output.mp4',
});

if (result) {
  // result.blobURL: often a blob: URL in the browser; use with <a download> or Object URL
  console.log(result.totalSegments);
}

// Try to get a poster image URL from the stream, if present
const poster = await downloader.getPosterUrl({ url: '...' });

On Node, swap WasmAdapter for RustAdapter; construction is the same:

import { RustAdapter } from '@hls-downloader/adapters/rust';

const downloader = new HlsDownloader({ adapter: RustAdapter, onEvent: ... });
await downloader.init();

HlsDownloader API overview

| Member | Description | | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | constructor({ adapter, option?, onEvent? }) | option holds default fetch options plus adapter-specific options; merged with each parseHls / download call | | init() | Initialize the adapter (WASM loads FFmpeg; avoid overlapping heavy downloads before init completes) | | isInit | Whether initialization finished | | setOption(option) | Update defaults (per-call url is not stored here) | | parseHls({ url, headers? }) | Returns ParseHlsResult: playlist, segment, or error | | download({ url, headers?, filename?, maxRetry?, downloadConcurrency? }) | Download and merge; on success returns { blobURL, totalSegments } (exact semantics depend on the adapter) | | getPosterUrl({ url, headers? }) | Poster URL string, or undefined |

HlsDownloaderEvent values

Includes (not limited to): FFMPEG_LOADING / FFMPEG_LOADED, STARTING_DOWNLOAD, SOURCE_PARSED, DOWNLOADING, DOWNLOADING_SEGMENTS, STICHING_SEGMENTS (the last two pass { total, completed }), READY_FOR_DOWNLOAD, ERROR. Handle them in onEvent as needed.

WASM-only options (init / constructor option)

On HlsDownloaderWasmAdapter, common fields include:

  • coreURL / wasmURL / workerURL: override FFmpeg asset URLs (default builds point at UMD assets on a CDN)
  • useESM: when true, load FFmpeg from the CDN esm/ paths (e.g. Vite); when omitted or false, use umd/ paths (default).
  • disableMultiThread: if true, use the single-thread FFmpeg build (no worker)

Types and extensions

Import ParseHlsResult, HlsDownloaderFetchOption, HlsDownloaderDownloadOption, Playlist, Segment, etc. from @hls-downloader/shared. For a custom adapter, implement HlsDownloaderAdapterInternal, wrap with createAdapter, and pass it to HlsDownloader (same pattern as built-ins).

Compliance

Only use streams you are allowed to access, and follow the source site’s terms and applicable law.

License

MIT.