magnetizer
v3.1.0
Published
Library for decoding and encoding magnet links
Maintainers
Readme
Magnetizer
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
btihandbtmhhash 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
- Quick Start
- API Reference
- Supported Hash Types
- Advanced Usage
- Compatibility
- Development
- License
Installation
npm install magnetizeryarn add magnetizerpnpm add magnetizerQuick 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 hexMultiple 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:31d6cfe0d16ae931b73c59d7e0c089c0IMagnetURI 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:31d6cfe0d16ae931b73c59d7e0c089c0Advanced 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 linkUsing 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 lintLicense
This project is licensed under the MIT License - see the LICENSE file for details.
