@torrent-tv/proxy 2.107.3 → 2.107.5
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
|
@@ -70,8 +70,30 @@
|
|
|
70
70
|
* (`EncodeRun.speedX`), with input waits and stops taken out. Zero or less
|
|
71
71
|
* means nothing has measured it yet, and then no comparison involving its
|
|
72
72
|
* speed can be made.
|
|
73
|
+
* @property {boolean} [fixedEnd] - Whether `to` is where its process ends. An
|
|
74
|
+
* original input is one copied stretch and its run makes nothing past it; a
|
|
75
|
+
* packet input's run grows past `to` one piece at a time, so its `to` bounds
|
|
76
|
+
* nothing yet (`EncodeRuns`).
|
|
73
77
|
*/
|
|
74
78
|
|
|
79
|
+
/**
|
|
80
|
+
* The last number a live run can make where it stands: its `to` when that is
|
|
81
|
+
* where its process ends, otherwise no bound.
|
|
82
|
+
*
|
|
83
|
+
* Counted as reaching every number after it instead, a run whose stretch ended
|
|
84
|
+
* at #204 was the plan's answer for #205: the run starting on #205 was stopped
|
|
85
|
+
* as "the film is no worse off without it", none was placed there again, and
|
|
86
|
+
* the viewer on the last piece of Drifters 04 waited for minutes (field
|
|
87
|
+
* 2026-10-05, torrent-tv/meta#117).
|
|
88
|
+
*
|
|
89
|
+
* @param {LiveRun} run
|
|
90
|
+
* @returns {number}
|
|
91
|
+
*/
|
|
92
|
+
function roadEndOf(run) {
|
|
93
|
+
const to = Number(run.to);
|
|
94
|
+
return run.fixedEnd === true && to >= Number(run.from) ? to : Number.POSITIVE_INFINITY;
|
|
95
|
+
}
|
|
96
|
+
|
|
75
97
|
/**
|
|
76
98
|
* What a viewer is waiting for. Which viewer is deliberately absent.
|
|
77
99
|
*
|
|
@@ -267,7 +289,8 @@ export function planEncoders({
|
|
|
267
289
|
// outside.
|
|
268
290
|
const priced = (encoders) => {
|
|
269
291
|
const perPiece = pieceAt(encoders.length);
|
|
270
|
-
return encoders.map((encoder) => ({ at: encoder.at, delaySec: encoder.owes(perPiece)
|
|
292
|
+
return encoders.map((encoder) => ({ at: encoder.at, delaySec: encoder.owes(perPiece),
|
|
293
|
+
through: encoder.through ?? Number.POSITIVE_INFINITY }));
|
|
271
294
|
};
|
|
272
295
|
|
|
273
296
|
|
|
@@ -442,7 +465,8 @@ export function planEncoders({
|
|
|
442
465
|
at: positions[index],
|
|
443
466
|
owes: head === positions[index]
|
|
444
467
|
? (piece) => finishesItsPieceIn(filler, piece)
|
|
445
|
-
: (piece) => moveSec + piece
|
|
468
|
+
: (piece) => moveSec + piece,
|
|
469
|
+
through: head === positions[index] ? roadEndOf(filler) : Number.POSITIVE_INFINITY
|
|
446
470
|
});
|
|
447
471
|
}
|
|
448
472
|
// Bodies nobody was given a position for go on working where they stand,
|
|
@@ -465,7 +489,8 @@ export function planEncoders({
|
|
|
465
489
|
at: head,
|
|
466
490
|
owes: cutInFront
|
|
467
491
|
? (piece) => moveSec + piece
|
|
468
|
-
: (piece) => finishesItsPieceIn(run, piece)
|
|
492
|
+
: (piece) => finishesItsPieceIn(run, piece),
|
|
493
|
+
through: roadEndOf(run)
|
|
469
494
|
});
|
|
470
495
|
}
|
|
471
496
|
const scored = latenessOf(priced(encoders), coverage, wanted, untilNeeded, rate / contentionPenaltyFor(Math.max(0, encoders.length - 1)), refetchPerSegment, segmentSeconds, neverSec);
|
|
@@ -506,7 +531,8 @@ export function planEncoders({
|
|
|
506
531
|
at,
|
|
507
532
|
owes: at === head
|
|
508
533
|
? (piece) => finishesItsPieceIn(run, piece)
|
|
509
|
-
: (piece) => moveSec + piece
|
|
534
|
+
: (piece) => moveSec + piece,
|
|
535
|
+
through: at === head ? roadEndOf(run) : Number.POSITIVE_INFINITY
|
|
510
536
|
});
|
|
511
537
|
}
|
|
512
538
|
for (let index = 0; index < positions.length; index += 1) {
|
|
@@ -867,7 +893,8 @@ function latenessOf(encoders, coverage, wanted, untilNeeded, rate, refetchSecPer
|
|
|
867
893
|
let byWhom = null;
|
|
868
894
|
for (let at = 0; at < encoders.length; at += 1) {
|
|
869
895
|
const encoder = encoders[at];
|
|
870
|
-
|
|
896
|
+
// Behind it, or standing on a road that ends before it.
|
|
897
|
+
if (encoder.at > index || index > encoder.through) {
|
|
871
898
|
continue;
|
|
872
899
|
}
|
|
873
900
|
// WHEN THIS BODY REACHES THIS NUMBER. `delaySec` is when it finishes the
|
|
@@ -1160,15 +1187,8 @@ function gapFinderFor(coverage, surviving, rate, refetchSecPerSegment = 0) {
|
|
|
1160
1187
|
const head = Number(/** @type {{ head?: number }} */ (run).head);
|
|
1161
1188
|
placed.push({
|
|
1162
1189
|
at: Number.isFinite(head) ? head : Number(/** @type {{ from: number }} */ (run).from),
|
|
1163
|
-
// A live run's road
|
|
1164
|
-
|
|
1165
|
-
// A run given no end drives to the end of the film, which is what makes
|
|
1166
|
-
// the price of cutting in front of it real. Written out rather than
|
|
1167
|
-
// imported: this file depends on nothing, and that is what lets it be
|
|
1168
|
-
// exercised with plain values alone.
|
|
1169
|
-
to: Number(/** @type {{ to: number }} */ (run).to) < Number(/** @type {{ from: number }} */ (run).from)
|
|
1170
|
-
? Number.POSITIVE_INFINITY
|
|
1171
|
-
: Number(/** @type {{ to: number }} */ (run).to)
|
|
1190
|
+
// A live run's road: nothing past its end is reached by it.
|
|
1191
|
+
to: roadEndOf(/** @type {LiveRun} */ (run))
|
|
1172
1192
|
});
|
|
1173
1193
|
}
|
|
1174
1194
|
return (at, bound, deadlineAt, alsoPlaced) => {
|
|
@@ -1192,6 +1212,7 @@ function gapFinderFor(coverage, surviving, rate, refetchSecPerSegment = 0) {
|
|
|
1192
1212
|
// millions of steps, and the plan held the proxy's thread for most of every
|
|
1193
1213
|
// second (Home Assistant 2026-10-08, torrent-tv/meta#151).
|
|
1194
1214
|
const standing = [...placed.map((live) => live.at), ...(alsoPlaced ?? [])];
|
|
1215
|
+
const roadEnds = [...placed.map((live) => live.to), ...(alsoPlaced ?? []).map(() => Number.POSITIVE_INFINITY)];
|
|
1195
1216
|
const passed = standing.map((a) => coverage.madeBetween(a, start - 1));
|
|
1196
1217
|
for (let index = start; index <= last; index += 1) {
|
|
1197
1218
|
const readyHere = coverage.isReady(index);
|
|
@@ -1217,8 +1238,9 @@ function gapFinderFor(coverage, surviving, rate, refetchSecPerSegment = 0) {
|
|
|
1217
1238
|
let soonest = Number.POSITIVE_INFINITY;
|
|
1218
1239
|
for (let which = 0; which < standing.length; which += 1) {
|
|
1219
1240
|
const a = standing[which];
|
|
1220
|
-
if (a > index) {
|
|
1221
|
-
// Standing past it
|
|
1241
|
+
if (a > index || index > roadEnds[which]) {
|
|
1242
|
+
// Standing past it, or on a road that ends before it. Encoders only
|
|
1243
|
+
// move forward, so it never will.
|
|
1222
1244
|
continue;
|
|
1223
1245
|
}
|
|
1224
1246
|
if (a === index) {
|
|
@@ -1312,6 +1312,9 @@ export class EncodeRuns {
|
|
|
1312
1312
|
from: run.from, to: run.to });
|
|
1313
1313
|
if (admittedInput.original) {
|
|
1314
1314
|
run.originalInput = admittedInput;
|
|
1315
|
+
// Its stretch is all it can make: the plan counts it reaching nothing
|
|
1316
|
+
// past `to` (torrent-tv/meta#117).
|
|
1317
|
+
run.fixedEnd = true;
|
|
1315
1318
|
// Every number of the stretch answers to its one key, so a failure
|
|
1316
1319
|
// anywhere inside it is recorded against the stretch that was commanded.
|
|
1317
1320
|
run.admittedInputKeys = new Map(Array.from({ length: inputEnd - safeIndex + 1 }, (_, offset) => [safeIndex + offset, inputKey]));
|
|
@@ -11,6 +11,13 @@ import { logger } from "../../utils/logger.js";
|
|
|
11
11
|
import { isOutputName, OutputSpec } from "../encode/output/index.js";
|
|
12
12
|
import { withSubtitleReadiness } from "./subtitle-readiness.js";
|
|
13
13
|
|
|
14
|
+
/** @param {{ spec: { sourceFileIndexes: number[] }, file: { fileIndex: number } }} output */
|
|
15
|
+
export function sourceFileIndexesForOutput(output) {
|
|
16
|
+
return output.spec.sourceFileIndexes.length > 0
|
|
17
|
+
? [...output.spec.sourceFileIndexes]
|
|
18
|
+
: [output.file.fileIndex];
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
/**
|
|
15
22
|
* The segment number an assignment is recorded under for this file, −1 for the
|
|
16
23
|
* init, or null for anything that is neither (a playlist).
|
|
@@ -1044,7 +1051,8 @@ export class ViewerRequests {
|
|
|
1044
1051
|
subtitle ? this.#host.subtitleReadyFor?.(viewer) !== false : true);
|
|
1045
1052
|
forecast.operations = outputs.flatMap((output, index) => {
|
|
1046
1053
|
const common = { speed: this.#host.playbackReadiness.forecastRate(tracks[index].readings, now, 0, "piece"),
|
|
1047
|
-
processedSeconds: tracks[index].processedSeconds
|
|
1054
|
+
processedSeconds: tracks[index].processedSeconds,
|
|
1055
|
+
sourceFileIndexes: sourceFileIndexesForOutput(output) };
|
|
1048
1056
|
return [
|
|
1049
1057
|
...(output.spec.video ? [{ ...common, track: "video",
|
|
1050
1058
|
operation: output.spec.transcodesVideo ? "encode" : "copy",
|