@ctrl/torrent-file 4.3.0 → 4.4.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.
@@ -1,5 +1,4 @@
|
|
1
1
|
import { stringToUint8Array, uint8ArrayToString } from 'uint8array-extras';
|
2
|
-
import { isValidUTF8 } from './utils.js';
|
3
2
|
const td = new TextDecoder();
|
4
3
|
class Decoder {
|
5
4
|
idx = 0;
|
@@ -70,8 +69,7 @@ class Decoder {
|
|
70
69
|
nextBufOrString() {
|
71
70
|
const length = this.readNumber();
|
72
71
|
this.assertByte(':');
|
73
|
-
|
74
|
-
return isValidUTF8(buf) ? td.decode(buf) : buf;
|
72
|
+
return this.readBytes(length);
|
75
73
|
}
|
76
74
|
nextString() {
|
77
75
|
const length = this.readNumber();
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import { concatUint8Arrays, stringToUint8Array } from 'uint8array-extras';
|
2
|
-
import { cmpRawString } from './utils.js';
|
3
2
|
const te = new TextEncoder();
|
4
3
|
const encodeString = (str) => {
|
5
4
|
const lengthBytes = new TextEncoder().encode(str.length.toString());
|
@@ -33,7 +32,7 @@ const encodeNumber = (num) => {
|
|
33
32
|
const encodeDictionary = (obj) => {
|
34
33
|
const results = [];
|
35
34
|
Object.keys(obj)
|
36
|
-
.sort(
|
35
|
+
.sort()
|
37
36
|
.forEach(key => {
|
38
37
|
results.push(encodeString(key));
|
39
38
|
results.push(new Uint8Array(encode(obj[key])));
|
@@ -18,73 +18,3 @@ export const cmpRawString = (str1, str2) => {
|
|
18
18
|
}
|
19
19
|
return v1.length < v2.length ? -1 : 1;
|
20
20
|
};
|
21
|
-
export const typedArraysAreEqual = (a, b) => {
|
22
|
-
if (a.byteLength !== b.byteLength) {
|
23
|
-
return false;
|
24
|
-
}
|
25
|
-
return a.every((val, i) => val === b[i]);
|
26
|
-
};
|
27
|
-
// Copied from https://github.com/hcodes/isutf8/blob/master/src/index.ts
|
28
|
-
/*
|
29
|
-
https://tools.ietf.org/html/rfc3629
|
30
|
-
UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
|
31
|
-
UTF8-1 = %x00-7F
|
32
|
-
UTF8-2 = %xC2-DF UTF8-tail
|
33
|
-
UTF8-3 = %xE0 %xA0-BF UTF8-tail
|
34
|
-
%xE1-EC 2( UTF8-tail )
|
35
|
-
%xED %x80-9F UTF8-tail
|
36
|
-
%xEE-EF 2( UTF8-tail )
|
37
|
-
UTF8-4 = %xF0 %x90-BF 2( UTF8-tail )
|
38
|
-
%xF1-F3 3( UTF8-tail )
|
39
|
-
%xF4 %x80-8F 2( UTF8-tail )
|
40
|
-
UTF8-tail = %x80-BF
|
41
|
-
*/
|
42
|
-
export const isValidUTF8 = (buf) => {
|
43
|
-
let i = 0;
|
44
|
-
const len = buf.length;
|
45
|
-
while (i < len) {
|
46
|
-
// UTF8-1 = %x00-7F
|
47
|
-
if (buf[i] <= 0x7f) {
|
48
|
-
i++;
|
49
|
-
continue;
|
50
|
-
}
|
51
|
-
// UTF8-2 = %xC2-DF UTF8-tail
|
52
|
-
if (buf[i] >= 0xc2 && buf[i] <= 0xdf) {
|
53
|
-
// if(buf[i + 1] >= 0x80 && buf[i + 1] <= 0xBF) {
|
54
|
-
if (buf[i + 1] >> 6 === 2) {
|
55
|
-
i += 2;
|
56
|
-
continue;
|
57
|
-
}
|
58
|
-
return false;
|
59
|
-
}
|
60
|
-
// UTF8-3 = %xE0 %xA0-BF UTF8-tail
|
61
|
-
// UTF8-3 = %xED %x80-9F UTF8-tail
|
62
|
-
if (((buf[i] === 0xe0 && buf[i + 1] >= 0xa0 && buf[i + 1] <= 0xbf) ||
|
63
|
-
(buf[i] === 0xed && buf[i + 1] >= 0x80 && buf[i + 1] <= 0x9f)) &&
|
64
|
-
buf[i + 2] >> 6 === 2) {
|
65
|
-
i += 3;
|
66
|
-
continue;
|
67
|
-
}
|
68
|
-
// UTF8-3 = %xE1-EC 2( UTF8-tail )
|
69
|
-
// UTF8-3 = %xEE-EF 2( UTF8-tail )
|
70
|
-
if (((buf[i] >= 0xe1 && buf[i] <= 0xec) || (buf[i] >= 0xee && buf[i] <= 0xef)) &&
|
71
|
-
buf[i + 1] >> 6 === 2 &&
|
72
|
-
buf[i + 2] >> 6 === 2) {
|
73
|
-
i += 3;
|
74
|
-
continue;
|
75
|
-
}
|
76
|
-
// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail )
|
77
|
-
// %xF1-F3 3( UTF8-tail )
|
78
|
-
// %xF4 %x80-8F 2( UTF8-tail )
|
79
|
-
if (((buf[i] === 0xf0 && buf[i + 1] >= 0x90 && buf[i + 1] <= 0xbf) ||
|
80
|
-
(buf[i] >= 0xf1 && buf[i] <= 0xf3 && buf[i + 1] >> 6 === 2) ||
|
81
|
-
(buf[i] === 0xf4 && buf[i + 1] >= 0x80 && buf[i + 1] <= 0x8f)) &&
|
82
|
-
buf[i + 2] >> 6 === 2 &&
|
83
|
-
buf[i + 3] >> 6 === 2) {
|
84
|
-
i += 4;
|
85
|
-
continue;
|
86
|
-
}
|
87
|
-
return false;
|
88
|
-
}
|
89
|
-
return true;
|
90
|
-
};
|
@@ -1,6 +1,6 @@
|
|
1
1
|
export declare const sha1: (input: Uint8Array) => string;
|
2
2
|
/**
|
3
|
-
* sha1 of torrent file info. This hash is
|
3
|
+
* sha1 of torrent file info. This hash is commonly used by torrent clients as the ID of the torrent.
|
4
4
|
*/
|
5
5
|
export declare function hash(file: Uint8Array): string;
|
6
6
|
export interface TorrentFileData {
|
package/dist/src/torrentFile.js
CHANGED
@@ -2,6 +2,13 @@ import { createHash } from 'node:crypto';
|
|
2
2
|
import { join, sep } from 'node:path';
|
3
3
|
import { isUint8Array, uint8ArrayToHex, uint8ArrayToString } from 'uint8array-extras';
|
4
4
|
import { decode, encode } from './bencode/index.js';
|
5
|
+
// Helper function to convert Uint8Array to string for display
|
6
|
+
const toString = (value) => {
|
7
|
+
if (value instanceof Uint8Array) {
|
8
|
+
return uint8ArrayToString(value);
|
9
|
+
}
|
10
|
+
return value.toString();
|
11
|
+
};
|
5
12
|
export const sha1 = (input) => {
|
6
13
|
const hash = createHash('sha1');
|
7
14
|
// Update the hash object with the data
|
@@ -9,7 +16,7 @@ export const sha1 = (input) => {
|
|
9
16
|
return hash.digest('hex');
|
10
17
|
};
|
11
18
|
/**
|
12
|
-
* sha1 of torrent file info. This hash is
|
19
|
+
* sha1 of torrent file info. This hash is commonly used by torrent clients as the ID of the torrent.
|
13
20
|
*/
|
14
21
|
export function hash(file) {
|
15
22
|
const torrent = decode(file);
|
@@ -28,9 +35,9 @@ export function files(file) {
|
|
28
35
|
pieces: [],
|
29
36
|
};
|
30
37
|
const files = torrent.info.files || [torrent.info];
|
31
|
-
const name = (torrent.info['name.utf-8'] || torrent.info.name)
|
38
|
+
const name = toString(torrent.info['name.utf-8'] || torrent.info.name);
|
32
39
|
result.files = files.map((file, i) => {
|
33
|
-
const parts = [name, ...(file['path.utf-8'] || file.path || [])].map(p =>
|
40
|
+
const parts = [name, ...(file['path.utf-8'] || file.path || [])].map(p => toString(p));
|
34
41
|
return {
|
35
42
|
path: join(sep, ...parts).slice(1),
|
36
43
|
name: parts[parts.length - 1],
|
@@ -61,7 +68,7 @@ function splitPieces(buf) {
|
|
61
68
|
export function info(file) {
|
62
69
|
const torrent = decode(file);
|
63
70
|
const result = {
|
64
|
-
name: (torrent.info['name.utf-8'] || torrent.info.name)
|
71
|
+
name: toString(torrent.info['name.utf-8'] || torrent.info.name),
|
65
72
|
announce: [],
|
66
73
|
urlList: [],
|
67
74
|
};
|
@@ -72,10 +79,10 @@ export function info(file) {
|
|
72
79
|
result.created = new Date(torrent['creation date'] * 1000);
|
73
80
|
}
|
74
81
|
if (torrent['created by']) {
|
75
|
-
result.createdBy = torrent['created by']
|
82
|
+
result.createdBy = toString(torrent['created by']);
|
76
83
|
}
|
77
|
-
if (
|
78
|
-
result.comment =
|
84
|
+
if (torrent.comment) {
|
85
|
+
result.comment = toString(torrent.comment);
|
79
86
|
}
|
80
87
|
// announce and announce-list will be missing if metadata fetched via ut_metadata
|
81
88
|
if (Array.isArray(torrent['announce-list']) &&
|
@@ -83,12 +90,12 @@ export function info(file) {
|
|
83
90
|
torrent['announce-list'].length > 0) {
|
84
91
|
torrent['announce-list'].forEach((urls) => {
|
85
92
|
urls.forEach((url) => {
|
86
|
-
result.announce.push(
|
93
|
+
result.announce.push(toString(url));
|
87
94
|
});
|
88
95
|
});
|
89
96
|
}
|
90
97
|
else if (torrent.announce) {
|
91
|
-
result.announce.push(torrent.announce
|
98
|
+
result.announce.push(toString(torrent.announce));
|
92
99
|
}
|
93
100
|
if (result.announce.length) {
|
94
101
|
result.announce = Array.from(new Set(result.announce));
|
@@ -98,7 +105,7 @@ export function info(file) {
|
|
98
105
|
// some clients set url-list to empty string
|
99
106
|
torrent['url-list'] = torrent['url-list'].length > 0 ? [torrent['url-list']] : [];
|
100
107
|
}
|
101
|
-
result.urlList = (torrent['url-list'] || []).map((url) =>
|
108
|
+
result.urlList = (torrent['url-list'] || []).map((url) => toString(url));
|
102
109
|
if (result.urlList.length) {
|
103
110
|
result.urlList = Array.from(new Set(result.urlList));
|
104
111
|
}
|