@torrent-tv/proxy 2.101.26 → 2.101.28
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
|
@@ -281,6 +281,8 @@ 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),
|
|
285
|
+
fileAvailable: typeof features.fileAvailable === "boolean" ? features.fileAvailable : null,
|
|
284
286
|
headerRemaining: nonNegative(features.headerRemaining),
|
|
285
287
|
peers: nonNegative(features.peers),
|
|
286
288
|
at: this.#now()
|
|
@@ -291,9 +293,10 @@ export class LocalObservations {
|
|
|
291
293
|
|
|
292
294
|
/**
|
|
293
295
|
* Predict this host's first-frame wait from the closest measured start with
|
|
294
|
-
* the same media suffix. Distance
|
|
295
|
-
*
|
|
296
|
-
* in their raw units.
|
|
296
|
+
* the same media suffix. Distance uses squared log-ratios for numeric
|
|
297
|
+
* inputs and exact-state distance for categorical inputs; it does not mix
|
|
298
|
+
* bytes, bit rates and peers in their raw units. Missing data contributes
|
|
299
|
+
* distance only when the other observation measured that input.
|
|
297
300
|
*
|
|
298
301
|
* @param {object} features
|
|
299
302
|
* @returns {number | null}
|
|
@@ -303,24 +306,40 @@ export class LocalObservations {
|
|
|
303
306
|
const readings = this.#entries.firstFrame[this.#firstFrameKey()] ?? [];
|
|
304
307
|
const candidates = readings.filter(reading => reading.extension === (features.extension ?? ""));
|
|
305
308
|
if (candidates.length === 0) return null;
|
|
306
|
-
const dimensions = ["fileLength", "downloadSpeed", "linkMbps", "linkSampleAgeMs", "
|
|
309
|
+
const dimensions = ["fileLength", "downloadSpeed", "linkMbps", "linkSampleAgeMs", "preparedOutputBytes",
|
|
310
|
+
"fileAvailable", "headerRemaining", "peers"];
|
|
307
311
|
const scales = new Map(dimensions.map(key => [key, median(candidates
|
|
308
|
-
.map(reading => nonNegative(reading[key]))
|
|
312
|
+
.map(reading => key === "fileAvailable" ? null : nonNegative(reading[key]))
|
|
309
313
|
.filter(value => value !== null && value > 0))]));
|
|
310
314
|
let best = null;
|
|
311
315
|
for (const reading of candidates) {
|
|
312
316
|
let distance = 0;
|
|
313
317
|
let used = 0;
|
|
318
|
+
let shared = 0;
|
|
314
319
|
for (const key of dimensions) {
|
|
320
|
+
const current = key === "fileAvailable"
|
|
321
|
+
? (typeof features[key] === "boolean" ? features[key] : null)
|
|
322
|
+
: nonNegative(features[key]);
|
|
323
|
+
const previous = key === "fileAvailable"
|
|
324
|
+
? (typeof reading[key] === "boolean" ? reading[key] : null)
|
|
325
|
+
: nonNegative(reading[key]);
|
|
326
|
+
if (current === null && previous === null) continue;
|
|
327
|
+
if (current === null || previous === null) {
|
|
328
|
+
distance += 1;
|
|
329
|
+
used += 1;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
shared += 1;
|
|
315
333
|
const scale = scales.get(key);
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
334
|
+
const difference = typeof current === "boolean" && typeof previous === "boolean"
|
|
335
|
+
? Number(current !== previous)
|
|
336
|
+
: scale === null
|
|
337
|
+
? Number(current !== previous)
|
|
338
|
+
: Math.log1p(current / scale) - Math.log1p(previous / scale);
|
|
320
339
|
distance += difference * difference;
|
|
321
340
|
used += 1;
|
|
322
341
|
}
|
|
323
|
-
if (used === 0) continue;
|
|
342
|
+
if (used === 0 || shared === 0) continue;
|
|
324
343
|
distance /= used;
|
|
325
344
|
if (!best || distance < best.distance || (distance === best.distance && reading.at > best.reading.at)) {
|
|
326
345
|
best = { distance, reading };
|
|
@@ -119,6 +119,8 @@ 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),
|
|
123
|
+
fileAvailable: null,
|
|
122
124
|
headerRemaining: null,
|
|
123
125
|
peers: null
|
|
124
126
|
};
|
|
@@ -160,6 +162,9 @@ export class ViewerRequests {
|
|
|
160
162
|
linkMbps: Number.isFinite(linkMbps) && linkMbps > 0
|
|
161
163
|
? linkMbps : this.#host.viewers.get(consumerId)?.linkReading()?.linkMbps,
|
|
162
164
|
linkSampleAgeMs: Number.isFinite(linkSampleAgeMs) && linkSampleAgeMs >= 0 ? linkSampleAgeMs : null,
|
|
165
|
+
preparedOutputBytes: Number.isSafeInteger(fileIndex) && fileIndex >= 0
|
|
166
|
+
? this.#preparedOutputBytes(sourceKey, fileIndex) : null,
|
|
167
|
+
fileAvailable: typeof stats?.fileAvailable === "boolean" ? stats.fileAvailable : null,
|
|
163
168
|
headerRemaining: Number.isFinite(stats?.headerBytes) && Number.isFinite(stats?.headerDownloadedBytes)
|
|
164
169
|
? Math.max(0, stats.headerBytes - stats.headerDownloadedBytes) : null,
|
|
165
170
|
peers: stats?.connectedPeers ?? stats?.numPeers
|
|
@@ -221,6 +226,23 @@ export class ViewerRequests {
|
|
|
221
226
|
return true;
|
|
222
227
|
}
|
|
223
228
|
|
|
229
|
+
#preparedOutputBytes(sourceKey, fileIndex) {
|
|
230
|
+
const outputs = this.#host.outputs;
|
|
231
|
+
const segmentStore = this.#host.segmentStore;
|
|
232
|
+
if (!outputs?.values || !segmentStore?.sizesOf) return null;
|
|
233
|
+
let bytes = 0;
|
|
234
|
+
const seen = new Set();
|
|
235
|
+
for (const output of outputs.values()) {
|
|
236
|
+
if (output.file?.sourceKey !== sourceKey || output.file?.fileIndex !== fileIndex || !output.outputKey) continue;
|
|
237
|
+
if (seen.has(output.outputKey)) continue;
|
|
238
|
+
seen.add(output.outputKey);
|
|
239
|
+
for (const size of segmentStore.sizesOf(output.outputKey).values()) {
|
|
240
|
+
if (Number.isFinite(size) && size > 0) bytes += size;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return bytes;
|
|
244
|
+
}
|
|
245
|
+
|
|
224
246
|
#pruneEarlyWaits() {
|
|
225
247
|
const cutoff = Date.now() - 30 * 60_000;
|
|
226
248
|
for (const [key, value] of this.#earlyWaits) {
|