@torrent-tv/proxy 2.83.1 → 2.83.2
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 +6 -0
- package/package.json +1 -1
- package/services/torrent-pool.js +21 -0
- package/test/swarm-follows-readers.test.js +42 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## 2.83.2
|
|
2
|
+
|
|
3
|
+
- **Fix**: 2.83.1 COULD NOT START PLAYBACK AT ALL, and the cause was its own new rule. A torrent nobody has stated anything about leaves its swarm — and a torrent that has just been added has stated nothing yet, because the read of the file's edges is still in flight and the playback plan is still being built. Field 2026-09-11: added at 20:57:17, first peer at 20:57:18, out of the swarm at 20:57:21 with 741 connections let go. Nothing ever rejoined it: rejoining waits for a reader, and the reader was waiting for the header the swarm had been fetching. `[stats]` then read `peers=0 connected of 0 known (94 queued, 5 tracker(s) offered up to 683 seeders)` for as long as the viewer was willing to wait.
|
|
4
|
+
- **Fix**: The condition is a state rather than a period: a torrent is left only once it has been read at least once. That is what separates a film somebody left from a film being opened right now, and a torrent nobody ever reads still goes by the pool's own idle removal, which is where that belongs.
|
|
5
|
+
- **Chore**: Two checks that asserted the old behaviour now read a torrent through its real sequence — read once, then left — and two more cover the state this release is about.
|
|
6
|
+
|
|
1
7
|
## 2.83.1
|
|
2
8
|
|
|
3
9
|
- **Fix**: THE PIECE STORE COULD END A TORRENT, AND ON 2026-09-11 IT DID. Switching to the second episode of a five-file torrent reached a store that had shrunk to three blocks of 4 MB while the machine offered 4.3 GB; a claim for a block failed after five seconds, the failure travelled out through the torrent client's own write callback, and the client destroyed the torrent. For the rest of the process every read answered `File 1 not found in torrent:d4022ff4...`, `/stats` said `peers=0 connected of 1186 known`, the header of the new episode never downloaded, and the viewer waited on a plan that could not be built until the addon was restarted. Memory is no longer a reason to refuse anything: an arriving piece that cannot have a block is written straight to disk, which is where it was going anyway.
|
package/package.json
CHANGED
package/services/torrent-pool.js
CHANGED
|
@@ -971,7 +971,28 @@ export class TorrentPool {
|
|
|
971
971
|
}
|
|
972
972
|
const usage = this.fileUsageByTorrent.get(torrent);
|
|
973
973
|
const isRead = Boolean(usage && usage.size > 0);
|
|
974
|
+
if (isRead) {
|
|
975
|
+
// Recorded on the torrent, as `hasActiveReader` and `hasUnmetDemand`
|
|
976
|
+
// beside it are: it is a fact about this torrent and it lives as long as
|
|
977
|
+
// the torrent does.
|
|
978
|
+
torrent.hasBeenRead = true;
|
|
979
|
+
}
|
|
974
980
|
const isWanted = isRead || demandFor(torrent).register.windows().length > 0;
|
|
981
|
+
// A TORRENT NOBODY HAS READ YET IS BEING SET UP, NOT ABANDONED. Field
|
|
982
|
+
// 2026-09-11, and it broke playback outright: a torrent was added at
|
|
983
|
+
// 20:57:17, its first peer connected at 20:57:18, and this pass took it out
|
|
984
|
+
// of the swarm at 20:57:21 — while the read of the file's edges was still
|
|
985
|
+
// in flight and the playback plan was being built. Nothing rejoined it,
|
|
986
|
+
// because rejoining waits for a reader and a reader cannot arrive: the
|
|
987
|
+
// header it needs is downloaded by the swarm that was just let go.
|
|
988
|
+
//
|
|
989
|
+
// The condition is a state and not a period: having been read at least once
|
|
990
|
+
// is what tells a film somebody left from a film nobody has opened yet. One
|
|
991
|
+
// that is never read at all goes by the pool's own idle removal, which is
|
|
992
|
+
// where that belongs.
|
|
993
|
+
if (!isWanted && torrent.hasBeenRead !== true) {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
975
996
|
if (isWanted && torrent.paused === true) {
|
|
976
997
|
torrent.resume();
|
|
977
998
|
logger.info(
|
|
@@ -67,6 +67,11 @@ test("a torrent nobody is reading is let go of, and its data is not", () => {
|
|
|
67
67
|
const torrent = torrentWith(6);
|
|
68
68
|
const pool = poolWith(torrent);
|
|
69
69
|
try {
|
|
70
|
+
// Read once and left, which is the state this is about: a film nobody has
|
|
71
|
+
// opened yet is being set up, and the test below covers that.
|
|
72
|
+
pool.fileUsageByTorrent.set(torrent, new Map([[0, 1]]));
|
|
73
|
+
pool.followTheReaders(torrent);
|
|
74
|
+
pool.fileUsageByTorrent.set(torrent, new Map());
|
|
70
75
|
pool.followTheReaders(torrent);
|
|
71
76
|
|
|
72
77
|
assert.equal(torrent.paused, true, "the swarm was not left");
|
|
@@ -114,6 +119,9 @@ test("the swarm is rejoined when a reader comes back", () => {
|
|
|
114
119
|
const torrent = torrentWith(3);
|
|
115
120
|
const pool = poolWith(torrent);
|
|
116
121
|
try {
|
|
122
|
+
pool.fileUsageByTorrent.set(torrent, new Map([[0, 1]]));
|
|
123
|
+
pool.followTheReaders(torrent);
|
|
124
|
+
pool.fileUsageByTorrent.set(torrent, new Map());
|
|
117
125
|
pool.followTheReaders(torrent);
|
|
118
126
|
assert.equal(torrent.paused, true);
|
|
119
127
|
|
|
@@ -124,3 +132,37 @@ test("the swarm is rejoined when a reader comes back", () => {
|
|
|
124
132
|
forgetTorrent(torrent);
|
|
125
133
|
}
|
|
126
134
|
});
|
|
135
|
+
|
|
136
|
+
test("a torrent nobody has read yet is being set up, and is left alone", () => {
|
|
137
|
+
// Field 2026-09-11, and it broke playback outright: a torrent added at
|
|
138
|
+
// 20:57:17 had its first peer at 20:57:18 and was taken out of the swarm at
|
|
139
|
+
// 20:57:21 — while the read of the file's edges was still in flight. Nothing
|
|
140
|
+
// rejoined it, because rejoining waits for a reader and the reader was
|
|
141
|
+
// waiting for the header the swarm was fetching.
|
|
142
|
+
const torrent = torrentWith(103);
|
|
143
|
+
const pool = poolWith(torrent);
|
|
144
|
+
try {
|
|
145
|
+
pool.followTheReaders(torrent);
|
|
146
|
+
assert.equal(torrent.paused, false, "a torrent being opened was taken out of its swarm");
|
|
147
|
+
assert.equal(torrent._peers.size, 103, "and its connections were let go");
|
|
148
|
+
} finally {
|
|
149
|
+
forgetTorrent(torrent);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("once it has been read, leaving is allowed again", () => {
|
|
154
|
+
const torrent = torrentWith(4);
|
|
155
|
+
const pool = poolWith(torrent);
|
|
156
|
+
try {
|
|
157
|
+
// A reader arrives and goes.
|
|
158
|
+
pool.fileUsageByTorrent.set(torrent, new Map([[0, 1]]));
|
|
159
|
+
pool.followTheReaders(torrent);
|
|
160
|
+
assert.equal(torrent.paused, false);
|
|
161
|
+
|
|
162
|
+
pool.fileUsageByTorrent.set(torrent, new Map());
|
|
163
|
+
pool.followTheReaders(torrent);
|
|
164
|
+
assert.equal(torrent.paused, true, "a film somebody left keeps its swarm for nobody");
|
|
165
|
+
} finally {
|
|
166
|
+
forgetTorrent(torrent);
|
|
167
|
+
}
|
|
168
|
+
});
|