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 🙏

© 2025 – Pkg Stats / Ryan Hefner

magnetizer

v3.1.0

Published

Library for decoding and encoding magnet links

Readme

Magnetizer

ci Coverage Status npm version NPM Downloads TypeScript NPM License

A powerful TypeScript library for decoding and encoding magnet links.

Features

  • Zero dependencies - Lightweight and self-contained
  • TypeScript-first - Full type definitions included
  • Dual module support - Works with both ESM and CommonJS
  • BitTorrent v1 & v2 - Supports both btih and btmh hash types
  • Multiple hash types - SHA-1, MD5, eDonkey 2000, and more
  • Base32 & hex support - Automatic format detection and conversion
  • URL encoding/decoding - Handles special characters automatically
  • 100% test coverage - Thoroughly tested and reliable

Table of Contents


Installation

npm install magnetizer
yarn add magnetizer
pnpm add magnetizer

Quick Start

import { decode, encode } from 'magnetizer';

// Decode a magnet link
const result = decode('magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&dn=example');
console.log(result.displayName);  // 'example'

// Access structured info hash data
console.log(result.infoHashData[0].type);   // 'btih'
console.log(result.infoHashData[0].value);  // 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a'
console.log(result.infoHashData[0].urn);    // 'urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'

// Encode a magnet link
const magnetLink = encode({
  displayName: 'example',
  infoHashData: [{
    type: 'btih',
    value: 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a',
    urn: 'urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'
  }],
  trackers: ['udp://tracker.example.com:80']
});
console.log(magnetLink);
// 'magnet:?dn=example&xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&tr=udp%3A%2F%2Ftracker.example.com%3A80'

API Reference

decode(magnetURI: string): IMagnetURI

Parses a magnet link string into a structured object.

Examples

Basic decoding:

import { decode } from 'magnetizer';

const result = decode('magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a');

console.log(result);
// {
//   displayName: null,
//   length: null,
//   infoHashes: ['urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'],
//   infoHashData: [{
//     type: 'btih',
//     value: 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a',
//     urn: 'urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'
//   }],
//   webSeeds: [],
//   acceptableSources: [],
//   sources: [],
//   keywords: [],
//   manifest: null,
//   trackers: []
// }

// Access the raw hash value directly (no string parsing needed)
console.log(result.infoHashData[0].value);  // 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a'

Decoding with display name and trackers:

const magnetLink = 'magnet:?dn=Ubuntu%2024.04%20LTS&xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&tr=udp%3A%2F%2Ftracker.example.com%3A80&tr=wss%3A%2F%2Ftracker.webtorrent.io';

const result = decode(magnetLink);

console.log(result.displayName);  // 'Ubuntu 24.04 LTS'
console.log(result.trackers);
// [
//   'udp://tracker.example.com:80',
//   'wss://tracker.webtorrent.io'
// ]

Base32 hashes (auto-converted to hex):

// Base32 encoded hash (32 characters)
const result = decode('magnet:?xt=urn:btih:QHQXPYWMACKDWKP47RRVIV7VOURXFE5Q');

console.log(result.infoHashes);
// ['urn:btih:81e177e2cc00943b29fcfc635457f575237293b0']
// Note: Base32 is automatically converted to lowercase hex

Multiple hash types:

const magnetLink = 'magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&xt=urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709';

const result = decode(magnetLink);

console.log(result.infoHashes);
// [
//   'urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a',
//   'urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709'
// ]

Handling invalid input:

// Empty or invalid strings return default empty object
const result = decode('');
console.log(result.infoHashes);  // []

// Invalid hashes are silently ignored
const result2 = decode('magnet:?xt=urn:btih:invalid');
console.log(result2.infoHashes);  // []

// Non-URN format is ignored
const result3 = decode('magnet:?xt=btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a');
console.log(result3.infoHashes);  // [] (missing 'urn:' prefix)

encode(data: Partial<IMagnetURI>): string

Builds a magnet link string from a structured object.

Examples

Basic encoding with hash only:

import { encode } from 'magnetizer';

const magnetLink = encode({
  infoHashes: ['c12fe1c06bba254a9dc9f519b335aa7c1367a88a']
});

console.log(magnetLink);
// 'magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'

Full object with all fields:

const magnetLink = encode({
  displayName: 'example-file.tar.gz',
  length: 1048576,
  infoHashes: ['c12fe1c06bba254a9dc9f519b335aa7c1367a88a'],
  trackers: [
    'udp://tracker.example.com:80',
    'wss://tracker.webtorrent.io'
  ],
  webSeeds: ['https://example.com/files/example-file.tar.gz'],
  acceptableSources: ['https://mirror.example.com/example-file.tar.gz'],
  sources: ['http://cache.example.com/c12fe1c06bba254a9dc9f519b335aa7c1367a88a'],
  keywords: ['example', 'archive', 'tar'],
  manifest: 'https://example.com/manifest.rss'
});

console.log(magnetLink);
// 'magnet:?dn=example-file.tar.gz&xl=1048576&xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&tr=udp%3A%2F%2Ftracker.example.com%3A80&tr=wss%3A%2F%2Ftracker.webtorrent.io&kt=example+archive+tar&ws=https%3A%2F%2Fexample.com%2Ffiles%2Fexample-file.tar.gz&as=https%3A%2F%2Fmirror.example.com%2Fexample-file.tar.gz&xs=http%3A%2F%2Fcache.example.com%2Fc12fe1c06bba254a9dc9f519b335aa7c1367a88a&mt=https%3A%2F%2Fexample.com%2Fmanifest.rss'

Using Uint8Array/Buffer for hashes:

// From hex string to Uint8Array
const hashBytes = new Uint8Array([
  0xc1, 0x2f, 0xe1, 0xc0, 0x6b, 0xba, 0x25, 0x4a,
  0x9d, 0xc9, 0xf5, 0x19, 0xb3, 0x35, 0xaa, 0x7c,
  0x13, 0x67, 0xa8, 0x8a
]);

const magnetLink = encode({
  infoHashes: [hashBytes]
});

console.log(magnetLink);
// 'magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'

Multiple info hashes:

const magnetLink = encode({
  infoHashes: [
    'urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a',
    'urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709',
    'urn:md5:d41d8cd98f00b204e9800998ecf8427e'
  ]
});

console.log(magnetLink);
// 'magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&xt=urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709&xt=urn:md5:d41d8cd98f00b204e9800998ecf8427e'

Different hash type URNs:

// Plain hex defaults to btih
encode({ infoHashes: ['c12fe1c06bba254a9dc9f519b335aa7c1367a88a'] });
// Result: xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a

// Explicit URN prefix is preserved
encode({ infoHashes: ['urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709'] });
// Result: xt=urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709

encode({ infoHashes: ['urn:ed2k:31d6cfe0d16ae931b73c59d7e0c089c0'] });
// Result: xt=urn:ed2k:31d6cfe0d16ae931b73c59d7e0c089c0

IMagnetURI Interface

| Property | Type | Magnet Param | Description | |----------|------|--------------|-------------| | displayName | string \| null | dn | Human-readable filename | | length | number \| null | xl | Exact file size in bytes | | infoHashData | IInfoHashData[] | xt | Structured info hash data | | infoHashes | Array<string \| Uint8Array> | xt | URN containing file hash(es) (deprecated, use infoHashData) | | webSeeds | string[] | ws | HTTP/HTTPS download URLs | | acceptableSources | string[] | as | Alternative web download sources | | sources | string[] | xs | P2P source links (by content-hash) | | keywords | string[] | kt | Search keywords | | manifest | string \| null | mt | Link to metafile (e.g., RSS feed) | | trackers | string[] | tr | BitTorrent tracker URLs |

IInfoHashData Interface

| Property | Type | Description | |----------|------|-------------| | type | string | Hash type identifier (btih, btmh, sha1, md5, ed2k) | | value | string | Raw hexadecimal hash value (lowercase) | | urn | string | Complete URN string (e.g., urn:btih:c12fe1c0...) |

Supported Hash Types

| Hash Type | URN Prefix | Hex Length | Base32 Support | Description | |-----------|------------|------------|----------------|-------------| | BitTorrent v1 | urn:btih: | 40 chars | Yes (32 chars) | SHA-1 hash of torrent info dictionary | | BitTorrent v2 | urn:btmh: | 68 chars | No | Multihash (1220 prefix + SHA-256) | | SHA-1 | urn:sha1: | 40 chars | Yes (32 chars) | Generic SHA-1 file hash | | MD5 | urn:md5: | 32 chars | No | MD5 file hash | | eDonkey 2000 | urn:ed2k: | 32 chars | No | eDonkey/eMule network hash |

Hash Format Examples

BitTorrent v1 (hex):    urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a
BitTorrent v1 (base32): urn:btih:QHQXPYWMACKDWKP47RRVIV7VOURXFE5Q
BitTorrent v2:          urn:btmh:1220caf1e1c30e81cb361b9ee167c4aa411dfc88b7eb23e726d4451376f351009414
SHA-1:                  urn:sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709
MD5:                    urn:md5:d41d8cd98f00b204e9800998ecf8427e
eDonkey 2000:           urn:ed2k:31d6cfe0d16ae931b73c59d7e0c089c0

Advanced Usage

Multiple Info Hashes

Torrents can include multiple hash types for cross-network compatibility:

import { decode, encode } from 'magnetizer';

// Decode a magnet link with multiple hashes
const result = decode(
  'magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a' +
  '&xt=urn:ed2k:31d6cfe0d16ae931b73c59d7e0c089c0'
);

// Access structured data for each hash
console.log(result.infoHashData);
// [
//   { type: 'btih', value: 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a', urn: 'urn:btih:...' },
//   { type: 'ed2k', value: '31d6cfe0d16ae931b73c59d7e0c089c0', urn: 'urn:ed2k:...' }
// ]

// Filter by hash type
const btihHash = result.infoHashData.find(h => h.type === 'btih');
console.log(btihHash?.value);  // 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a'

BitTorrent v2 Hybrid Torrents

BitTorrent v2 uses SHA-256 hashes with a multihash prefix. Hybrid torrents include both v1 and v2 hashes:

const hybridMagnet = encode({
  displayName: 'hybrid-torrent',
  infoHashData: [
    {
      type: 'btih',
      value: 'c12fe1c06bba254a9dc9f519b335aa7c1367a88a',
      urn: 'urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'
    },
    {
      type: 'btmh',
      value: '1220caf1e1c30e81cb361b9ee167c4aa411dfc88b7eb23e726d4451376f351009414',
      urn: 'urn:btmh:1220caf1e1c30e81cb361b9ee167c4aa411dfc88b7eb23e726d4451376f351009414'
    }
  ]
});

// Both old and new clients can use this magnet link

Using Uint8Array for Hashes

The encoder accepts binary hash data as Uint8Array:

// Convert hex string to bytes
function hexToBytes(hex: string): Uint8Array {
  const bytes = new Uint8Array(hex.length / 2);
  for (let i = 0; i < hex.length; i += 2) {
    bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
  }
  return bytes;
}

const hashBytes = hexToBytes('c12fe1c06bba254a9dc9f519b335aa7c1367a88a');

const magnetLink = encode({
  infoHashes: [hashBytes]
});
// Result: 'magnet:?xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a'

Round-Trip Preservation

Data is preserved through decode/encode cycles:

const original = 'magnet:?dn=test&xt=urn:btih:c12fe1c06bba254a9dc9f519b335aa7c1367a88a&tr=udp%3A%2F%2Ftracker.example.com%3A80';

const decoded = decode(original);
const reencoded = encode(decoded);

// Note: Parameter order may differ, but data is equivalent
console.log(decode(reencoded));
// Same structured data as decode(original)

Compatibility

| Runtime | Support | |---------|---------| | Node.js | v14+ (ES2020) | | Deno | Full ESM support | | Bun | Native TypeScript support | | Browser | Modern browsers (ES2020) |

Module Formats

  • ESM: import { decode, encode } from 'magnetizer'
  • CommonJS: const { decode, encode } = require('magnetizer')

Development

# Clone the repository
git clone https://github.com/isolomak/magnetizer.git
cd magnetizer

# Install dependencies
npm install

# Build (compiles to lib/)
npm run build

# Run tests (100% coverage required)
npm test

# Run linting
npm run lint

License

This project is licensed under the MIT License - see the LICENSE file for details.