@torrent-tv/proxy 2.19.0 → 2.20.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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 2.20.0
2
+
3
+ - **Fix**: A file's read window is shared between the readers it has, instead of being granted whole to each. The window is stated in seconds of playback and the piece store's memory is one budget for the whole torrent, so a viewer with a picture and a separately published audio track asked for twice what the budget was written against, and a warm-up made it three times. On 2026-08-15 that ended as it had to: every resident piece held at once, a read that returned zero bytes, and every encoder on the file taking that for the end of it. This is the first step of the sliding window, not the whole of it — pieces still leave memory only by the store's own eviction.
4
+
1
5
  ## 2.19.0
2
6
 
3
7
  - **New**: What the torrent itself costs this machine is measured and charged. Downloading a file, verifying every piece of it and pushing segments down a data channel are work on the same box as the encoder, they scale with the file's own bitrate, and the budget counted none of it — measured on the addon host with every encoder suspended, the machine was still 20-29 % busy. The figure is taken only while NOTHING is encoding, which is the one moment it can be attributed without arithmetic, and it is expressed per megabyte moved so any file's rate can be priced from it. A viewer's file is then charged at its own byte rate when deciding what quality this host can offer.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.19.0",
3
+ "version": "2.20.0",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "publishConfig": {
@@ -2489,10 +2489,42 @@ export class HlsSessionManager {
2489
2489
  return 0;
2490
2490
  }
2491
2491
  const bytesPerSecond = fileLength / durationSeconds;
2492
- const wanted = Math.round(bytesPerSecond * READ_WINDOW_SECONDS);
2492
+ // Shared between the readers this file already has. The window is stated in
2493
+ // seconds of playback and the store's memory is one budget for the whole
2494
+ // torrent, so N readers asking for thirty seconds each ask for N times what
2495
+ // was provided for — and on 2026-08-15 that is exactly what happened: a
2496
+ // viewer with a picture and an audio track had every resident piece held at
2497
+ // once, a read ended with zero bytes, and every encoder on the file took
2498
+ // that for the end of it.
2499
+ //
2500
+ // Dividing keeps the promise the budget was written against. It is not the
2501
+ // sliding window of roadmap item 8 — pieces still leave only by the store's
2502
+ // own eviction — but it removes the multiplication that broke it.
2503
+ const readers = Math.max(1, this.#readersOn(sourceKey, fileIndex));
2504
+ const wanted = Math.round((bytesPerSecond * READ_WINDOW_SECONDS) / readers);
2493
2505
  return Math.min(READ_WINDOW_MAX_BYTES, Math.max(READ_WINDOW_MIN_BYTES, wanted));
2494
2506
  }
2495
2507
 
2508
+ /**
2509
+ * How many live sessions read this file: the picture, any rung being warmed
2510
+ * beside it, and any audio track published on its own.
2511
+ *
2512
+ * @param {string} sourceKey
2513
+ * @param {number} fileIndex
2514
+ * @returns {number}
2515
+ */
2516
+ #readersOn(sourceKey, fileIndex) {
2517
+ let readers = 0;
2518
+ for (const session of this.sessionsById.values()) {
2519
+ if (session?.sourceKey === sourceKey &&
2520
+ session.fileIndex === fileIndex &&
2521
+ session.state !== "disposed") {
2522
+ readers += 1;
2523
+ }
2524
+ }
2525
+ return readers;
2526
+ }
2527
+
2496
2528
  #enforceLookAhead() {
2497
2529
  for (const session of this.sessionsById.values()) {
2498
2530
  this.#enforceLookAheadFor(session);