@torrent-tv/proxy 2.106.1 → 2.107.0

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.106.1",
3
+ "version": "2.107.0",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -2219,60 +2219,78 @@ export class Renditions {
2219
2219
  this.#host.outputs.touch(already);
2220
2220
  return already;
2221
2221
  }
2222
- const rendition = await this.#host.createOrGetSession({
2223
- sourceKey: base.file.sourceKey,
2224
- fileIndex: base.file.fileIndex,
2225
- // No picture at all: the video flag says what to do with a video stream
2226
- // this output does not carry.
2227
- transcodeVideo: false,
2228
- transcodeAudio,
2229
- fileName: base.file.name,
2230
- // Opened by nobody in particular, as a step is.
2231
- consumerId: "",
2232
- audioTrackIndex: trackIndex,
2233
- audioOnly: true,
2234
- // Where the viewer is, so the rendition starts with the picture rather
2235
- // than at the beginning of the file. Read the same way a quality variant
2236
- // reads it: the base's own field is only written by a seek or by a
2237
- // segment IT served, so on a resume-from-position open it is still unset
2238
- // while the player is asking for segment #537 — and the audio would begin
2239
- // at zero and never catch up, since nothing treats a far request as a
2240
- // seek. The accessor falls back to the last segment actually requested.
2241
- // Where the PICTURE is, not where it has been read to.
2242
- //
2243
- // The position this class keeps is written by the segments a session
2244
- // serves, so it is the READ head, and the viewer's picture sits behind it
2245
- // by everything the player has buffered. Started at the read head, the
2246
- // audio run begins AHEAD of the viewer, and every request they then make
2247
- // is behind a run that only moves forward — field 2026-08-15, placed at
2248
- // #16 while the player asked for #10, and the audio arrived only after
2249
- // the encoder was dragged back.
2250
- //
2251
- // The distance is measured, not assumed: the browser reports how many
2252
- // seconds it holds ahead of the picture with every link report, so the
2253
- // playhead is one subtraction away. A stale report is no use — a viewer
2254
- // who seeked since then is somewhere else entirely — so an old one is
2255
- // ignored and the whole look-ahead is subtracted instead, which cannot
2256
- // leave the run ahead of them.
2257
- startPositionSeconds: this.#host.audioStartSecondsFor({
2258
- family: this.#host.outputs.familyOf(base),
2259
- openedAtSeconds: this.#host.encodeRuns.progressOf(base)?.startPositionSeconds,
2260
- segmentSeconds: this.#host.segmentDurationSec
2261
- }),
2262
- segmentFormatId: base.segmentFormat.id,
2263
- // Cut where the picture is cut. Two streams meant to be played together
2264
- // have to be divided at the same times, and the grid is the base's — the
2265
- // table as it stands now, corrections included. A base on the uniform
2266
- // grid passes nothing: the rendition computes the same even grid from the
2267
- // same duration.
2268
- inheritedGrid: base.timeline.cutGrid === "keyframe"
2269
- ? {
2270
- boundaries: base.timeline.boundaries,
2271
- published: base.timeline.published
2272
- }
2273
- : null
2274
- });
2275
- return rendition ?? null;
2222
+ const waitStartedAt = performance.now();
2223
+ const waitFields = {
2224
+ process: "P6.a",
2225
+ baseSessionId: base.id,
2226
+ trackIndex,
2227
+ consumerId,
2228
+ audioMode: transcodeAudio ? "transcode" : "copy"
2229
+ };
2230
+ this.#host.observeWait?.(base.file.sourceKey, "process", { ...waitFields, phase: "begin", at: waitStartedAt });
2231
+ let waitOutcome = "error";
2232
+ try {
2233
+ const rendition = await this.#host.createOrGetSession({
2234
+ sourceKey: base.file.sourceKey,
2235
+ fileIndex: base.file.fileIndex,
2236
+ // No picture at all: the video flag says what to do with a video stream
2237
+ // this output does not carry.
2238
+ transcodeVideo: false,
2239
+ transcodeAudio,
2240
+ fileName: base.file.name,
2241
+ // Opened by nobody in particular, as a step is.
2242
+ consumerId: "",
2243
+ audioTrackIndex: trackIndex,
2244
+ audioOnly: true,
2245
+ // Where the viewer is, so the rendition starts with the picture rather
2246
+ // than at the beginning of the file. Read the same way a quality variant
2247
+ // reads it: the base's own field is only written by a seek or by a
2248
+ // segment IT served, so on a resume-from-position open it is still unset
2249
+ // while the player is asking for segment #537 — and the audio would begin
2250
+ // at zero and never catch up, since nothing treats a far request as a
2251
+ // seek. The accessor falls back to the last segment actually requested.
2252
+ // Where the PICTURE is, not where it has been read to.
2253
+ //
2254
+ // The position this class keeps is written by the segments a session
2255
+ // serves, so it is the READ head, and the viewer's picture sits behind it
2256
+ // by everything the player has buffered. Started at the read head, the
2257
+ // audio run begins AHEAD of the viewer, and every request they then make
2258
+ // is behind a run that only moves forward — field 2026-08-15, placed at
2259
+ // #16 while the player asked for #10, and the audio arrived only after
2260
+ // the encoder was dragged back.
2261
+ //
2262
+ // The distance is measured, not assumed: the browser reports how many
2263
+ // seconds it holds ahead of the picture with every link report, so the
2264
+ // playhead is one subtraction away. A stale report is no use — a viewer
2265
+ // who seeked since then is somewhere else entirely — so an old one is
2266
+ // ignored and the whole look-ahead is subtracted instead, which cannot
2267
+ // leave the run ahead of them.
2268
+ startPositionSeconds: this.#host.audioStartSecondsFor({
2269
+ family: this.#host.outputs.familyOf(base),
2270
+ openedAtSeconds: this.#host.encodeRuns.progressOf(base)?.startPositionSeconds,
2271
+ segmentSeconds: this.#host.segmentDurationSec
2272
+ }),
2273
+ segmentFormatId: base.segmentFormat.id,
2274
+ // Cut where the picture is cut. Two streams meant to be played together
2275
+ // have to be divided at the same times, and the grid is the base's — the
2276
+ // table as it stands now, corrections included. A base on the uniform
2277
+ // grid passes nothing: the rendition computes the same even grid from the
2278
+ // same duration.
2279
+ inheritedGrid: base.timeline.cutGrid === "keyframe"
2280
+ ? {
2281
+ boundaries: base.timeline.boundaries,
2282
+ published: base.timeline.published
2283
+ }
2284
+ : null
2285
+ });
2286
+ waitOutcome = rendition ? "opened" : "unavailable";
2287
+ return rendition ?? null;
2288
+ } finally {
2289
+ const waitEndedAt = performance.now();
2290
+ this.#host.observeWait?.(base.file.sourceKey, "process", { ...waitFields, phase: "end",
2291
+ at: waitEndedAt, startedAt: waitStartedAt, endedAt: waitEndedAt,
2292
+ durationMs: waitEndedAt - waitStartedAt, outcome: waitOutcome });
2293
+ }
2276
2294
  }
2277
2295
 
2278
2296
  /**