@torrent-tv/proxy 2.107.40 → 2.107.41
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
|
@@ -629,7 +629,7 @@ export function wireOutputs({
|
|
|
629
629
|
viewerSecondsOn: (output, consumerId, now) => viewerSecondsOn(parts.viewers, output, consumerId, now),
|
|
630
630
|
minimumBufferSecondsFor: (output) => minimumBufferSecondsOf(output),
|
|
631
631
|
// What this proxy may keep of downloaded pieces on disk.
|
|
632
|
-
sourceStorageBytes: () => parts.machineBudget?.allowedFor
|
|
632
|
+
sourceStorageBytes: () => parts.machineBudget?.allowedFor("spilled pieces") ?? null,
|
|
633
633
|
getSourceStats: (...args) => parts.getSourceStats?.(...args) ?? null,
|
|
634
634
|
disposeSession: (...args) => parts.lifecycle.disposeSession(...args),
|
|
635
635
|
planEncodersSoon: (...args) => parts.encodeRuns.planEncodersSoon(...args),
|
package/services/storage/wire.js
CHANGED
|
@@ -194,6 +194,8 @@ export function wireMachineBudget({
|
|
|
194
194
|
|
|
195
195
|
return {
|
|
196
196
|
capacityOf: name => budget.capacityOf(name),
|
|
197
|
+
/** What one claimant was last allowed, or null before a measured division. */
|
|
198
|
+
allowedFor: name => budget.allowedFor(name),
|
|
197
199
|
/**
|
|
198
200
|
* @param {string | null} [resource] - One resource to revise; all when absent.
|
|
199
201
|
* @param {string | null} [because] - Who asked, for the revision's line.
|
|
@@ -740,12 +740,13 @@ export function predictPlaybackReadiness(input = {}) {
|
|
|
740
740
|
// share (Home Assistant 2026-10-26, torrent-tv/meta#239). Said as such, and
|
|
741
741
|
// the viewer keeps waiting rather than starting into stops.
|
|
742
742
|
const storageBytes = Number(input.sourceStorageBytes);
|
|
743
|
-
|
|
744
|
-
|
|
743
|
+
const tailParts = tailStock.filter(part => !part.skipped);
|
|
744
|
+
if (Number.isFinite(delay) && Number.isFinite(storageBytes) && storageBytes >= 0 && tailParts.length > 0) {
|
|
745
|
+
const cushionBytes = tailParts.reduce((sum, part) => sum + Math.max(0, part.totalBytes - part.missingBytes) +
|
|
745
746
|
Math.max(0, part.missingBytes - part.bytesPerSecond * Math.max(0, part.finish - delay)), 0);
|
|
746
747
|
if (cushionBytes > storageBytes) {
|
|
747
748
|
return { ...result(false, null, buffered, reserve, null, "cushion-exceeds-storage", preparedSegments),
|
|
748
|
-
cushionBytes, storageBytes };
|
|
749
|
+
cushionBytes, storageBytes, tail: tailStock };
|
|
749
750
|
}
|
|
750
751
|
}
|
|
751
752
|
const originReady = trackState.every(({ clientRanges }) => compare(contiguousEnd(clientRanges, at), at) > 0);
|
|
@@ -756,6 +757,9 @@ export function predictPlaybackReadiness(input = {}) {
|
|
|
756
757
|
return { ...forecast, measuredAt: now, predictedStartAt: Number.isFinite(delay) ? now + delay * 1000 : null,
|
|
757
758
|
firstRequiredSegmentsSeconds,
|
|
758
759
|
firstRequiredStages,
|
|
760
|
+
// What the rest of the film weighs per source, at what rate it comes and
|
|
761
|
+
// when, or why a source has none: said in the readiness line.
|
|
762
|
+
tail: tailStock,
|
|
759
763
|
// The piece whose `kind` — its production, or its delivery to the page —
|
|
760
764
|
// comes `atSeconds` from now while the media before it lasts
|
|
761
765
|
// `aheadSeconds`: the difference is the delay.
|
|
@@ -801,7 +805,11 @@ function scheduleTail({ trackState, sourceState, runStarts, trackFinish, link,
|
|
|
801
805
|
const sourceDurations = new Map();
|
|
802
806
|
for (const state of trackState) {
|
|
803
807
|
const seconds = Math.max(0, state.tailEndSeconds - tailStart) * state.tailWorkFraction;
|
|
804
|
-
if (!(seconds > 0))
|
|
808
|
+
if (!(seconds > 0)) {
|
|
809
|
+
stock?.push({ track: state.track.id, skipped: "no-work", tailStart, tailEnd: state.tailEndSeconds,
|
|
810
|
+
workFraction: state.tailWorkFraction, tailSegments: state.tailSegmentCount });
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
805
813
|
for (const sourceId of new Set(state.track.sourceIds ?? [])) {
|
|
806
814
|
sourceDurations.set(sourceId, Math.max(sourceDurations.get(sourceId) ?? 0, seconds));
|
|
807
815
|
}
|
|
@@ -811,7 +819,10 @@ function scheduleTail({ trackState, sourceState, runStarts, trackFinish, link,
|
|
|
811
819
|
for (const [sourceId, seconds] of sourceDurations) {
|
|
812
820
|
const source = sourceState.get(sourceId);
|
|
813
821
|
if (!source) return { reason: "source-measurement-unavailable" };
|
|
814
|
-
if (source.source.complete === true)
|
|
822
|
+
if (source.source.complete === true) {
|
|
823
|
+
stock?.push({ sourceId, skipped: "complete" });
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
815
826
|
// Held means on this proxy now, past the last byte the near window's
|
|
816
827
|
// pieces read: those are counted above, and the window's planned arrivals
|
|
817
828
|
// counted again as held took 117 s of film off a 90-minute tail. The
|
|
@@ -821,7 +832,10 @@ function scheduleTail({ trackState, sourceState, runStarts, trackFinish, link,
|
|
|
821
832
|
heldBeyond(source.source.residence, windowEnd), windowEnd);
|
|
822
833
|
if (bytes === null) return { reason: "source-measurement-unavailable",
|
|
823
834
|
unavailableSource: { sourceId, phase: "tail" } };
|
|
824
|
-
if (!(bytes > 0))
|
|
835
|
+
if (!(bytes > 0)) {
|
|
836
|
+
stock?.push({ sourceId, skipped: "held", seconds, windowEnd });
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
825
839
|
const { service } = source;
|
|
826
840
|
const rate = service.tailRate ?? service.rate;
|
|
827
841
|
if (!rate || !(rate.rateAt(0) > 0)) {
|
|
@@ -832,7 +846,7 @@ function scheduleTail({ trackState, sourceState, runStarts, trackFinish, link,
|
|
|
832
846
|
sourceArrivalAt = Math.max(sourceArrivalAt, service.finish);
|
|
833
847
|
// What this stretch weighs and what it still lacks: the stock the start
|
|
834
848
|
// asks to hold is read from these once the start's delay is known.
|
|
835
|
-
stock?.push({ totalBytes:
|
|
849
|
+
stock?.push({ sourceId, seconds, windowEnd, totalBytes:estimateUnmappedSourceBytes(source.source, seconds, duration, []) ?? bytes,
|
|
836
850
|
missingBytes: bytes, bytesPerSecond: rate.rateAt(0), finish: service.finish });
|
|
837
851
|
const state = trackState.find(candidate => candidate.track.sourceIds?.includes(sourceId));
|
|
838
852
|
const index = state?.segments.at(-1)?.index ?? 0;
|