@torrent-tv/proxy 2.95.23 → 2.95.24

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.95.23",
3
+ "version": "2.95.24",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -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 (const encoder of encoders) {
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
- + coverage.madeBetween(encoder.at, index) * refetchSecPerSegment;
834
+ + passed[at] * refetchSecPerSegment;
824
835
  if (arrival < soonest) {
825
836
  soonest = arrival;
826
837
  byWhom = encoder;
827
838
  }
828
839
  }
829
- if (coverage.isReady(index)) {
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
- if (coverage.isReady(index)) {
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 (const a of [...placed.map((live) => live.at), ...(alsoPlaced ?? [])]) {
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
- + coverage.madeBetween(a, index) * refetchSecPerSegment;
1167
+ + passed[which] * refetchSecPerSegment;
1145
1168
  if (arrival < soonest) {
1146
1169
  soonest = arrival;
1147
1170
  }