@torrent-tv/proxy 2.101.27 → 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
|
@@ -282,6 +282,7 @@ export class LocalObservations {
|
|
|
282
282
|
linkMbps: nonNegative(features.linkMbps),
|
|
283
283
|
linkSampleAgeMs: nonNegative(features.linkSampleAgeMs),
|
|
284
284
|
preparedOutputBytes: nonNegative(features.preparedOutputBytes),
|
|
285
|
+
fileAvailable: typeof features.fileAvailable === "boolean" ? features.fileAvailable : null,
|
|
285
286
|
headerRemaining: nonNegative(features.headerRemaining),
|
|
286
287
|
peers: nonNegative(features.peers),
|
|
287
288
|
at: this.#now()
|
|
@@ -292,9 +293,10 @@ export class LocalObservations {
|
|
|
292
293
|
|
|
293
294
|
/**
|
|
294
295
|
* Predict this host's first-frame wait from the closest measured start with
|
|
295
|
-
* the same media suffix. Distance
|
|
296
|
-
*
|
|
297
|
-
* 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.
|
|
298
300
|
*
|
|
299
301
|
* @param {object} features
|
|
300
302
|
* @returns {number | null}
|
|
@@ -305,24 +307,39 @@ export class LocalObservations {
|
|
|
305
307
|
const candidates = readings.filter(reading => reading.extension === (features.extension ?? ""));
|
|
306
308
|
if (candidates.length === 0) return null;
|
|
307
309
|
const dimensions = ["fileLength", "downloadSpeed", "linkMbps", "linkSampleAgeMs", "preparedOutputBytes",
|
|
308
|
-
"headerRemaining", "peers"];
|
|
310
|
+
"fileAvailable", "headerRemaining", "peers"];
|
|
309
311
|
const scales = new Map(dimensions.map(key => [key, median(candidates
|
|
310
|
-
.map(reading => nonNegative(reading[key]))
|
|
312
|
+
.map(reading => key === "fileAvailable" ? null : nonNegative(reading[key]))
|
|
311
313
|
.filter(value => value !== null && value > 0))]));
|
|
312
314
|
let best = null;
|
|
313
315
|
for (const reading of candidates) {
|
|
314
316
|
let distance = 0;
|
|
315
317
|
let used = 0;
|
|
318
|
+
let shared = 0;
|
|
316
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;
|
|
317
333
|
const scale = scales.get(key);
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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);
|
|
322
339
|
distance += difference * difference;
|
|
323
340
|
used += 1;
|
|
324
341
|
}
|
|
325
|
-
if (used === 0) continue;
|
|
342
|
+
if (used === 0 || shared === 0) continue;
|
|
326
343
|
distance /= used;
|
|
327
344
|
if (!best || distance < best.distance || (distance === best.distance && reading.at > best.reading.at)) {
|
|
328
345
|
best = { distance, reading };
|
|
@@ -120,6 +120,7 @@ export class ViewerRequests {
|
|
|
120
120
|
? linkMbps : this.#host.viewers.get(consumerId)?.linkReading()?.linkMbps,
|
|
121
121
|
linkSampleAgeMs: Number.isFinite(linkSampleAgeMs) && linkSampleAgeMs >= 0 ? linkSampleAgeMs : null,
|
|
122
122
|
preparedOutputBytes: this.#preparedOutputBytes(sourceKey, fileIndex),
|
|
123
|
+
fileAvailable: null,
|
|
123
124
|
headerRemaining: null,
|
|
124
125
|
peers: null
|
|
125
126
|
};
|
|
@@ -163,6 +164,7 @@ export class ViewerRequests {
|
|
|
163
164
|
linkSampleAgeMs: Number.isFinite(linkSampleAgeMs) && linkSampleAgeMs >= 0 ? linkSampleAgeMs : null,
|
|
164
165
|
preparedOutputBytes: Number.isSafeInteger(fileIndex) && fileIndex >= 0
|
|
165
166
|
? this.#preparedOutputBytes(sourceKey, fileIndex) : null,
|
|
167
|
+
fileAvailable: typeof stats?.fileAvailable === "boolean" ? stats.fileAvailable : null,
|
|
166
168
|
headerRemaining: Number.isFinite(stats?.headerBytes) && Number.isFinite(stats?.headerDownloadedBytes)
|
|
167
169
|
? Math.max(0, stats.headerBytes - stats.headerDownloadedBytes) : null,
|
|
168
170
|
peers: stats?.connectedPeers ?? stats?.numPeers
|