@ctrl/torrent-file

中文文档
4.5.2发布于 2026/10/05MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 8678

Parse a torrent file (name, hash, files, pieces)

原始使用文档
文档目录12 节
  1. Install
  2. API
  3. info(file)
  4. files(file)
  5. hash(file)
  6. hashV2(file)
  7. hashes(file)
  8. Low-level bencode
  9. Encode
  10. Validation scope
  11. Demo
  12. Specifications and related projects

torrent-file npm

Parse, inspect, and encode BitTorrent metainfo files.

Supports BitTorrent v1 (BEP 3), v2 (BEP 52), and hybrid torrent files containing both formats.

This project is based on parse-torrent and node-bencode. It includes a strict bencode encoder and decoder built around Uint8Array rather than Node.js Buffer.

Demo: https://torrent-file.pages.dev

Install

npm install @ctrl/torrent-file

API

info(file)

Returns display metadata, trackers, web seeds, and the detected version: 'v1', 'v2', or 'hybrid'.

import fs from 'fs';

import { info } from '@ctrl/torrent-file';

const torrentInfo = info(fs.readFileSync('myfile'));
console.log({ torrentInfo });

files(file)

Returns file and piece information:

  • length is the sum of the listed file lengths.
  • offset is the file's byte offset in the protocol piece space. BEP 52 aligns every non-empty v2 file to a piece boundary, so v2 offsets can contain gaps that are not included in length.
  • pieces contains hexadecimal SHA-1 hashes for v1/hybrid torrents and is absent for v2-only torrents.
  • piecesRoot is a hexadecimal SHA-256 Merkle root on v2/hybrid files.
  • pieceLayers maps hexadecimal pieces roots to arrays of hexadecimal SHA-256 hashes.

Paths use the host platform's path separator. For v2 torrents, the advisory torrent name is prepended to the paths returned from the BEP 52 file tree.

import fs from 'fs';

import { files } from '@ctrl/torrent-file';

const torrentFiles = files(fs.readFileSync('myfile'));
console.log({ torrentFiles });

hash(file)

Returns the v1 SHA-1 info hash. It throws for a v2-only torrent because that torrent does not have a v1 identity.

import fs from 'fs';

import { hash } from '@ctrl/torrent-file';

const torrentHash = hash(fs.readFileSync('myfile'));
console.log({ torrentHash });

hashV2(file)

Returns the full 32-byte v2 SHA-256 info hash as hexadecimal. It throws for a v1-only torrent.

import fs from 'fs';

import { hashV2 } from '@ctrl/torrent-file';

const torrentHashV2 = hashV2(fs.readFileSync('myfile'));
console.log({ torrentHashV2 });

hashes(file)

Returns the available v1 (SHA-1) and v2 (SHA-256) info hashes along with the detected torrent version. infoHash is present for v1 and hybrid torrents; infoHashV2 is present for v2 and hybrid torrents.

import fs from 'fs';

import { hashes } from '@ctrl/torrent-file';

const h = hashes(fs.readFileSync('myfile'));
console.log(h.version); // 'v1', 'v2', or 'hybrid'
console.log(h.infoHash); // SHA-1 (v1/hybrid only)
console.log(h.infoHashV2); // SHA-256 (v2/hybrid only)

Info hashes are computed from the exact bencoded info dictionary bytes found in the file, as required by BEP 3 and BEP 52. They are not computed from a decode/encode round trip.

Low-level bencode

decode() returns bencoded byte strings as Uint8Array, including byte strings used as dictionary values. Decoded dictionaries have a null prototype, so keys such as __proto__, constructor, and toString are ordinary own properties rather than inherited JavaScript behavior. encode() accepts strings, Uint8Array, safe integers, arrays, and dictionaries.

The decoder rejects noncanonical or incomplete bencode, including unordered/duplicate dictionary keys, leading-zero integers, negative zero, unsafe integers, truncated values, and trailing data. The higher-level parsing and hashing functions use the same strict decoder and therefore throw on malformed input.

Dictionary keys can be arbitrary bytes. Decoded dictionaries retain enough internal information for encode(decode(data)) to preserve binary keys such as BEP 52 pieces roots. Newly constructed textual dictionary keys are UTF-8 encoded.

Encode

Convert a parsed torrent object back into a .torrent file buffer.

import fs from 'fs';

import { toTorrentFile } from '@ctrl/torrent-file';

// Minimal example: create a .torrent buffer from fields
const buf = toTorrentFile({
  info: {
    // Required info fields
    'piece length': 16384,
    pieces: new Uint8Array(/* 20-byte SHA1 hashes concatenated */),
    name: 'example.txt',
    length: 12345,
  },
  // Optional fields
  announce: ['udp://tracker.publicbt.com:80/announce'],
  urlList: ['https://example.com/example.txt'],
  private: false,
  created: new Date(),
  createdBy: 'my-app/1.0.0',
  comment: 'Generated by @ctrl/torrent-file',
});

fs.writeFileSync('example.torrent', buf);

toTorrentFile() serializes supplied metadata; it does not read file contents, calculate piece hashes, build v2 Merkle trees, or insert hybrid padding files.

For v2 pieceLayers, dictionary keys are raw 32-byte pieces roots rather than hexadecimal text. When constructing them manually, represent each byte with one JavaScript character:

const rawDictionaryKey = (bytes: Uint8Array) => String.fromCharCode(...bytes);

const buf = toTorrentFile({
  info: v2Info,
  pieceLayers: {
    [rawDictionaryKey(piecesRoot)]: concatenatedLayerHashes,
  },
});

The pieceLayers returned by files() is a display-friendly hexadecimal representation and is not the raw input shape accepted by toTorrentFile().

Validation scope

The parser validates canonical bencoding and the v1/v2 file-information structure it consumes, including v2 metadata version, piece size, file-tree shape, file lengths, pieces roots, and hash byte lengths.

It does not recompute file hashes, cryptographically verify piece layers against Merkle roots, or prove that the v1 and v2 sides of a hybrid torrent describe identical content. Applications downloading or trusting content must perform those integrity checks separately.

Demo

Run a local demo UI to drop a .torrent file and view parsed output:

pnpm install
pnpm demo:watch

To build the demo for static hosting:

pnpm demo:build

版本与发布记录

@ctrl/torrent-file 共发布 24 个版本,首次发布于 2019/05/19;过去 12 个月发布了 3 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
4.5.2latest2026/10/051 个月前
4.5.12026/07/133 个月前
4.5.02026/02/178 个月前
4.4.02025/10/061.1 年前
4.3.02025/10/061.1 年前
4.2.02025/09/161.1 年前

关于 @ctrl/torrent-file 的常见问题

@ctrl/torrent-file 是什么?

Parse a torrent file (name, hash, files, pieces)

如何安装 @ctrl/torrent-file?

在项目目录运行 npm install @ctrl/torrent-file,或使用 pnpm add / yarn add / bun add。

@ctrl/torrent-file 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@ctrl/torrent-file 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@ctrl/torrent-file 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@ctrl/torrent-file 可以商用吗?

@ctrl/torrent-file 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@ctrl/torrent-file 的下载量有多少?

根据 npm 官方下载统计,@ctrl/torrent-file 在 2026/10/11 – 2026/11/09 这 30 天内被下载 8,678 次,日均约 289 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@ctrl/torrent-file 还在维护吗?

最新版本 4.5.2 发布于 2026/10/05(1 个月前);至今共发布 24 个版本,其中过去 12 个月发布了 3 个;首次发布于 2019/05/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。