@torrent-tv/proxy 2.97.10 → 2.97.11

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.97.10",
3
+ "version": "2.97.11",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -51,13 +51,11 @@ export class EncodeInputs {
51
51
  #capacity;
52
52
  #urgent;
53
53
  #rankAt;
54
- #deadlineOf;
55
- #firstPieceIn;
56
54
  #log;
57
55
  #now;
58
56
 
59
57
  constructor({ resolve, readRanges, heldRanges = null, reviseBudget, changed, failed, capacity = () => null, urgent = () => true,
60
- rankAt = () => null, deadlineOf = () => null, firstPieceIn = () => null, openOf = () => null, log = () => {}, now = Date.now }) {
58
+ rankAt = () => null, openOf = () => null, log = () => {}, now = Date.now }) {
61
59
  this.#openOf = openOf;
62
60
  this.#resolve = resolve;
63
61
  this.#read = readRanges;
@@ -68,8 +66,6 @@ export class EncodeInputs {
68
66
  this.#capacity = capacity;
69
67
  this.#urgent = urgent;
70
68
  this.#rankAt = rankAt;
71
- this.#deadlineOf = deadlineOf;
72
- this.#firstPieceIn = firstPieceIn;
73
69
  this.#log = log;
74
70
  this.#now = now;
75
71
  }
@@ -411,26 +407,8 @@ export class EncodeInputs {
411
407
  return good;
412
408
  };
413
409
  const sizing = this.stretchFor(output);
414
- let target = sizing?.bytes ?? null;
410
+ const target = sizing?.bytes ?? null;
415
411
  if (sizing && !sizing.openMeasured) request.timing.openApproximate = true;
416
- // NO LONGER THAN THE VIEWER CAN WAIT. A stretch is sized so its copy takes
417
- // no longer than an open; for a piece the viewer reaches soon, the copy and
418
- // the time to that piece's being served must both fit before they reach it.
419
- // Field 2026-10-12: after a seek back, 222.4 MB were copied for 7.7 s ahead
420
- // of a piece needed in about 8 s, and the picture stood 13.2 s. Unknown
421
- // terms leave the stretch as it was.
422
- const deadline = this.#deadlineOf(output, serves);
423
- const firstPiece = this.#firstPieceIn(output, from, serves);
424
- const copyRate = middleOf(this.#copyRates);
425
- if (target !== null && Number.isFinite(deadline) && Number.isFinite(firstPiece) && copyRate !== null) {
426
- const fitting = Math.floor(copyRate * Math.max(0, deadline - firstPiece) * 1000);
427
- if (fitting < target) {
428
- const capped = Math.max(minimum, fitting);
429
- this.#log(`encode input #${from}..#${request.to} of ${output.outputKey ?? output.id}: copy held to ${capped} of ${target} bytes ` +
430
- `— #${serves} is needed in ${deadline.toFixed(1)}s and its first piece takes ${firstPiece.toFixed(1)}s to be served`);
431
- target = capped;
432
- }
433
- }
434
412
  let end = target === null || this.#heldRanges === null ? floor : await longest(target);
435
413
  if (this.#requests.get(request.key) !== request) return undefined;
436
414
  this.#wanted.set(request.key, { wanted: stretches.get(end).bytes, required: minimum });
@@ -98,7 +98,6 @@ import { contentOf, LocalObservations, PROXY_ROOT } from "../encode/LocalObserva
98
98
  import { configurationKeyOf } from "../encode/fingerprint.js";
99
99
  import { qualityStateOf } from "../encode/quality/OutputQualityState.js";
100
100
  import { downloadShare } from "../storage/processor-share.js";
101
- import { secondsToServe, secondsUntilPiece } from "../encode/input-deadline.js";
102
101
  import { ENCODE_RUN_STATE, processCanBeSignalled } from "../encode/encode-run-state.js";
103
102
 
104
103
  // Where a variant and an audio rendition live under a session — `v/<height>/…`
@@ -1014,19 +1013,6 @@ export function wireOutputs({
1014
1013
  index >= window.from && index <= window.to && window.urgent === true),
1015
1014
  // The piece's rank in the output's own map, said with an input's state.
1016
1015
  rankAt: (output, index) => parts.encodeOrchestrator?.rankAt?.(output.outputKey ?? "", index) ?? null,
1017
- // WHEN THE VIEWER REACHES A PIECE: the output map's zones state it for their
1018
- // near edge, and a piece inside a zone is that much film further on.
1019
- deadlineOf: (output, index) => secondsUntilPiece(parts.encodeOrchestrator?.wantedSegmentsOn(output.outputKey ?? "") ?? [],
1020
- output.timeline?.published ?? output.timeline?.boundaries, index),
1021
- // HOW LONG A RUN STARTED AT `from` TAKES TO SERVE `serves`: its open, the
1022
- // pieces it encodes up to and including `serves`, and the next one where a
1023
- // piece waits for the file after it.
1024
- firstPieceIn: (output, from, serves) => secondsToServe({
1025
- open: parts.encodeOrchestrator?.openOf?.(output.outputKey ?? "")?.seconds,
1026
- speed: parts.encodeOrchestrator?.speedOn?.(output.outputKey ?? ""),
1027
- grid: output.timeline?.published ?? output.timeline?.boundaries,
1028
- from, serves, waitsForNext: !parts.encodeRuns.publishesAlone(output)
1029
- }),
1030
1016
  log: line => logger.info(line),
1031
1017
  changed: (output, result) => {
1032
1018
  if (result.kind === "terminal") {
@@ -1,52 +0,0 @@
1
- /**
2
- * @file When the viewer reaches a piece, and how long a run takes to serve it:
3
- * the two terms that keep an encoder input's copy from making the viewer wait
4
- * (torrent-tv/meta#178).
5
- *
6
- * Field 2026-10-12, an AVI on Home Assistant: after a seek back to 100 s the
7
- * input of run `#27..#224` — 222.4 MB, copied in 7.7 s — was prepared ahead of
8
- * a piece the viewer reached about 8 s later, and the picture stood 13.2 s. A
9
- * stretch is sized so that its copy takes no longer than an open; for a piece
10
- * the viewer reaches soon the copy has to leave room for the run to serve it.
11
- */
12
-
13
- /**
14
- * Seconds until the viewer reaches piece `index`, from the output's map.
15
- *
16
- * A zone states `withinSeconds` for its near edge (`output/Timeline.js`); a
17
- * piece inside it is that much film further on. The nearest zone holding the
18
- * piece decides. Null where no zone holds it or the grid is unknown.
19
- *
20
- * @param {{ from: number, to: number, withinSeconds?: number }[]} zones
21
- * @param {number[] | null | undefined} grid - Where each piece begins, in seconds of film.
22
- * @param {number} index
23
- * @returns {number | null}
24
- */
25
- export function secondsUntilPiece(zones, grid, index) {
26
- if (!Array.isArray(grid) || !Number.isFinite(grid[index])) return null;
27
- let nearest = null;
28
- for (const zone of zones) {
29
- if (!(index >= zone.from && index <= zone.to) || !Number.isFinite(zone.withinSeconds) || !Number.isFinite(grid[zone.from])) continue;
30
- const seconds = Math.max(0, zone.withinSeconds) + (grid[index] - grid[zone.from]);
31
- if (nearest === null || seconds < nearest) nearest = seconds;
32
- }
33
- return nearest;
34
- }
35
-
36
- /**
37
- * Seconds from a run's start at `from` to piece `serves` being served.
38
- *
39
- * The open (spawn and first input, without encoding its first piece, as
40
- * `EncodeRuns` measures it), the film from `from` through `serves` at the
41
- * output's speed, and — where a piece is published only when the file after it
42
- * closes — that next piece too. Null when a term is unknown.
43
- *
44
- * @param {{ open?: number | null, speed?: number | null, grid?: number[] | null, from: number, serves: number, waitsForNext?: boolean }} params
45
- * @returns {number | null}
46
- */
47
- export function secondsToServe({ open, speed, grid, from, serves, waitsForNext = false }) {
48
- if (!Number.isFinite(open) || open < 0 || !Number.isFinite(speed) || !(speed > 0) || !Array.isArray(grid)) return null;
49
- const last = waitsForNext && Number.isFinite(grid[serves + 2]) ? serves + 2 : serves + 1;
50
- const film = grid[last] - grid[from];
51
- return Number.isFinite(film) && film > 0 ? open + film / speed : null;
52
- }