@ctrl/magnet-link 2.0.4 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.d.ts → src/index.d.ts} +1 -1
- package/dist/{module → src}/index.js +4 -1
- package/package.json +39 -44
- package/dist/index.js +0 -145
@@ -7,7 +7,7 @@ export interface MagnetData {
|
|
7
7
|
* Is the multihash formatted, hex encoded full infohash for torrents in the new metadata format. 'btmh' and 'btih' exact topics may exist in the same magnet if they describe the same hybrid torrent.
|
8
8
|
* @link http://www.bittorrent.org/beps/bep_0009.html
|
9
9
|
*/
|
10
|
-
xt
|
10
|
+
xt?: string | string[];
|
11
11
|
/**
|
12
12
|
* Parsed xt= parameter see xt
|
13
13
|
*/
|
@@ -23,9 +23,12 @@ export function magnetDecode(uri) {
|
|
23
23
|
}
|
24
24
|
// If there are repeated parameters, return an array of values
|
25
25
|
if (r && Array.isArray(r)) {
|
26
|
-
|
26
|
+
r.push(val);
|
27
|
+
return;
|
27
28
|
}
|
28
29
|
result[key] = [r, val];
|
30
|
+
// eslint-disable-next-line no-useless-return
|
31
|
+
return;
|
29
32
|
});
|
30
33
|
if (result.xt) {
|
31
34
|
let m;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ctrl/magnet-link",
|
3
|
-
"version": "
|
3
|
+
"version": "3.0.0",
|
4
4
|
"description": "Parse a magnet URI into an object",
|
5
5
|
"author": "Scott Cooper <scttcper@gmail.com>",
|
6
6
|
"homepage": "https://magnet-link.vercel.app",
|
@@ -12,63 +12,58 @@
|
|
12
12
|
"link",
|
13
13
|
"magnet-uri"
|
14
14
|
],
|
15
|
-
"
|
16
|
-
"
|
17
|
-
"
|
15
|
+
"type": "module",
|
16
|
+
"exports": "./dist/src/index.js",
|
17
|
+
"types": "./dist/src/index.d.ts",
|
18
18
|
"files": [
|
19
|
-
"dist"
|
19
|
+
"dist/src"
|
20
20
|
],
|
21
21
|
"sideEffects": false,
|
22
|
-
"publishConfig": {
|
23
|
-
"access": "public"
|
24
|
-
},
|
25
22
|
"scripts": {
|
26
|
-
"build
|
27
|
-
"watch
|
28
|
-
"lint": "eslint --ext .
|
29
|
-
"lint:fix": "eslint --fix --ext .
|
23
|
+
"demo:build": "npm run build --workspace=demo",
|
24
|
+
"demo:watch": "npm run dev --workspace=demo",
|
25
|
+
"lint": "eslint --ext .ts .",
|
26
|
+
"lint:fix": "eslint --fix --ext .ts .",
|
30
27
|
"prepare": "npm run build",
|
31
|
-
"build": "tsc
|
32
|
-
"test": "
|
33
|
-
"test:watch": "
|
34
|
-
"test:ci": "
|
28
|
+
"build": "tsc",
|
29
|
+
"test": "ava",
|
30
|
+
"test:watch": "ava --watch",
|
31
|
+
"test:ci": "c8 --reporter=text --reporter=lcov ava"
|
35
32
|
},
|
36
33
|
"dependencies": {
|
37
|
-
"@ctrl/ts-base32": "^1.
|
34
|
+
"@ctrl/ts-base32": "^2.1.1"
|
38
35
|
},
|
39
36
|
"devDependencies": {
|
40
|
-
"@
|
41
|
-
"@
|
42
|
-
"@
|
43
|
-
"
|
44
|
-
"@rollup/plugin-node-resolve": "11.0.0",
|
45
|
-
"@types/node": "14.14.13",
|
37
|
+
"@ctrl/eslint-config": "3.2.0",
|
38
|
+
"@sindresorhus/tsconfig": "2.0.0",
|
39
|
+
"@types/node": "17.0.1",
|
40
|
+
"ava": "4.0.0-rc.1",
|
46
41
|
"buffer": "6.0.3",
|
47
|
-
"
|
48
|
-
"
|
49
|
-
"
|
50
|
-
"rollup-plugin-node-builtins": "2.1.2",
|
51
|
-
"rollup-plugin-node-globals": "1.4.0",
|
52
|
-
"rollup-plugin-serve": "1.1.0",
|
53
|
-
"rollup-plugin-terser": "7.0.2",
|
54
|
-
"rollup-plugin-typescript2": "0.29.0",
|
55
|
-
"typescript": "4.1.3"
|
56
|
-
},
|
57
|
-
"release": {
|
58
|
-
"branch": "master"
|
59
|
-
},
|
60
|
-
"jest": {
|
61
|
-
"testEnvironment": "node"
|
42
|
+
"c8": "7.10.0",
|
43
|
+
"tsm": "2.2.1",
|
44
|
+
"typescript": "4.5.4"
|
62
45
|
},
|
63
|
-
"
|
64
|
-
"
|
65
|
-
"
|
46
|
+
"ava": {
|
47
|
+
"files": [
|
48
|
+
"test/**/*.spec.ts"
|
66
49
|
],
|
67
|
-
"
|
68
|
-
"
|
50
|
+
"extensions": {
|
51
|
+
"ts": "module"
|
52
|
+
},
|
53
|
+
"nodeArguments": [
|
54
|
+
"--loader=tsm"
|
69
55
|
]
|
70
56
|
},
|
57
|
+
"workspaces": [
|
58
|
+
"demo"
|
59
|
+
],
|
60
|
+
"publishConfig": {
|
61
|
+
"access": "public"
|
62
|
+
},
|
63
|
+
"release": {
|
64
|
+
"branch": "master"
|
65
|
+
},
|
71
66
|
"engines": {
|
72
|
-
"node": ">=
|
67
|
+
"node": ">=14.16"
|
73
68
|
}
|
74
69
|
}
|
package/dist/index.js
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.magnetEncode = exports.magnetDecode = void 0;
|
4
|
-
const ts_base32_1 = require("@ctrl/ts-base32");
|
5
|
-
const start = 'magnet:?';
|
6
|
-
function magnetDecode(uri) {
|
7
|
-
// Support 'stream-magnet:' as well
|
8
|
-
const data = uri.substr(uri.indexOf(start) + start.length);
|
9
|
-
const params = data && data.length >= 0 ? data.split('&') : [];
|
10
|
-
const result = {};
|
11
|
-
params.forEach(param => {
|
12
|
-
const keyval = param.split('=');
|
13
|
-
// This keyval is invalid, skip it
|
14
|
-
if (keyval.length !== 2) {
|
15
|
-
return;
|
16
|
-
}
|
17
|
-
const key = keyval[0];
|
18
|
-
const val = parseQueryParamValue(key, keyval[1]);
|
19
|
-
if (val === undefined) {
|
20
|
-
return;
|
21
|
-
}
|
22
|
-
const r = result[key];
|
23
|
-
if (!r) {
|
24
|
-
result[key] = val;
|
25
|
-
return result;
|
26
|
-
}
|
27
|
-
// If there are repeated parameters, return an array of values
|
28
|
-
if (r && Array.isArray(r)) {
|
29
|
-
return r.push(val);
|
30
|
-
}
|
31
|
-
result[key] = [r, val];
|
32
|
-
});
|
33
|
-
if (result.xt) {
|
34
|
-
let m;
|
35
|
-
const xts = Array.isArray(result.xt) ? result.xt : [result.xt];
|
36
|
-
xts.forEach((xt) => {
|
37
|
-
if ((m = xt.match(/^urn:btih:(.{40})/))) {
|
38
|
-
result.infoHash = m[1].toLowerCase();
|
39
|
-
}
|
40
|
-
else if ((m = xt.match(/^urn:btih:(.{32})/))) {
|
41
|
-
const decodedStr = ts_base32_1.base32Decode(m[1]);
|
42
|
-
result.infoHash = Buffer.from(decodedStr).toString('hex');
|
43
|
-
}
|
44
|
-
});
|
45
|
-
}
|
46
|
-
if (result.dn) {
|
47
|
-
result.name = result.dn;
|
48
|
-
}
|
49
|
-
if (result.kt) {
|
50
|
-
result.keywords = result.kt;
|
51
|
-
}
|
52
|
-
if (typeof result.tr === 'string') {
|
53
|
-
result.announce = [result.tr];
|
54
|
-
}
|
55
|
-
else if (Array.isArray(result.tr)) {
|
56
|
-
result.announce = result.tr;
|
57
|
-
}
|
58
|
-
else {
|
59
|
-
result.announce = [];
|
60
|
-
}
|
61
|
-
result.urlList = [];
|
62
|
-
if (typeof result.as === 'string' || Array.isArray(result.as)) {
|
63
|
-
result.urlList = result.urlList.concat(result.as);
|
64
|
-
}
|
65
|
-
if (typeof result.ws === 'string' || Array.isArray(result.ws)) {
|
66
|
-
result.urlList = result.urlList.concat(result.ws);
|
67
|
-
}
|
68
|
-
result.announce = [...new Set(result.announce)].sort((a, b) => a.localeCompare(b));
|
69
|
-
result.urlList = [...new Set(result.urlList)].sort((a, b) => a.localeCompare(b));
|
70
|
-
return result;
|
71
|
-
}
|
72
|
-
exports.magnetDecode = magnetDecode;
|
73
|
-
/**
|
74
|
-
* Specific query parameters have expected formats, this attempts to parse them in the correct way
|
75
|
-
*/
|
76
|
-
function parseQueryParamValue(key, val) {
|
77
|
-
// Clean up torrent name
|
78
|
-
if (key === 'dn') {
|
79
|
-
return decodeURIComponent(val).replace(/\+/g, ' ');
|
80
|
-
}
|
81
|
-
// Address tracker (tr), exact source (xs), and acceptable source (as) are encoded
|
82
|
-
// URIs, so decode them
|
83
|
-
if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
|
84
|
-
return decodeURIComponent(val);
|
85
|
-
}
|
86
|
-
// Return keywords as an array
|
87
|
-
if (key === 'kt') {
|
88
|
-
return decodeURIComponent(val).split('+');
|
89
|
-
}
|
90
|
-
// Cast file index (ix) to a number
|
91
|
-
if (key === 'ix') {
|
92
|
-
return Number(val);
|
93
|
-
}
|
94
|
-
return val;
|
95
|
-
}
|
96
|
-
function magnetEncode(data) {
|
97
|
-
const obj = { ...data }; // Shallow clone object
|
98
|
-
// Support using convenience names, in addition to spec names
|
99
|
-
// (example: `infoHash` for `xt`, `name` for `dn`)
|
100
|
-
if (obj.infoHash) {
|
101
|
-
obj.xt = `urn:btih:${obj.infoHash}`;
|
102
|
-
}
|
103
|
-
if (obj.name) {
|
104
|
-
obj.dn = obj.name;
|
105
|
-
}
|
106
|
-
if (obj.keywords) {
|
107
|
-
obj.kt = obj.keywords;
|
108
|
-
}
|
109
|
-
if (obj.announce) {
|
110
|
-
obj.tr = obj.announce;
|
111
|
-
}
|
112
|
-
if (obj.urlList) {
|
113
|
-
obj.ws = obj.urlList;
|
114
|
-
delete obj.as;
|
115
|
-
}
|
116
|
-
return Object.keys(obj)
|
117
|
-
.filter(key => key.length === 2)
|
118
|
-
.reduce((prev, key, i) => {
|
119
|
-
let acc = prev;
|
120
|
-
const values = Array.isArray(obj[key]) ? obj[key] : [obj[key]];
|
121
|
-
values.forEach((val, j) => {
|
122
|
-
if ((i > 0 || j > 0) && (key !== 'kt' || j === 0)) {
|
123
|
-
acc = `${acc}&`;
|
124
|
-
}
|
125
|
-
let res = val;
|
126
|
-
if (key === 'dn') {
|
127
|
-
res = encodeURIComponent(val).replace(/%20/g, '+');
|
128
|
-
}
|
129
|
-
if (key === 'tr' || key === 'xs' || key === 'as' || key === 'ws') {
|
130
|
-
res = encodeURIComponent(val);
|
131
|
-
}
|
132
|
-
if (key === 'kt') {
|
133
|
-
res = encodeURIComponent(val);
|
134
|
-
}
|
135
|
-
if (key === 'kt' && j > 0) {
|
136
|
-
acc = `${acc}+${res}`;
|
137
|
-
}
|
138
|
-
else {
|
139
|
-
acc = `${acc}${key}=${res}`;
|
140
|
-
}
|
141
|
-
});
|
142
|
-
return acc;
|
143
|
-
}, `${start}`);
|
144
|
-
}
|
145
|
-
exports.magnetEncode = magnetEncode;
|