amule-ec-client 0.6.0 → 0.7.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.
Files changed (87) hide show
  1. package/README.md +10 -2
  2. package/dist/{AddLinkRequest-DwUbSMXD.mjs → AddLinkRequest-DEKGy-R2.js} +2 -5
  3. package/dist/{ClientQueueRequest-D9FaX5K9.mjs → ClientQueueRequest-DrLXSxtp.js} +2 -5
  4. package/dist/{ClientQueueResponse-FVQBR_8b.mjs → ClientQueueResponse-CXxY_9wU.js} +6 -6
  5. package/dist/{CreateCategoryRequest-Br6yfDhZ.mjs → CreateCategoryRequest-COulF12x.js} +2 -5
  6. package/dist/{DeleteCategoryRequest-C2-p6sx0.mjs → DeleteCategoryRequest-D-mljaNV.js} +2 -5
  7. package/dist/{DownloadCommandRequest-CaULjfNi.mjs → DownloadCommandRequest-Bf1Ez8Da.js} +3 -6
  8. package/dist/{DownloadFileRequest-CcNqsBo7.mjs → DownloadFileRequest-WfOIV07R.js} +2 -5
  9. package/dist/{DownloadQueueRequest-bd7lFiMj.mjs → DownloadQueueRequest-Br-pgrRt.js} +2 -5
  10. package/dist/DownloadQueueResponse-C-5d4teB.js +241 -0
  11. package/dist/{GetPreferencesRequest-C94Su9IH.mjs → GetPreferencesRequest-BE3RbRRn.js} +2 -5
  12. package/dist/{PreferencesDetailsResponse-BjMxbvVY.mjs → PreferencesDetailsResponse-D8lBd8Ot.js} +1 -4
  13. package/dist/{PreferencesResponse-Dth-n2sA.mjs → PreferencesResponse-BmGTQM30.js} +1 -4
  14. package/dist/{ReloadSharedFilesRequest-CPwAEJYG.mjs → ReloadSharedFilesRequest-BbDUeGcq.js} +2 -4
  15. package/dist/{Request-C0UUuQIX.mjs → Request-BvScDpeu.js} +3 -11
  16. package/dist/{SearchProgressResponse-Bputc9Ww.mjs → SearchProgressResponse-BQPliUup.js} +1 -4
  17. package/dist/{SearchRequest-CNqz-K1Z.mjs → SearchRequest-DOakj8fA.js} +3 -6
  18. package/dist/{SearchResultsRequest-DKG508KF.mjs → SearchResultsRequest-oZBs5KKm.js} +2 -4
  19. package/dist/{SearchResultsResponse-ChNrKJ6_.mjs → SearchResultsResponse-C9I9x035.js} +1 -4
  20. package/dist/{SearchStatusRequest-Bv6iaC9Y.mjs → SearchStatusRequest-B1ZzSQlE.js} +2 -4
  21. package/dist/{SearchStopRequest-rET-2Nsz.mjs → SearchStopRequest-FfXf_DCn.js} +2 -4
  22. package/dist/{ServerConnectRequest-CcO2-Eqd.mjs → ServerConnectRequest-Cdiw-KWu.js} +2 -5
  23. package/dist/{ServerDisconnectRequest-DEORM3SF.mjs → ServerDisconnectRequest-BVXSumxX.js} +2 -4
  24. package/dist/{ServerListRequest-FwFQBp12.mjs → ServerListRequest-3yMrgZID.js} +2 -4
  25. package/dist/{ServerListResponse-ZAKSSCPZ.mjs → ServerListResponse-Do3iRai0.js} +5 -6
  26. package/dist/{ServerUpdateFromUrlRequest-D4xBqJDJ.mjs → ServerUpdateFromUrlRequest-DpxBII5W.js} +2 -5
  27. package/dist/{SetFileCategoryRequest-BwEPJVeR.mjs → SetFileCategoryRequest-CFgkJB-H.js} +2 -5
  28. package/dist/{SetPreferencesRequest-D2fVIH3P.mjs → SetPreferencesRequest-BdZ40Ao_.js} +2 -5
  29. package/dist/{SharedFilePriorityRequest-j6ImgagV.mjs → SharedFilePriorityRequest-BMNmaL06.js} +2 -5
  30. package/dist/{SharedFilesRequest-D2M3K0eB.mjs → SharedFilesRequest-BZKz0oyn.js} +2 -5
  31. package/dist/SharedFilesResponse-DE0cd1DT.js +45 -0
  32. package/dist/{StatsRequest-B8v9LLHG.mjs → StatsRequest-DVwx5wk1.js} +2 -5
  33. package/dist/{StatsResponse-BVUxNPbz.mjs → StatsResponse-CP2F2zt0.js} +25 -4
  34. package/dist/{Codes-CjiW7Pdl.mjs → Tag-B5gWV2XF.js} +268 -3
  35. package/dist/{UpdateCategoryRequest-CgzH7SxP.mjs → UpdateCategoryRequest-Bu22YjOm.js} +2 -5
  36. package/dist/{UpdateRequest-Bunl73Ga.mjs → UpdateRequest-CaQ867p8.js} +2 -5
  37. package/dist/UpdateState-Dn-SuAsj.js +173 -0
  38. package/dist/{download-details-OM0FJUhZ.mjs → download-details-OM0FJUhZ.js} +0 -2
  39. package/dist/{index.d.mts → index.d.ts} +358 -337
  40. package/dist/{index.mjs → index.js} +94 -54
  41. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  42. package/dist/{utils-DBnUQnZ-.mjs → utils-CNoUroOI.js} +11 -3
  43. package/package.json +1 -1
  44. package/dist/AddLinkRequest-DwUbSMXD.mjs.map +0 -1
  45. package/dist/ClientQueueRequest-D9FaX5K9.mjs.map +0 -1
  46. package/dist/ClientQueueResponse-FVQBR_8b.mjs.map +0 -1
  47. package/dist/Codes-CjiW7Pdl.mjs.map +0 -1
  48. package/dist/CreateCategoryRequest-Br6yfDhZ.mjs.map +0 -1
  49. package/dist/DeleteCategoryRequest-C2-p6sx0.mjs.map +0 -1
  50. package/dist/DownloadCommandRequest-CaULjfNi.mjs.map +0 -1
  51. package/dist/DownloadFileRequest-CcNqsBo7.mjs.map +0 -1
  52. package/dist/DownloadQueueRequest-bd7lFiMj.mjs.map +0 -1
  53. package/dist/DownloadQueueResponse-DyP1rLTV.mjs +0 -261
  54. package/dist/DownloadQueueResponse-DyP1rLTV.mjs.map +0 -1
  55. package/dist/GetPreferencesRequest-C94Su9IH.mjs.map +0 -1
  56. package/dist/PreferencesDetailsResponse-BjMxbvVY.mjs.map +0 -1
  57. package/dist/PreferencesResponse-Dth-n2sA.mjs.map +0 -1
  58. package/dist/ReloadSharedFilesRequest-CPwAEJYG.mjs.map +0 -1
  59. package/dist/Request-C0UUuQIX.mjs.map +0 -1
  60. package/dist/SearchProgressResponse-Bputc9Ww.mjs.map +0 -1
  61. package/dist/SearchRequest-CNqz-K1Z.mjs.map +0 -1
  62. package/dist/SearchResultsRequest-DKG508KF.mjs.map +0 -1
  63. package/dist/SearchResultsResponse-ChNrKJ6_.mjs.map +0 -1
  64. package/dist/SearchStatusRequest-Bv6iaC9Y.mjs.map +0 -1
  65. package/dist/SearchStopRequest-rET-2Nsz.mjs.map +0 -1
  66. package/dist/ServerConnectRequest-CcO2-Eqd.mjs.map +0 -1
  67. package/dist/ServerDisconnectRequest-DEORM3SF.mjs.map +0 -1
  68. package/dist/ServerListRequest-FwFQBp12.mjs.map +0 -1
  69. package/dist/ServerListResponse-ZAKSSCPZ.mjs.map +0 -1
  70. package/dist/ServerUpdateFromUrlRequest-D4xBqJDJ.mjs.map +0 -1
  71. package/dist/SetFileCategoryRequest-BwEPJVeR.mjs.map +0 -1
  72. package/dist/SetPreferencesRequest-D2fVIH3P.mjs.map +0 -1
  73. package/dist/SharedFilePriorityRequest-j6ImgagV.mjs.map +0 -1
  74. package/dist/SharedFilesRequest-D2M3K0eB.mjs.map +0 -1
  75. package/dist/SharedFilesResponse-BiXT_oCx.mjs +0 -41
  76. package/dist/SharedFilesResponse-BiXT_oCx.mjs.map +0 -1
  77. package/dist/StatsRequest-B8v9LLHG.mjs.map +0 -1
  78. package/dist/StatsResponse-BVUxNPbz.mjs.map +0 -1
  79. package/dist/Tag-CZF6BRMY.mjs +0 -262
  80. package/dist/Tag-CZF6BRMY.mjs.map +0 -1
  81. package/dist/UpdateCategoryRequest-CgzH7SxP.mjs.map +0 -1
  82. package/dist/UpdateRequest-Bunl73Ga.mjs.map +0 -1
  83. package/dist/UpdateResponse-1LhyH9Zf.mjs +0 -47
  84. package/dist/UpdateResponse-1LhyH9Zf.mjs.map +0 -1
  85. package/dist/download-details-OM0FJUhZ.mjs.map +0 -1
  86. package/dist/index.mjs.map +0 -1
  87. package/dist/utils-DBnUQnZ-.mjs.map +0 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  A TypeScript client library for interacting with aMule's External Connection (EC) protocol.
7
7
 
8
- Ported from [jamule](https://github.com/vexdev/jamule) (Java/Kotlin) to TypeScript.
8
+ This project started as a port from [jamule](https://github.com/vexdev/jamule) (Java/Kotlin) to TypeScript. But as of the date this readme was last updated, this project covers wider functionality.
9
9
 
10
10
  ## Features
11
11
 
@@ -14,6 +14,7 @@ Ported from [jamule](https://github.com/vexdev/jamule) (Java/Kotlin) to TypeScri
14
14
  - ✅ Server statistics
15
15
  - ✅ File searching (local, global, Kad, web)
16
16
  - ✅ Download management
17
+ - ✅ Per-peer source details for active downloads (via incremental updates)
17
18
  - ✅ Shared files listing
18
19
  - ✅ Category management
19
20
  - ✅ ED2K link parsing
@@ -101,7 +102,13 @@ Options:
101
102
  **Downloads**
102
103
 
103
104
  - `downloadSearchResult(hash, category?): Promise<void>` - Download from search results
104
- - `getDownloadQueue(): Promise<AmuleTransferringFile[]>` - Get download queue
105
+ - `getDownloadQueue(): Promise<AmuleTransferringFile[]>` - Get download queue (chunk info and source name buckets, but no per-peer details)
106
+ - `getDownloadQueueWithSources(): Promise<AmuleTransferringFile[]>` - Get download queue with `sources` filled with the connected peers of each download (name, IP, software, speeds, queue rank, ...)
107
+ - `getUpdate(): Promise<UpdateResponse>` - Incremental update snapshot: downloads (with `sources`), shared files and clients. The daemon sends per-connection diffs; the client merges them internally, so every call returns full objects
108
+
109
+ > **Note:** aMule only exposes per-peer info through the incremental update mechanism (`EC_OP_GET_UPDATE`), never nested inside `EC_OP_GET_DLOAD_QUEUE` responses. Peers are linked to downloads through `client.requestFileId === file.ecid`. The internal cache is per connection and resets automatically on reconnect.
110
+ >
111
+ > `sourceNames` (the filenames under which the sources share each file) is also sent by the daemon as a per-connection incremental map — even for full-detail `getDownloadQueue()` requests. `getDownloadQueue()` therefore returns complete name buckets only on the first call of a connection; the update-based methods merge the diffs and are always complete.
105
112
 
106
113
  **Shared Files**
107
114
 
@@ -115,6 +122,7 @@ This library implements the aMule External Connection protocol version 0x0204, c
115
122
  - aMule 2.3.2
116
123
  - aMule 2.3.3
117
124
  - aMule 3.0.0
125
+ - aMule 3.0.1
118
126
 
119
127
  ### Protocol Features
120
128
 
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { a as StringTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { a as StringTag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/AddLinkRequest.ts
5
4
  /**
6
5
  * Add Link Request - Download from ED2K link
@@ -13,5 +12,3 @@ var AddLinkRequest = class extends Request {
13
12
  };
14
13
  //#endregion
15
14
  export { AddLinkRequest };
16
-
17
- //# sourceMappingURL=AddLinkRequest-DwUbSMXD.mjs.map
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { s as UByteTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { s as UByteTag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/ClientQueueRequest.ts
5
4
  /**
6
5
  * Client Queue Request - Get client upload queue
@@ -13,5 +12,3 @@ var ClientQueueRequest = class extends Request {
13
12
  };
14
13
  //#endregion
15
14
  export { ClientQueueRequest };
16
-
17
- //# sourceMappingURL=ClientQueueRequest-D9FaX5K9.mjs.map
@@ -1,7 +1,8 @@
1
- import "./Codes-CjiW7Pdl.mjs";
2
- import { f as findNumericTag, p as findTag } from "./Tag-CZF6BRMY.mjs";
3
- import { i as toOptionalNumber, n as toOptionalBool, r as toOptionalIp } from "./utils-DBnUQnZ-.mjs";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { f as findNumericTag, p as findTag } from "./Tag-B5gWV2XF.js";
3
+ import { a as toOptionalNumber, i as toOptionalIp, n as tagOwnNumericValue, r as toOptionalBool } from "./utils-CNoUroOI.js";
4
4
  //#region src/response/ClientQueueResponse.ts
5
+ var ClientQueueResponse_exports = /* @__PURE__ */ __exportAll({ ClientQueueResponseParser: () => ClientQueueResponseParser });
5
6
  var ClientQueueResponseParser = class {
6
7
  static fromPacket(packet) {
7
8
  return this.fromTags(packet.tags);
@@ -12,6 +13,7 @@ var ClientQueueResponseParser = class {
12
13
  for (const clientTag of clientTags) {
13
14
  const tags = clientTag.nestedTags || [];
14
15
  const client = {
16
+ ecid: tagOwnNumericValue(clientTag),
15
17
  clientName: findTag(tags, 256)?.getValue(),
16
18
  userHashHexString: findTag(tags, 1539)?.getValue()?.toString("hex"),
17
19
  userID: findNumericTag(tags, 1566)?.getInt(),
@@ -60,6 +62,4 @@ var ClientQueueResponseParser = class {
60
62
  }
61
63
  };
62
64
  //#endregion
63
- export { ClientQueueResponseParser };
64
-
65
- //# sourceMappingURL=ClientQueueResponse-FVQBR_8b.mjs.map
65
+ export { ClientQueueResponse_exports as n, ClientQueueResponseParser as t };
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { a as StringTag, l as UIntTag, s as UByteTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { a as StringTag, l as UIntTag, s as UByteTag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/CreateCategoryRequest.ts
5
4
  /**
6
5
  * Create Category Request - Create a new category
@@ -20,5 +19,3 @@ var CreateCategoryRequest = class extends Request {
20
19
  };
21
20
  //#endregion
22
21
  export { CreateCategoryRequest };
23
-
24
- //# sourceMappingURL=CreateCategoryRequest-Br6yfDhZ.mjs.map
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { l as UIntTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { l as UIntTag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/DeleteCategoryRequest.ts
5
4
  /**
6
5
  * Delete Category Request - Delete an existing category
@@ -13,5 +12,3 @@ var DeleteCategoryRequest = class extends Request {
13
12
  };
14
13
  //#endregion
15
14
  export { DeleteCategoryRequest };
16
-
17
- //# sourceMappingURL=DeleteCategoryRequest-C2-p6sx0.mjs.map
@@ -1,7 +1,6 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { r as Hash16Tag } from "./Tag-CZF6BRMY.mjs";
4
- import "./index.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { r as Hash16Tag } from "./Tag-B5gWV2XF.js";
3
+ import "./index.js";
5
4
  //#region src/request/DownloadCommandRequest.ts
6
5
  /**
7
6
  * Download Command Request - Send commands to files in download queue
@@ -27,5 +26,3 @@ var DownloadCommandRequest = class DownloadCommandRequest extends Request {
27
26
  };
28
27
  //#endregion
29
28
  export { DownloadCommandRequest };
30
-
31
- //# sourceMappingURL=DownloadCommandRequest-CaULjfNi.mjs.map
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { r as Hash16Tag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { r as Hash16Tag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/DownloadFileRequest.ts
5
4
  /**
6
5
  * Download File Request - Download a file from search results
@@ -16,5 +15,3 @@ var DownloadFileRequest = class extends Request {
16
15
  };
17
16
  //#endregion
18
17
  export { DownloadFileRequest };
19
-
20
- //# sourceMappingURL=DownloadFileRequest-CcNqsBo7.mjs.map
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { s as UByteTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { s as UByteTag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/DownloadQueueRequest.ts
5
4
  /**
6
5
  * Download Queue Request - Get download queue
@@ -13,5 +12,3 @@ var DownloadQueueRequest = class extends Request {
13
12
  };
14
13
  //#endregion
15
14
  export { DownloadQueueRequest };
16
-
17
- //# sourceMappingURL=DownloadQueueRequest-bd7lFiMj.mjs.map
@@ -0,0 +1,241 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { f as findNumericTag, p as findTag } from "./Tag-B5gWV2XF.js";
3
+ import { n as PARTSIZE, t as ChunkStatus } from "./download-details-OM0FJUhZ.js";
4
+ import { a as toOptionalNumber, n as tagOwnNumericValue, r as toOptionalBool } from "./utils-CNoUroOI.js";
5
+ import { r as parseKnownFileFields } from "./SharedFilesResponse-DE0cd1DT.js";
6
+ //#region src/response/DownloadDetailsResponse.ts
7
+ /**
8
+ * Decode an aMule EC RLE-compressed buffer.
9
+ * Format: [value, value, count] repeats value count times; other bytes pass through.
10
+ */
11
+ function rleDecode(buf) {
12
+ let size = 0;
13
+ let index = 0;
14
+ while (index < buf.length) if (index < buf.length - 2 && buf[index + 1] === buf[index]) {
15
+ size += buf[index + 2];
16
+ index += 3;
17
+ } else {
18
+ size += 1;
19
+ index += 1;
20
+ }
21
+ const output = Buffer.alloc(size);
22
+ let outIndex = 0;
23
+ index = 0;
24
+ while (index < buf.length) if (index < buf.length - 2 && buf[index + 1] === buf[index]) {
25
+ const count = buf[index + 2];
26
+ output.fill(buf[index], outIndex, outIndex + count);
27
+ outIndex += count;
28
+ index += 3;
29
+ } else {
30
+ output[outIndex++] = buf[index];
31
+ index += 1;
32
+ }
33
+ return output;
34
+ }
35
+ /**
36
+ * Reconstruct the current state from the previous state and an RLE-decoded XOR diff,
37
+ * mirroring aMule's RLE_Data: resize previous buffer to the diff size (zero-extend on
38
+ * grow, truncate on shrink), then XOR byte-wise.
39
+ */
40
+ function xorReconstruct(previous, decodedDiff) {
41
+ const result = Buffer.alloc(decodedDiff.length, 0);
42
+ previous.copy(result, 0, 0, Math.min(previous.length, decodedDiff.length));
43
+ for (let i = 0; i < decodedDiff.length; i++) result[i] ^= decodedDiff[i];
44
+ return result;
45
+ }
46
+ /**
47
+ * Decode an RLE-decoded buffer of byte-interleaved (column-major) little-endian uint64 values.
48
+ */
49
+ function decodeInterleavedUint64(decoded) {
50
+ if (decoded.length === 0 || decoded.length % 8 !== 0) return [];
51
+ const valueCount = decoded.length / 8;
52
+ const values = new Array(valueCount);
53
+ for (let i = 0; i < valueCount; i++) {
54
+ let value = 0;
55
+ for (let byte = 7; byte >= 0; byte--) value = value * 256 + decoded[i + byte * valueCount];
56
+ values[i] = value;
57
+ }
58
+ return values;
59
+ }
60
+ function stringValue(tag) {
61
+ if (!tag) return "";
62
+ const value = tag.getValue();
63
+ return typeof value === "string" ? value : "";
64
+ }
65
+ function bufferValue(tag) {
66
+ if (!tag) return;
67
+ const value = tag.getValue();
68
+ return Buffer.isBuffer(value) ? value : void 0;
69
+ }
70
+ function nestedTag(parent, tagName) {
71
+ return parent.nestedTags ? findTag(parent.nestedTags, tagName) : void 0;
72
+ }
73
+ function nestedNumeric(parent, tagName) {
74
+ if (!parent.nestedTags) return 0;
75
+ const numeric = findNumericTag(parent.nestedTags, tagName);
76
+ if (numeric) return Number(numeric.getValue());
77
+ return tagOwnNumericValue(findTag(parent.nestedTags, tagName)) ?? 0;
78
+ }
79
+ /**
80
+ * Extract the raw (RLE-encoded) part/gap/req status buffers of a partfile tag.
81
+ */
82
+ function extractPartFileStatusBuffers(fileTag) {
83
+ return {
84
+ partStatus: bufferValue(nestedTag(fileTag, 786)),
85
+ gapStatus: bufferValue(nestedTag(fileTag, 787)),
86
+ reqStatus: bufferValue(nestedTag(fileTag, 788))
87
+ };
88
+ }
89
+ /**
90
+ * Compute per-chunk status from RLE-decoded part/gap/req status buffers.
91
+ */
92
+ function computeChunkInfo(sizeFull, buffers) {
93
+ const partCount = sizeFull > 0 ? Math.ceil(sizeFull / PARTSIZE) : 0;
94
+ const availability = new Array(partCount).fill(0);
95
+ if (buffers.partStatus && buffers.partStatus.length > 0) for (let i = 0; i < Math.min(buffers.partStatus.length, partCount); i++) availability[i] = buffers.partStatus[i];
96
+ const chunks = new Array(partCount).fill(ChunkStatus.COMPLETE);
97
+ if (partCount > 0 && buffers.gapStatus && buffers.gapStatus.length > 0) {
98
+ const gapValues = decodeInterleavedUint64(buffers.gapStatus);
99
+ for (let i = 0; i + 1 < gapValues.length; i += 2) {
100
+ const gapStart = gapValues[i];
101
+ const gapEnd = gapValues[i + 1];
102
+ if (gapStart > sizeFull || gapEnd > sizeFull || gapStart >= gapEnd) continue;
103
+ const startPart = Math.floor(gapStart / PARTSIZE);
104
+ const endPart = Math.min(Math.floor(gapEnd / PARTSIZE) + 1, partCount);
105
+ for (let part = startPart; part < endPart; part++) {
106
+ const chunkStart = part * PARTSIZE;
107
+ if (gapStart < Math.min((part + 1) * 9728e3, sizeFull) && gapEnd > chunkStart) chunks[part] = availability[part] > 0 ? ChunkStatus.AVAILABLE : ChunkStatus.UNAVAILABLE;
108
+ }
109
+ }
110
+ }
111
+ if (partCount > 0 && buffers.reqStatus && buffers.reqStatus.length > 0) {
112
+ const reqValues = decodeInterleavedUint64(buffers.reqStatus);
113
+ for (let i = 0; i + 1 < reqValues.length; i += 2) {
114
+ const reqStart = reqValues[i];
115
+ const reqEnd = reqValues[i + 1];
116
+ if (reqStart > sizeFull || reqEnd > sizeFull || reqStart >= reqEnd) continue;
117
+ const startPart = Math.floor(reqStart / PARTSIZE);
118
+ const endPart = Math.min(Math.floor(reqEnd / PARTSIZE) + 1, partCount);
119
+ for (let part = startPart; part < endPart; part++) {
120
+ if (chunks[part] === ChunkStatus.COMPLETE) continue;
121
+ const chunkStart = part * PARTSIZE;
122
+ if (reqStart < Math.min((part + 1) * 9728e3, sizeFull) && reqEnd > chunkStart) chunks[part] = ChunkStatus.DOWNLOADING;
123
+ }
124
+ }
125
+ }
126
+ return {
127
+ chunks,
128
+ availability,
129
+ partCount,
130
+ sizeFull
131
+ };
132
+ }
133
+ /**
134
+ * Chunk details of a partfile tag from a full (non-incremental) download queue packet.
135
+ * Only valid for EC_OP_GET_DLOAD_QUEUE responses: incremental updates (EC_OP_GET_UPDATE)
136
+ * send XOR diffs for the status buffers and must be reconstructed statefully instead.
137
+ */
138
+ function chunkInfoFromPartFileTag(fileTag) {
139
+ const sizeFull = nestedNumeric(fileTag, 771);
140
+ const raw = extractPartFileStatusBuffers(fileTag);
141
+ return computeChunkInfo(sizeFull, {
142
+ partStatus: raw.partStatus ? rleDecode(raw.partStatus) : void 0,
143
+ gapStatus: raw.gapStatus ? rleDecode(raw.gapStatus) : void 0,
144
+ reqStatus: raw.reqStatus ? rleDecode(raw.reqStatus) : void 0
145
+ });
146
+ }
147
+ /**
148
+ * Raw diff entries of the source-names map of a partfile tag, or undefined when the
149
+ * packet carries no source-names changes for this file.
150
+ *
151
+ * The daemon sends source names (the filenames under which the sources share the file)
152
+ * as a per-connection incremental map (see CPartFile_Encoder::Encode in aMule's
153
+ * ExternalConn.cpp): an EC_TAG_PARTFILE_SOURCE_NAMES container whose children are
154
+ * integer-valued EC_TAG_PARTFILE_SOURCE_NAMES tags (the map key), each carrying a
155
+ * nested count (0 removes the entry) and, only when the entry is new, a nested name
156
+ * string. The map is never reset while the connection lives, not even for
157
+ * EC_DETAIL_FULL requests.
158
+ */
159
+ function sourceNameEntriesFromFileTag(fileTag) {
160
+ const container = nestedTag(fileTag, 789);
161
+ if (!container) return;
162
+ const entries = [];
163
+ for (const child of container.nestedTags || []) {
164
+ if (child.name !== 789) continue;
165
+ const id = tagOwnNumericValue(child);
166
+ if (id === void 0) continue;
167
+ const name = stringValue(nestedTag(child, 789)) || void 0;
168
+ const count = nestedNumeric(child, 796);
169
+ entries.push({
170
+ id,
171
+ name,
172
+ count
173
+ });
174
+ }
175
+ return entries;
176
+ }
177
+ /**
178
+ * Stateless view of source-name diff entries: only entries whose name is present in
179
+ * this very packet (i.e. new for the connection). Complete on the first request of a
180
+ * connection; later requests only carry changes, so prefer the stateful update path
181
+ * for polling.
182
+ */
183
+ function sourceNameCountsFromEntries(entries) {
184
+ return entries.filter((entry) => entry.name !== void 0 && entry.count > 0).map((entry) => ({
185
+ name: entry.name,
186
+ count: entry.count
187
+ }));
188
+ }
189
+ //#endregion
190
+ //#region src/response/DownloadQueueResponse.ts
191
+ var DownloadQueueResponse_exports = /* @__PURE__ */ __exportAll({ DownloadQueueResponseParser: () => DownloadQueueResponseParser });
192
+ var DownloadQueueResponseParser = class {
193
+ static fromPacket(packet) {
194
+ const files = [];
195
+ const partfileTags = packet.tags.filter((tag) => tag.name === 768);
196
+ for (const fileTag of partfileTags) {
197
+ const tags = fileTag.nestedTags || [];
198
+ let a4afSources = void 0;
199
+ const a4afSourcesTag = findTag(tags, 802);
200
+ if (a4afSourcesTag) {
201
+ a4afSources = [];
202
+ a4afSourcesTag.nestedTags = a4afSourcesTag.nestedTags || [];
203
+ for (const sourceTag of a4afSourcesTag.nestedTags) if (sourceTag.name === 15) a4afSources.push(sourceTag.getValue());
204
+ }
205
+ const file = {
206
+ ...parseKnownFileFields(fileTag),
207
+ partMetID: findNumericTag(tags, 770)?.getShort(),
208
+ sizeXfer: toOptionalNumber(findNumericTag(tags, 772)?.getLong()),
209
+ sizeDone: toOptionalNumber(findNumericTag(tags, 774)?.getLong()),
210
+ fileStatus: findNumericTag(tags, 776)?.getInt(),
211
+ stopped: toOptionalBool(findNumericTag(tags, 791)?.getInt()),
212
+ sourceCount: findNumericTag(tags, 778)?.getShort(),
213
+ sourceNotCurrCount: findNumericTag(tags, 780)?.getShort(),
214
+ sourceXferCount: findNumericTag(tags, 781)?.getShort(),
215
+ sourceCountA4AF: findNumericTag(tags, 779)?.getShort(),
216
+ speed: toOptionalNumber(findNumericTag(tags, 775)?.getLong()),
217
+ downPrio: findNumericTag(tags, 777)?.getInt(),
218
+ fileCat: toOptionalNumber(findNumericTag(tags, 783)?.getLong()),
219
+ lastSeenComplete: toOptionalNumber(findNumericTag(tags, 785)?.getLong()),
220
+ lastDateChanged: toOptionalNumber(findNumericTag(tags, 784)?.getLong()),
221
+ downloadActiveTime: findNumericTag(tags, 792)?.getInt(),
222
+ availablePartCount: findNumericTag(tags, 797)?.getShort(),
223
+ a4AFAuto: toOptionalBool(findNumericTag(tags, 801)?.getInt()),
224
+ hashedPartCount: findNumericTag(tags, 800)?.getInt(),
225
+ getLostDueToCorruption: toOptionalNumber(findNumericTag(tags, 793)?.getLong()),
226
+ getGainDueToCompression: toOptionalNumber(findNumericTag(tags, 794)?.getLong()),
227
+ totalPacketsSavedDueToICH: findNumericTag(tags, 795)?.getInt(),
228
+ a4afSources
229
+ };
230
+ if (file.fileHashHexString) {
231
+ file.chunkInfo = chunkInfoFromPartFileTag(fileTag);
232
+ const sourceNameEntries = sourceNameEntriesFromFileTag(fileTag);
233
+ if (sourceNameEntries) file.sourceNames = sourceNameCountsFromEntries(sourceNameEntries);
234
+ }
235
+ files.push(file);
236
+ }
237
+ return { files };
238
+ }
239
+ };
240
+ //#endregion
241
+ export { rleDecode as a, extractPartFileStatusBuffers as i, DownloadQueueResponse_exports as n, sourceNameEntriesFromFileTag as o, computeChunkInfo as r, xorReconstruct as s, DownloadQueueResponseParser as t };
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { l as UIntTag, s as UByteTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { l as UIntTag, s as UByteTag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/GetPreferencesRequest.ts
5
4
  /**
6
5
  * Preferences Request - Get preferences
@@ -14,5 +13,3 @@ var GetPreferencesRequest = class extends Request {
14
13
  };
15
14
  //#endregion
16
15
  export { GetPreferencesRequest };
17
-
18
- //# sourceMappingURL=GetPreferencesRequest-C94Su9IH.mjs.map
@@ -1,5 +1,4 @@
1
- import "./Codes-CjiW7Pdl.mjs";
2
- import { f as findNumericTag, p as findTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { f as findNumericTag, p as findTag } from "./Tag-B5gWV2XF.js";
3
2
  //#region src/response/PreferencesDetailsResponse.ts
4
3
  var PreferencesDetailsResponse = class {
5
4
  preferences;
@@ -92,5 +91,3 @@ var PreferencesDetailsResponseParser = class {
92
91
  };
93
92
  //#endregion
94
93
  export { PreferencesDetailsResponseParser };
95
-
96
- //# sourceMappingURL=PreferencesDetailsResponse-BjMxbvVY.mjs.map
@@ -1,5 +1,4 @@
1
- import "./Codes-CjiW7Pdl.mjs";
2
- import { f as findNumericTag, p as findTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { f as findNumericTag, p as findTag } from "./Tag-B5gWV2XF.js";
3
2
  //#region src/response/PreferencesResponse.ts
4
3
  var PreferencesResponse = class {
5
4
  categories;
@@ -35,5 +34,3 @@ var PreferencesResponseParser = class {
35
34
  };
36
35
  //#endregion
37
36
  export { PreferencesResponseParser };
38
-
39
- //# sourceMappingURL=PreferencesResponse-Dth-n2sA.mjs.map
@@ -1,5 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import "./Tag-B5gWV2XF.js";
3
3
  //#region src/request/ReloadSharedFilesRequest.ts
4
4
  /**
5
5
  * Reload Shared Files Request - Reload shared files list
@@ -11,5 +11,3 @@ var ReloadSharedFilesRequest = class extends Request {
11
11
  };
12
12
  //#endregion
13
13
  export { ReloadSharedFilesRequest };
14
-
15
- //# sourceMappingURL=ReloadSharedFilesRequest-CPwAEJYG.mjs.map
@@ -1,3 +1,4 @@
1
+ import { p as findTag } from "./Tag-B5gWV2XF.js";
1
2
  //#region src/ec/packet/Flags.ts
2
3
  /**
3
4
  * Packet flags for EC protocol
@@ -80,11 +81,10 @@ var Flags = class Flags {
80
81
  };
81
82
  //#endregion
82
83
  //#region src/ec/packet/Packet.ts
83
- var Packet = class Packet {
84
+ var Packet = class {
84
85
  opCode;
85
86
  flags;
86
87
  tags;
87
- static EC_CURRENT_PROTOCOL_VERSION = 516;
88
88
  constructor(opCode, flags = new Flags(), tags = []) {
89
89
  this.opCode = opCode;
90
90
  this.flags = flags;
@@ -105,16 +105,10 @@ var Packet = class Packet {
105
105
  return this;
106
106
  }
107
107
  /**
108
- * Get protocol version
109
- */
110
- static getProtocolVersion() {
111
- return Packet.EC_CURRENT_PROTOCOL_VERSION;
112
- }
113
- /**
114
108
  * Find a tag by name
115
109
  */
116
110
  findTag(tagName) {
117
- return this.tags.find((tag) => tag.name === tagName);
111
+ return findTag(this.tags, tagName);
118
112
  }
119
113
  /**
120
114
  * Get all tags with a specific name
@@ -156,5 +150,3 @@ var Request = class {
156
150
  };
157
151
  //#endregion
158
152
  export { Packet as n, Flags as r, Request as t };
159
-
160
- //# sourceMappingURL=Request-C0UUuQIX.mjs.map
@@ -1,5 +1,4 @@
1
- import "./Codes-CjiW7Pdl.mjs";
2
- import { f as findNumericTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { f as findNumericTag } from "./Tag-B5gWV2XF.js";
3
2
  //#region src/response/SearchProgressResponse.ts
4
3
  var SearchProgressResponse = class SearchProgressResponse {
5
4
  progress;
@@ -13,5 +12,3 @@ var SearchProgressResponse = class SearchProgressResponse {
13
12
  };
14
13
  //#endregion
15
14
  export { SearchProgressResponse };
16
-
17
- //# sourceMappingURL=SearchProgressResponse-Bputc9Ww.mjs.map
@@ -1,7 +1,6 @@
1
- import { n as Packet, r as Flags, t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { a as StringTag, l as UIntTag, s as UByteTag, u as ULongTag } from "./Tag-CZF6BRMY.mjs";
4
- import "./index.mjs";
1
+ import { n as Packet, r as Flags, t as Request } from "./Request-BvScDpeu.js";
2
+ import { a as StringTag, l as UIntTag, s as UByteTag, u as ULongTag } from "./Tag-B5gWV2XF.js";
3
+ import "./index.js";
5
4
  //#region src/request/SearchRequest.ts
6
5
  /**
7
6
  * Search Request - Start a search
@@ -53,5 +52,3 @@ var SearchRequest = class extends Request {
53
52
  };
54
53
  //#endregion
55
54
  export { SearchRequest };
56
-
57
- //# sourceMappingURL=SearchRequest-CNqz-K1Z.mjs.map
@@ -1,5 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import "./Tag-B5gWV2XF.js";
3
3
  //#region src/request/SearchResultsRequest.ts
4
4
  /**
5
5
  * Search Results Request - Get search results
@@ -11,5 +11,3 @@ var SearchResultsRequest = class extends Request {
11
11
  };
12
12
  //#endregion
13
13
  export { SearchResultsRequest };
14
-
15
- //# sourceMappingURL=SearchResultsRequest-DKG508KF.mjs.map
@@ -1,5 +1,4 @@
1
- import "./Codes-CjiW7Pdl.mjs";
2
- import { f as findNumericTag, p as findTag } from "./Tag-CZF6BRMY.mjs";
1
+ import { f as findNumericTag, p as findTag } from "./Tag-B5gWV2XF.js";
3
2
  //#region src/response/SearchResultsResponse.ts
4
3
  var SearchResultsResponseParser = class {
5
4
  static fromPacket(packet) {
@@ -27,5 +26,3 @@ var SearchResultsResponseParser = class {
27
26
  };
28
27
  //#endregion
29
28
  export { SearchResultsResponseParser };
30
-
31
- //# sourceMappingURL=SearchResultsResponse-ChNrKJ6_.mjs.map
@@ -1,5 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import "./Tag-B5gWV2XF.js";
3
3
  //#region src/request/SearchStatusRequest.ts
4
4
  /**
5
5
  * Search Status Request - Get search progress
@@ -11,5 +11,3 @@ var SearchStatusRequest = class extends Request {
11
11
  };
12
12
  //#endregion
13
13
  export { SearchStatusRequest };
14
-
15
- //# sourceMappingURL=SearchStatusRequest-Bv6iaC9Y.mjs.map
@@ -1,5 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import "./Tag-B5gWV2XF.js";
3
3
  //#region src/request/SearchStopRequest.ts
4
4
  /**
5
5
  * Search Stop Request - Stop current search
@@ -11,5 +11,3 @@ var SearchStopRequest = class extends Request {
11
11
  };
12
12
  //#endregion
13
13
  export { SearchStopRequest };
14
-
15
- //# sourceMappingURL=SearchStopRequest-rET-2Nsz.mjs.map
@@ -1,6 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
3
- import { i as Ipv4Tag } from "./Tag-CZF6BRMY.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import { i as Ipv4Tag } from "./Tag-B5gWV2XF.js";
4
3
  //#region src/request/ServerConnectRequest.ts
5
4
  /**
6
5
  * Server Connect Request - Connect to a specific server
@@ -16,5 +15,3 @@ var ServerConnectRequest = class extends Request {
16
15
  };
17
16
  //#endregion
18
17
  export { ServerConnectRequest };
19
-
20
- //# sourceMappingURL=ServerConnectRequest-CcO2-Eqd.mjs.map
@@ -1,5 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import "./Tag-B5gWV2XF.js";
3
3
  //#region src/request/ServerDisconnectRequest.ts
4
4
  /**
5
5
  * Server Disconnect Request - Disconnect from the current server
@@ -11,5 +11,3 @@ var ServerDisconnectRequest = class extends Request {
11
11
  };
12
12
  //#endregion
13
13
  export { ServerDisconnectRequest };
14
-
15
- //# sourceMappingURL=ServerDisconnectRequest-DEORM3SF.mjs.map
@@ -1,5 +1,5 @@
1
- import { t as Request } from "./Request-C0UUuQIX.mjs";
2
- import "./Codes-CjiW7Pdl.mjs";
1
+ import { t as Request } from "./Request-BvScDpeu.js";
2
+ import "./Tag-B5gWV2XF.js";
3
3
  //#region src/request/ServerListRequest.ts
4
4
  /**
5
5
  * Server List Request - Request the list of servers
@@ -11,5 +11,3 @@ var ServerListRequest = class extends Request {
11
11
  };
12
12
  //#endregion
13
13
  export { ServerListRequest };
14
-
15
- //# sourceMappingURL=ServerListRequest-FwFQBp12.mjs.map