@torrent-tv/proxy 2.107.16 → 2.107.18

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.107.16",
3
+ "version": "2.107.18",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -41,7 +41,7 @@ function sameInputs(left, right) {
41
41
  return left.every((input, index) => input.sourceId === right[index].sourceId && input.ranges === right[index].ranges);
42
42
  }
43
43
 
44
- function forecastInputState(tracks, identity) {
44
+ export function forecastInputState(tracks, identity) {
45
45
  if (!identity) return null;
46
46
  const track = tracks.find(candidate => candidate.id === identity.trackId);
47
47
  const segment = track?.segments.find(candidate => candidate.index === identity.segmentIndex);
@@ -51,6 +51,9 @@ function forecastInputState(tracks, identity) {
51
51
  trackId: identity.trackId,
52
52
  segmentIndex: identity.segmentIndex,
53
53
  phase: identity.phase,
54
+ trackFound: Boolean(track),
55
+ segmentFound: Boolean(segment),
56
+ sourceInputFound: Boolean(sourceInput),
54
57
  rangesKnown: Array.isArray(sourceInput?.ranges),
55
58
  rangeCount: Array.isArray(sourceInput?.ranges) ? sourceInput.ranges.length : null
56
59
  };
@@ -1121,7 +1124,8 @@ export class ViewerRequests {
1121
1124
  const previousInputState = measurement.forecastInputState ?? null;
1122
1125
  const currentInputState = forecastInputState(tracks, unavailableInput);
1123
1126
  if (previousInputState && forecastInputIdentity(previousInputState) !== forecastInputIdentity(currentInputState)) {
1124
- observeForecastInput(this.#host.observeWait, session.file.sourceKey, previousInputState,
1127
+ const resolvedInputState = forecastInputState(tracks, previousInputState) ?? previousInputState;
1128
+ observeForecastInput(this.#host.observeWait, session.file.sourceKey, resolvedInputState,
1125
1129
  currentInputState ? "forecast-blocker-replaced" : "forecast-blocker-cleared");
1126
1130
  }
1127
1131
  if (currentInputState && JSON.stringify(previousInputState) !== JSON.stringify(currentInputState)) {
@@ -749,8 +749,13 @@ function scheduleTail({ trackState, sourceState, sourceByteCoverage, sourceArriv
749
749
  if (!source) return { reason: "source-measurement-unavailable" };
750
750
  if (source.source.complete === true) continue;
751
751
  const ranges = exactInputs ? inputRangesOf(exactInputs, sourceId) : null;
752
- if (ranges === null) return { reason: "source-input-ranges-unavailable",
753
- unavailableSource: { sourceId, trackId: track.id, segmentIndex: segment.index, phase: "tail" } };
752
+ if (ranges === null) {
753
+ // The tail extends beyond the ranges the playback map has asked to
754
+ // resolve. Stop this projection at that boundary: the near window
755
+ // remains exact, and later segments enter the map as the viewer
756
+ // advances. Waiting for the whole tail here prevents a cold start.
757
+ return null;
758
+ }
754
759
  const bytes = supplyOf(sourceId);
755
760
  let order = 0;
756
761
  for (const range of ranges) {