@torrent-tv/proxy 2.107.42 → 2.107.43
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
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
|
|
40
40
|
import { ENCODE_RUN_EVENT, ENCODE_RUN_STATE, INITIAL_RUN_STATE, nextState } from "./encode-run-state.js";
|
|
41
41
|
import { classifyEncodeExit, ENCODE_EXIT } from "./encode-exit.js";
|
|
42
|
-
import {
|
|
42
|
+
import { workDeltaBetween } from "./encoder-readings.js";
|
|
43
43
|
import { RunClock } from "./RunClock.js";
|
|
44
44
|
import { RunProgress } from "./RunProgress.js";
|
|
45
45
|
|
|
@@ -229,7 +229,7 @@ export class EncodeRun {
|
|
|
229
229
|
* @param {{ info: (line: string) => void, warn: (line: string) => void, error?: (line: string) => void }} params.logger
|
|
230
230
|
* @param {() => number} [params.now]
|
|
231
231
|
* @param {(ended: RunEnded) => void} [params.onEnded]
|
|
232
|
-
* @param {(reading: { speed: number, at: number }) => void} [params.onSpeedMeasured] -
|
|
232
|
+
* @param {(reading: { speed: number, at: number, workSeconds: number, workingSeconds: number }) => void} [params.onSpeedMeasured] -
|
|
233
233
|
* Told each time this run has measured its processing speed, once per
|
|
234
234
|
* reading.
|
|
235
235
|
* @param {(name: string, following: string | null) => string | null} [params.onClosed] - Called with the
|
|
@@ -353,10 +353,10 @@ export class EncodeRun {
|
|
|
353
353
|
}
|
|
354
354
|
|
|
355
355
|
/**
|
|
356
|
-
* The
|
|
357
|
-
* piece
|
|
356
|
+
* The processing speed, its produced media and active working time, with
|
|
357
|
+
* the measurement time; null before a piece supplies a measured interval.
|
|
358
358
|
*
|
|
359
|
-
* @returns {{ speed: number, at: number } | null}
|
|
359
|
+
* @returns {{ speed: number, at: number, workSeconds: number, workingSeconds: number } | null}
|
|
360
360
|
*/
|
|
361
361
|
get speedReading() {
|
|
362
362
|
return this.#speedReading === null ? null : { ...this.#speedReading };
|
|
@@ -764,9 +764,9 @@ export class EncodeRun {
|
|
|
764
764
|
if (sample === null) {
|
|
765
765
|
return;
|
|
766
766
|
}
|
|
767
|
-
const
|
|
768
|
-
if (
|
|
769
|
-
this.#speedReading = { speed, at: sample.at };
|
|
767
|
+
const work = workDeltaBetween(this.#pieceSample, sample);
|
|
768
|
+
if (work !== null) {
|
|
769
|
+
this.#speedReading = { speed: work.workSeconds / work.workingSeconds, at: sample.at, ...work };
|
|
770
770
|
this.#pieceSample = sample;
|
|
771
771
|
this.#speedMeasurementPending = false;
|
|
772
772
|
this.onSpeedMeasured(this.speedReading);
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
export class SpeedReadings {
|
|
17
|
-
/** @type {WeakMap<object, Array<{ speed: number, at: number }>>} */
|
|
17
|
+
/** @type {WeakMap<object, Array<{ speed: number, at: number, workSeconds?: number, workingSeconds?: number }>>} */
|
|
18
18
|
#byOutput = new WeakMap();
|
|
19
19
|
#keepMs;
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ export class SpeedReadings {
|
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* @param {object} output
|
|
28
|
-
* @param {{ speed: number, at: number } | null} reading
|
|
28
|
+
* @param {{ speed: number, at: number, workSeconds?: number, workingSeconds?: number } | null} reading
|
|
29
29
|
*/
|
|
30
30
|
note(output, reading) {
|
|
31
31
|
if (!output || !(reading?.speed > 0) || !Number.isFinite(reading.at)) return;
|
|
@@ -33,7 +33,12 @@ export class SpeedReadings {
|
|
|
33
33
|
if (!readings) this.#byOutput.set(output, readings = []);
|
|
34
34
|
let place = readings.length;
|
|
35
35
|
while (place > 0 && readings[place - 1].at > reading.at) place -= 1;
|
|
36
|
-
|
|
36
|
+
const sample = { speed: reading.speed, at: reading.at };
|
|
37
|
+
if (Number.isFinite(reading.workSeconds) && reading.workSeconds > 0 &&
|
|
38
|
+
Number.isFinite(reading.workingSeconds) && reading.workingSeconds > 0) {
|
|
39
|
+
Object.assign(sample, { workSeconds: reading.workSeconds, workingSeconds: reading.workingSeconds });
|
|
40
|
+
}
|
|
41
|
+
readings.splice(place, 0, sample);
|
|
37
42
|
const cutoff = readings.at(-1).at - this.#keepMs;
|
|
38
43
|
// As the forecast's own trend keeps them: the newest one before the horizon stays.
|
|
39
44
|
while (readings.length > 1 && readings[1].at <= cutoff) readings.shift();
|
|
@@ -41,7 +46,7 @@ export class SpeedReadings {
|
|
|
41
46
|
|
|
42
47
|
/**
|
|
43
48
|
* @param {object} output
|
|
44
|
-
* @returns {Array<{ speed: number, at: number }>} The
|
|
49
|
+
* @returns {Array<{ speed: number, at: number, workSeconds?: number, workingSeconds?: number }>} The readings in measurement order.
|
|
45
50
|
*/
|
|
46
51
|
windowOf(output) {
|
|
47
52
|
return [...(this.#byOutput.get(output) ?? [])];
|
|
@@ -31,13 +31,21 @@
|
|
|
31
31
|
* @returns {number | null} Film seconds made per second of the run's own work.
|
|
32
32
|
*/
|
|
33
33
|
export function speedFromWork(previous, current) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
const work = workDeltaBetween(previous, current);
|
|
35
|
+
return work === null ? null : work.workSeconds / work.workingSeconds;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Produced media and active processing time between samples of one run.
|
|
40
|
+
* @param {WorkSample | null} previous
|
|
41
|
+
* @param {WorkSample | null} current
|
|
42
|
+
* @returns {{ workSeconds: number, workingSeconds: number } | null}
|
|
43
|
+
*/
|
|
44
|
+
export function workDeltaBetween(previous, current) {
|
|
45
|
+
if (!previous || !current) return null;
|
|
46
|
+
const workSeconds = current.producedSeconds - previous.producedSeconds;
|
|
38
47
|
const workingSeconds = (current.workingMs - previous.workingMs) / 1000;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return producedSeconds / workingSeconds;
|
|
48
|
+
return Number.isFinite(workSeconds) && workSeconds > 0 &&
|
|
49
|
+
Number.isFinite(workingSeconds) && workingSeconds > 0
|
|
50
|
+
? { workSeconds, workingSeconds } : null;
|
|
43
51
|
}
|
|
@@ -76,12 +76,13 @@ export function forecastRate(readings, now = Date.now(), horizonSeconds = 0, wei
|
|
|
76
76
|
* ordered by when each was taken, readings taken in the same millisecond kept
|
|
77
77
|
* apart. Null for no reading.
|
|
78
78
|
*
|
|
79
|
-
* @param {Array<{ at: number, speed?: number, value?: number }>} readings
|
|
79
|
+
* @param {Array<{ at: number, speed?: number, value?: number, workSeconds?: number, workingSeconds?: number }>} readings
|
|
80
80
|
* @returns {object | null}
|
|
81
81
|
*/
|
|
82
82
|
export function rateSummaryOf(readings) {
|
|
83
83
|
const ordered = (Array.isArray(readings) ? readings : [])
|
|
84
|
-
.map(reading => ({ at: reading?.at, value: reading?.value ?? reading?.speed
|
|
84
|
+
.map(reading => ({ at: reading?.at, value: reading?.value ?? reading?.speed,
|
|
85
|
+
workSeconds: reading?.workSeconds, workingSeconds: reading?.workingSeconds }))
|
|
85
86
|
.filter(reading => Number.isFinite(reading.at) && Number.isFinite(reading.value) && reading.value >= 0)
|
|
86
87
|
.sort((left, right) => left.at - right.at);
|
|
87
88
|
return ordered.length > 0 ? summarizeRate(ordered) : null;
|
|
@@ -278,9 +279,9 @@ export function predictPlaybackReadiness(input = {}) {
|
|
|
278
279
|
[{ start: at, end: add(at, measured ? nearest(fromSeconds(buffered), unit) :
|
|
279
280
|
rescale(fromSeconds(buffered), unit)), frame: zero }],
|
|
280
281
|
ready: new Set(Array.isArray(track.readySegmentIndices) ? track.readySegmentIndices : []),
|
|
281
|
-
// Film made over
|
|
282
|
-
//
|
|
283
|
-
//
|
|
282
|
+
// Film made over active processing time, summed over the readings retained.
|
|
283
|
+
// Point-only legacy readings retain their equal-work harmonic summary.
|
|
284
|
+
// The last reading alone is one piece's content and machine — a
|
|
284
285
|
// first piece of credits read 6.49x and started a cold AVI on 2.4 s of
|
|
285
286
|
// buffer that the next piece, at 0.57x, did not hold (torrent-tv/meta#178).
|
|
286
287
|
curve: rateCurve(track.readings, now, "piece"),
|
|
@@ -1417,6 +1418,10 @@ function rateCurve(readings, now, weighting = "last") {
|
|
|
1417
1418
|
|
|
1418
1419
|
function summarizeRate(readings) {
|
|
1419
1420
|
const latest = readings.at(-1);
|
|
1421
|
+
const workKnown = readings.every(reading => Number.isFinite(reading.workSeconds) && reading.workSeconds > 0 &&
|
|
1422
|
+
Number.isFinite(reading.workingSeconds) && reading.workingSeconds > 0);
|
|
1423
|
+
const workSeconds = workKnown ? readings.reduce((sum, reading) => sum + reading.workSeconds, 0) : null;
|
|
1424
|
+
const workingSeconds = workKnown ? readings.reduce((sum, reading) => sum + reading.workingSeconds, 0) : null;
|
|
1420
1425
|
let weighted = 0;
|
|
1421
1426
|
for (let index = 0; index + 1 < readings.length; index += 1) {
|
|
1422
1427
|
weighted += readings[index].value * (readings[index + 1].at - readings[index].at);
|
|
@@ -1427,12 +1432,13 @@ function summarizeRate(readings) {
|
|
|
1427
1432
|
lastAt: latest.at,
|
|
1428
1433
|
lastValue: latest.value,
|
|
1429
1434
|
meanValue: readings.reduce((sum, reading) => sum + reading.value, 0) / readings.length,
|
|
1430
|
-
//
|
|
1435
|
+
// Equal-work summary for legacy readings without measured work quantities.
|
|
1431
1436
|
harmonicValue: readings.some(reading => !(reading.value > 0)) ? 0
|
|
1432
1437
|
: readings.length / readings.reduce((sum, reading) => sum + 1 / reading.value, 0),
|
|
1433
1438
|
// Each reading holding until the next: quantity over the span.
|
|
1434
1439
|
timeWeightedValue: spanMs > 0 ? weighted / spanMs : latest.value,
|
|
1435
|
-
spanSeconds: spanMs / 1000
|
|
1440
|
+
spanSeconds: spanMs / 1000,
|
|
1441
|
+
...(workKnown ? { workSeconds, workingSeconds, workRateValue: workSeconds / workingSeconds } : {})
|
|
1436
1442
|
};
|
|
1437
1443
|
}
|
|
1438
1444
|
|
|
@@ -1440,7 +1446,8 @@ function rateCurveFrom(summary, weighting = "last") {
|
|
|
1440
1446
|
// Conditional projection of the measured service. No exponential
|
|
1441
1447
|
// relaxation, smoothing time, slope extrapolation or guessed recovery.
|
|
1442
1448
|
// A new measurement changes the integral; polling does not change its rate.
|
|
1443
|
-
const value = weighting === "piece" && Number.isFinite(summary.
|
|
1449
|
+
const value = weighting === "piece" && Number.isFinite(summary.workRateValue) ? summary.workRateValue
|
|
1450
|
+
: weighting === "piece" && Number.isFinite(summary.harmonicValue) ? summary.harmonicValue
|
|
1444
1451
|
: weighting === "time" && Number.isFinite(summary.timeWeightedValue) ? summary.timeWeightedValue
|
|
1445
1452
|
: summary.lastValue;
|
|
1446
1453
|
const rate = Math.max(0, value);
|