@torrent-tv/proxy 2.95.23 → 2.95.25
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
|
@@ -794,13 +794,24 @@ function latenessOf(encoders, coverage, wanted, untilNeeded, rate, refetchSecPer
|
|
|
794
794
|
const lateAt = new Map(ranks.map((rank) => [rank, 0]));
|
|
795
795
|
/** When the last number of a rank is made, per rank. @type {Map<number, number>} */
|
|
796
796
|
const doneAt = new Map(ranks.map((rank) => [rank, 0]));
|
|
797
|
+
// How many numbers each encoder has already passed over that are made, kept
|
|
798
|
+
// as the walk goes rather than counted again for every number: counted again,
|
|
799
|
+
// a film of two thousand pieces cost the plan four million steps, and the
|
|
800
|
+
// plan held the proxy's thread for most of every second (Home Assistant
|
|
801
|
+
// 2026-10-08, torrent-tv/meta#151). The same count `madeBetween` gives.
|
|
802
|
+
const passed = encoders.map((encoder) => coverage.madeBetween(encoder.at, first - 1));
|
|
797
803
|
for (let index = first; index <= last; index += 1) {
|
|
804
|
+
const readyHere = coverage.isReady(index);
|
|
805
|
+
for (let at = 0; at < encoders.length; at += 1) {
|
|
806
|
+
if (readyHere && encoders[at].at <= index) passed[at] += 1;
|
|
807
|
+
}
|
|
798
808
|
// Which encoder gets to this piece first, and when. One standing on it is
|
|
799
809
|
// already there; one behind it must work its way up, re-making anything
|
|
800
810
|
// already made on the way, which costs its own time and the swarm's.
|
|
801
811
|
let soonest = Number.POSITIVE_INFINITY;
|
|
802
812
|
let byWhom = null;
|
|
803
|
-
for (
|
|
813
|
+
for (let at = 0; at < encoders.length; at += 1) {
|
|
814
|
+
const encoder = encoders[at];
|
|
804
815
|
if (encoder.at > index) {
|
|
805
816
|
continue;
|
|
806
817
|
}
|
|
@@ -820,13 +831,13 @@ function latenessOf(encoders, coverage, wanted, untilNeeded, rate, refetchSecPer
|
|
|
820
831
|
// stood still for 116.7 s.
|
|
821
832
|
const arrival = encoder.delaySec
|
|
822
833
|
+ (index - encoder.at) / rate
|
|
823
|
-
+
|
|
834
|
+
+ passed[at] * refetchSecPerSegment;
|
|
824
835
|
if (arrival < soonest) {
|
|
825
836
|
soonest = arrival;
|
|
826
837
|
byWhom = encoder;
|
|
827
838
|
}
|
|
828
839
|
}
|
|
829
|
-
if (
|
|
840
|
+
if (readyHere) {
|
|
830
841
|
// It exists. Nobody waits for it and nothing is owed — but whoever passes
|
|
831
842
|
// over it makes it a second time, and the swarm fetches its bytes again.
|
|
832
843
|
if (byWhom !== null) {
|
|
@@ -1103,8 +1114,19 @@ function gapFinderFor(coverage, surviving, rate, refetchSecPerSegment = 0) {
|
|
|
1103
1114
|
// the map happens to be in.
|
|
1104
1115
|
let best = null;
|
|
1105
1116
|
let bestDue = Number.POSITIVE_INFINITY;
|
|
1117
|
+
// Where every encoder already placed stands, and how many made numbers lie
|
|
1118
|
+
// between it and the number the walk is on — kept as the walk goes, because
|
|
1119
|
+
// counted again for every number a two-hour film made this one walk
|
|
1120
|
+
// millions of steps, and the plan held the proxy's thread for most of every
|
|
1121
|
+
// second (Home Assistant 2026-10-08, torrent-tv/meta#151).
|
|
1122
|
+
const standing = [...placed.map((live) => live.at), ...(alsoPlaced ?? [])];
|
|
1123
|
+
const passed = standing.map((a) => coverage.madeBetween(a, start - 1));
|
|
1106
1124
|
for (let index = start; index <= last; index += 1) {
|
|
1107
|
-
|
|
1125
|
+
const readyHere = coverage.isReady(index);
|
|
1126
|
+
for (let which = 0; which < standing.length; which += 1) {
|
|
1127
|
+
if (readyHere && standing[which] <= index) passed[which] += 1;
|
|
1128
|
+
}
|
|
1129
|
+
if (readyHere) {
|
|
1108
1130
|
continue;
|
|
1109
1131
|
}
|
|
1110
1132
|
const deadline = deadlineAt(index);
|
|
@@ -1121,7 +1143,8 @@ function gapFinderFor(coverage, surviving, rate, refetchSecPerSegment = 0) {
|
|
|
1121
1143
|
// second and a third on the very next numbers — three processes a segment
|
|
1122
1144
|
// apart for one person, which is the waste this model exists to refuse.
|
|
1123
1145
|
let soonest = Number.POSITIVE_INFINITY;
|
|
1124
|
-
for (
|
|
1146
|
+
for (let which = 0; which < standing.length; which += 1) {
|
|
1147
|
+
const a = standing[which];
|
|
1125
1148
|
if (a > index) {
|
|
1126
1149
|
// Standing past it. Encoders only move forward, so it never will.
|
|
1127
1150
|
continue;
|
|
@@ -1141,7 +1164,7 @@ function gapFinderFor(coverage, surviving, rate, refetchSecPerSegment = 0) {
|
|
|
1141
1164
|
// to arrive, and the model compares arrivals. Asked separately it was a
|
|
1142
1165
|
// second authority over the same encoder, and the two disagreed.
|
|
1143
1166
|
const arrival = (index - a + 1) / rate
|
|
1144
|
-
+
|
|
1167
|
+
+ passed[which] * refetchSecPerSegment;
|
|
1145
1168
|
if (arrival < soonest) {
|
|
1146
1169
|
soonest = arrival;
|
|
1147
1170
|
}
|
|
@@ -1009,7 +1009,16 @@ export class EncodeRuns {
|
|
|
1009
1009
|
onSpeedMeasured: () => this.#host.noteRunSpeedMeasured?.(session, run),
|
|
1010
1010
|
onEnded: (ended) => {
|
|
1011
1011
|
this.#runsByInputToken.delete(inputToken);
|
|
1012
|
-
if (admittedInput.original)
|
|
1012
|
+
if (admittedInput.original) {
|
|
1013
|
+
const reads = admittedInput.reads?.();
|
|
1014
|
+
if (reads) {
|
|
1015
|
+
const since = (at) => at ? `${at - run.startedAt}ms` : "never";
|
|
1016
|
+
this.#host.logger.info(`encode input of run #${run.from}..#${run.to} on ${session.outputKey}: ` +
|
|
1017
|
+
`${reads.count} read(s), ${reads.bytes} bytes, first at ${since(reads.firstAt)}, last at ${since(reads.lastAt)}, ` +
|
|
1018
|
+
`ended at ${Date.now() - run.startedAt}ms`);
|
|
1019
|
+
}
|
|
1020
|
+
admittedInput.release();
|
|
1021
|
+
}
|
|
1013
1022
|
this.noteRunEnded(session, run, ended);
|
|
1014
1023
|
}
|
|
1015
1024
|
});
|
|
@@ -27,6 +27,10 @@ export async function admitOriginalInput({ sources, reserve, readRanges }) {
|
|
|
27
27
|
}
|
|
28
28
|
let released = false;
|
|
29
29
|
retained = true;
|
|
30
|
+
// What FFmpeg asked of this input, for the run's own account of where its
|
|
31
|
+
// time went: field 2026-10-08, a run took 6-9 s for a piece FFmpeg makes in
|
|
32
|
+
// 1.6 s from a file, and nothing said whether it was waiting on its input.
|
|
33
|
+
const reads = { count: 0, bytes: 0, firstAt: 0, lastAt: 0 };
|
|
30
34
|
return {
|
|
31
35
|
kind: "result", original: true, sources, bytes, fingerprint: hash.digest("hex"),
|
|
32
36
|
tracks: sources.flatMap(source => (source.input.selections ?? []).map(selection => ({ track: selection.track,
|
|
@@ -43,9 +47,15 @@ export async function admitOriginalInput({ sources, reserve, readRanges }) {
|
|
|
43
47
|
const position = ranges.findIndex(([from, to]) => from <= start && (partial ? start : stop) <= to);
|
|
44
48
|
if (position < 0) return null;
|
|
45
49
|
stop = Math.min(stop, ranges[position][1]);
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
reads.count += 1;
|
|
52
|
+
reads.bytes += stop - start + 1;
|
|
53
|
+
reads.firstAt ||= now;
|
|
54
|
+
reads.lastAt = now;
|
|
46
55
|
return { length: fileLength, end: stop, bytes: entry.buffers[position].subarray(start - ranges[position][0], stop - ranges[position][0] + 1) };
|
|
47
56
|
},
|
|
48
57
|
lengthOf: fileIndex => held.get(fileIndex)?.source.input.fileLength ?? null,
|
|
58
|
+
reads: () => ({ ...reads }),
|
|
49
59
|
release() {
|
|
50
60
|
if (released) return;
|
|
51
61
|
released = true;
|