@torrent-tv/proxy 2.95.6 → 2.95.8
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
|
@@ -665,14 +665,17 @@ export class SharedPieceStore {
|
|
|
665
665
|
* range to declare.
|
|
666
666
|
*/
|
|
667
667
|
get wantedBytes() {
|
|
668
|
-
//
|
|
669
|
-
//
|
|
670
|
-
|
|
668
|
+
// MEMORY HOLDS WHAT IS READ; WHAT IS DOWNLOADED AHEAD HAS THE DISK. Download
|
|
669
|
+
// preferences order eviction and nothing else. Counted here, the map of a
|
|
670
|
+
// whole film asked for the whole film, the adaptive budget handed over all
|
|
671
|
+
// the memory the machine had free, and once the swarm was told the whole
|
|
672
|
+
// band the store filled 4.4 GB in five minutes and the kernel killed the
|
|
673
|
+
// process (Home Assistant, 2026-10-07, torrent-tv/meta#95).
|
|
671
674
|
const required = this.#lru.demand({ memoryRequiredOnly: true });
|
|
672
675
|
const pinned = this.#lru.pinnedCount;
|
|
673
|
-
if (
|
|
676
|
+
if (required.readers > 0) {
|
|
674
677
|
this.#widestSeenPieces = Math.max(this.#widestSeenPieces, required.widestPieces);
|
|
675
|
-
const pieces = Math.max(MIN_RESIDENT_PIECES,
|
|
678
|
+
const pieces = Math.max(MIN_RESIDENT_PIECES, required.unionPieces, required.widestPieces, pinned);
|
|
676
679
|
// Plus room to absorb what arrives while a write is finishing. Asking for
|
|
677
680
|
// exactly what the readers want leaves no free place ever, so every
|
|
678
681
|
// arrival evicts one of them — measured 2026-09-02: `6 reader(s) want 23
|
|
@@ -1826,17 +1826,19 @@ export class TorrentPool {
|
|
|
1826
1826
|
|
|
1827
1827
|
/**
|
|
1828
1828
|
* Schedule removal of a torrent (with its on-disk store) after
|
|
1829
|
-
* {@link TORRENT_IDLE_TTL_MS} of nothing being wanted of it.
|
|
1830
|
-
*
|
|
1829
|
+
* {@link TORRENT_IDLE_TTL_MS} of nothing being wanted of it. The clock runs
|
|
1830
|
+
* from when it stopped being wanted, so a timer already running is kept:
|
|
1831
|
+
* replacing it on every report of the same state extended the time without
|
|
1832
|
+
* end, and the withdrawal of one map's 4900 zones replaced it 3524 times in
|
|
1833
|
+
* four seconds (Home Assistant 2026-10-07, torrent-tv/meta#95).
|
|
1831
1834
|
*
|
|
1832
1835
|
* @param {import("webtorrent").Torrent} torrent
|
|
1833
1836
|
* @returns {void}
|
|
1834
1837
|
*/
|
|
1835
1838
|
#scheduleIdleRemoval(torrent) {
|
|
1836
|
-
if (!torrent) {
|
|
1839
|
+
if (!torrent || this.#idleTimers.has(torrent)) {
|
|
1837
1840
|
return;
|
|
1838
1841
|
}
|
|
1839
|
-
this.#cancelIdleRemoval(torrent);
|
|
1840
1842
|
const name = typeof torrent.name === "string" ? torrent.name : "(unknown)";
|
|
1841
1843
|
const infoHashShort = String(torrent.infoHash ?? "?").slice(0, 8);
|
|
1842
1844
|
logger.info(`torrent-pool: scheduling idle removal for "${name}" [${infoHashShort}] in ${TORRENT_IDLE_TTL_MS / 1000}s`);
|
|
@@ -19,13 +19,25 @@ export class DownloadMaps {
|
|
|
19
19
|
file.sourceZones = zones.map(zone => Number.isFinite(zone.deadlineAt) || !Number.isFinite(zone.withinSeconds)
|
|
20
20
|
? zone : { ...zone, deadlineAt: now + Math.max(0, zone.withinSeconds) * 1000 });
|
|
21
21
|
let changed = false;
|
|
22
|
+
// Until the new zones are resolved to bytes, a resolved zone stays while
|
|
23
|
+
// the film it covers is still wanted. A viewer moving on re-cuts every zone
|
|
24
|
+
// without making its film unwanted; dropping the zones that lost their
|
|
25
|
+
// exact interval published an empty map every few seconds of playback,
|
|
26
|
+
// which let the swarm go and emptied the encoder's resolved input (Home
|
|
27
|
+
// Assistant 2026-10-07, torrent-tv/meta#95). A zone no new zone overlaps —
|
|
28
|
+
// a seek away — is withdrawn at once.
|
|
22
29
|
const retained = file.zones.flatMap(zone => {
|
|
23
30
|
const interval = zone.downloadInterval ?? zone;
|
|
24
31
|
const current = file.sourceZones.find(candidate => candidate.from === interval.from && candidate.to === interval.to);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
if (!current) {
|
|
33
|
+
const stillWanted = file.sourceZones.some(candidate => candidate.from < interval.to && interval.from < candidate.to);
|
|
34
|
+
if (!stillWanted) changed = true;
|
|
35
|
+
return stillWanted ? [zone] : [];
|
|
36
|
+
}
|
|
37
|
+
const deadlineAt = Number.isFinite(current.deadlineAt)
|
|
38
|
+
? current.deadlineAt + (Math.max(0, zone.from - current.from) - (zone.leadSeconds ?? 0)) * 1000 : current.deadlineAt;
|
|
39
|
+
if (Object.keys(current).some(key => key !== "from" && key !== "to" && !Object.is(zone[key], key === "deadlineAt" ? deadlineAt : current[key]))) changed = true;
|
|
40
|
+
return [{ ...zone, ...current, from: zone.from, to: zone.to, deadlineAt }];
|
|
29
41
|
});
|
|
30
42
|
this.#setZones(file, retained);
|
|
31
43
|
for (const [statement, metadata] of file.metadata) {
|