@torrent-tv/proxy 2.101.26 → 2.101.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.101.26",
3
+ "version": "2.101.27",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -281,6 +281,7 @@ export class LocalObservations {
281
281
  downloadSpeed: nonNegative(features.downloadSpeed),
282
282
  linkMbps: nonNegative(features.linkMbps),
283
283
  linkSampleAgeMs: nonNegative(features.linkSampleAgeMs),
284
+ preparedOutputBytes: nonNegative(features.preparedOutputBytes),
284
285
  headerRemaining: nonNegative(features.headerRemaining),
285
286
  peers: nonNegative(features.peers),
286
287
  at: this.#now()
@@ -303,7 +304,8 @@ export class LocalObservations {
303
304
  const readings = this.#entries.firstFrame[this.#firstFrameKey()] ?? [];
304
305
  const candidates = readings.filter(reading => reading.extension === (features.extension ?? ""));
305
306
  if (candidates.length === 0) return null;
306
- const dimensions = ["fileLength", "downloadSpeed", "linkMbps", "linkSampleAgeMs", "headerRemaining", "peers"];
307
+ const dimensions = ["fileLength", "downloadSpeed", "linkMbps", "linkSampleAgeMs", "preparedOutputBytes",
308
+ "headerRemaining", "peers"];
307
309
  const scales = new Map(dimensions.map(key => [key, median(candidates
308
310
  .map(reading => nonNegative(reading[key]))
309
311
  .filter(value => value !== null && value > 0))]));
@@ -119,6 +119,7 @@ export class ViewerRequests {
119
119
  linkMbps: Number.isFinite(linkMbps) && linkMbps > 0
120
120
  ? linkMbps : this.#host.viewers.get(consumerId)?.linkReading()?.linkMbps,
121
121
  linkSampleAgeMs: Number.isFinite(linkSampleAgeMs) && linkSampleAgeMs >= 0 ? linkSampleAgeMs : null,
122
+ preparedOutputBytes: this.#preparedOutputBytes(sourceKey, fileIndex),
122
123
  headerRemaining: null,
123
124
  peers: null
124
125
  };
@@ -160,6 +161,8 @@ export class ViewerRequests {
160
161
  linkMbps: Number.isFinite(linkMbps) && linkMbps > 0
161
162
  ? linkMbps : this.#host.viewers.get(consumerId)?.linkReading()?.linkMbps,
162
163
  linkSampleAgeMs: Number.isFinite(linkSampleAgeMs) && linkSampleAgeMs >= 0 ? linkSampleAgeMs : null,
164
+ preparedOutputBytes: Number.isSafeInteger(fileIndex) && fileIndex >= 0
165
+ ? this.#preparedOutputBytes(sourceKey, fileIndex) : null,
163
166
  headerRemaining: Number.isFinite(stats?.headerBytes) && Number.isFinite(stats?.headerDownloadedBytes)
164
167
  ? Math.max(0, stats.headerBytes - stats.headerDownloadedBytes) : null,
165
168
  peers: stats?.connectedPeers ?? stats?.numPeers
@@ -221,6 +224,23 @@ export class ViewerRequests {
221
224
  return true;
222
225
  }
223
226
 
227
+ #preparedOutputBytes(sourceKey, fileIndex) {
228
+ const outputs = this.#host.outputs;
229
+ const segmentStore = this.#host.segmentStore;
230
+ if (!outputs?.values || !segmentStore?.sizesOf) return null;
231
+ let bytes = 0;
232
+ const seen = new Set();
233
+ for (const output of outputs.values()) {
234
+ if (output.file?.sourceKey !== sourceKey || output.file?.fileIndex !== fileIndex || !output.outputKey) continue;
235
+ if (seen.has(output.outputKey)) continue;
236
+ seen.add(output.outputKey);
237
+ for (const size of segmentStore.sizesOf(output.outputKey).values()) {
238
+ if (Number.isFinite(size) && size > 0) bytes += size;
239
+ }
240
+ }
241
+ return bytes;
242
+ }
243
+
224
244
  #pruneEarlyWaits() {
225
245
  const cutoff = Date.now() - 30 * 60_000;
226
246
  for (const [key, value] of this.#earlyWaits) {