@torrent-tv/proxy 2.98.18 → 2.98.19
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
package/server.js
CHANGED
|
@@ -65,6 +65,7 @@ import { DownloadMaps } from "./services/viewer/DownloadMaps.js";
|
|
|
65
65
|
import { nativeSourceMap, nativeOriginalSourceMap } from "./services/viewer/NativeSourceMap.js";
|
|
66
66
|
import { MediaReadRequests } from "./services/media/MediaReadRequests.js";
|
|
67
67
|
import { SegmentInputs } from "./services/media/SegmentInputs.js";
|
|
68
|
+
import { directSegmentInput } from "./services/media/direct-segment-input.js";
|
|
68
69
|
import { ContainerTrack } from "./services/media/tracks/ContainerTrack.js";
|
|
69
70
|
import { pauseCoefficient, viewerStartsOn } from "./services/viewer/PriorityMap.js";
|
|
70
71
|
import { coalescing } from "./utils/coalesce.js";
|
|
@@ -551,6 +552,17 @@ export async function startProxyServer({
|
|
|
551
552
|
`${Math.round(passCosts.ms)}ms from start to result in all, longest ${Math.round(passCosts.maxMs)}ms`);
|
|
552
553
|
Object.assign(passCosts, { since: now, passes: 0, whole: 0, reworked: 0, resolved: 0, windows: 0, ms: 0, maxMs: 0 });
|
|
553
554
|
};
|
|
555
|
+
// A container whose packet table a pass did not wait for builds the map
|
|
556
|
+
// again once, when the table is built or refused (`directSegmentInput`).
|
|
557
|
+
const refreshAfterTable = new WeakSet();
|
|
558
|
+
const refreshWhenBuilt = (container, built, { sourceKey, fileIndex }) => {
|
|
559
|
+
if (refreshAfterTable.has(container)) return;
|
|
560
|
+
refreshAfterTable.add(container);
|
|
561
|
+
void built.then(() => {
|
|
562
|
+
refreshAfterTable.delete(container);
|
|
563
|
+
return downloadMaps.refresh(sourceKey, fileIndex);
|
|
564
|
+
}).catch(error => logger.warn(`download map after a packet table: ${error?.message ?? error}`));
|
|
565
|
+
};
|
|
554
566
|
const downloadMaps = new DownloadMaps({
|
|
555
567
|
// The ranges a picture reads at open are named again by every segment;
|
|
556
568
|
// only the zone the swarm would rank first is sent (torrent-tv/meta#166).
|
|
@@ -693,13 +705,15 @@ export async function startProxyServer({
|
|
|
693
705
|
// packets, which the same index states (torrent-tv/meta#166).
|
|
694
706
|
let value = null;
|
|
695
707
|
try {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
const index = await direct.readPacketIndex(interval);
|
|
699
|
-
await index.prepareAudioDependencies?.(interval, direct.readRange);
|
|
700
|
-
value = new SegmentInputs({ index, tracks: wanted }).forInterval({ ...interval, mode: track => modes.get(track) });
|
|
701
|
-
}
|
|
708
|
+
value = await directSegmentInput(direct, { interval, tracks: wanted, mode: track => modes.get(track) },
|
|
709
|
+
built => refreshWhenBuilt(direct, built, map));
|
|
702
710
|
} catch { value = null; }
|
|
711
|
+
// A table still being built holds this output's segments, and only
|
|
712
|
+
// this output's: the map is built again when it is.
|
|
713
|
+
if (value?.kind === "pending") {
|
|
714
|
+
waiting.add(zone.outputKey);
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
703
717
|
// The pass shares the thread in equal turns (`takeTurns`): in one
|
|
704
718
|
// stretch the first pass over a film's 4000 zones held the main thread
|
|
705
719
|
// for all of its work, and handed back after every zone it took
|
|
@@ -199,6 +199,20 @@ export class AviContainer extends Container {
|
|
|
199
199
|
return false;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Whether reading the sound's packet table now would wait for it to be
|
|
204
|
+
* built: the index is read, the table is not, and no refusal of memory for
|
|
205
|
+
* it stands. A reader with other work may go on with it instead. Field r42
|
|
206
|
+
* (Home Assistant, 2026-10-14): the download map waited 3.2 s for the
|
|
207
|
+
* table, between the soundtrack's first segment and the picture's next
|
|
208
|
+
* ones, and the swarm was asked for the picture's next piece only after it
|
|
209
|
+
* (torrent-tv/meta#178).
|
|
210
|
+
*/
|
|
211
|
+
packetTableWouldWait() {
|
|
212
|
+
if (!this.#index || this.#packets || this.#scan) return false;
|
|
213
|
+
return this.#soundPacketsRefused === null || this.packetMemory?.fits?.(this.#soundPacketsRefused) !== false;
|
|
214
|
+
}
|
|
215
|
+
|
|
202
216
|
/** The index, read from the file; see `#readIndex`. */
|
|
203
217
|
async #readIndexOnce() {
|
|
204
218
|
const tracks = await this.readTracks();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The bytes one segment reads, from an index its container already
|
|
3
|
+
* holds, for the download map's pass (torrent-tv/meta#178).
|
|
4
|
+
*
|
|
5
|
+
* The pass works out every segment of every output a viewer watches, one at a
|
|
6
|
+
* time. A segment read from the original file is answered by arithmetic over
|
|
7
|
+
* the index; a soundtrack segment of an AVI needs the sound's packet table,
|
|
8
|
+
* which is built once for the whole film. While that table was being built the
|
|
9
|
+
* pass waited for it, and the picture's segments after the soundtrack's first
|
|
10
|
+
* were not stated to the swarm: field r42 (Home Assistant, 2026-10-14), the
|
|
11
|
+
* picture's next piece was asked for 4.0 s after its input asked for it, 3.2 s
|
|
12
|
+
* of that behind the table.
|
|
13
|
+
*/
|
|
14
|
+
import { SegmentInputs } from "./SegmentInputs.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} container - Has `supportsOriginalSourceRanges`, `readSourceRanges` and `readPacketIndex`.
|
|
18
|
+
* @param {{ interval: object, tracks: object[], mode: (track: object) => string }} segment
|
|
19
|
+
* @param {(built: Promise<void>) => void} whenBuilt - Given a promise that settles when a table
|
|
20
|
+
* still being built is built or refused, when the answer is "pending".
|
|
21
|
+
* @returns {Promise<{ kind: string, ranges?: Array<[number, number]> }>} `pending` when the
|
|
22
|
+
* answer waits for a table still being built.
|
|
23
|
+
*/
|
|
24
|
+
export async function directSegmentInput(container, { interval, tracks, mode }, whenBuilt) {
|
|
25
|
+
if (await container.supportsOriginalSourceRanges(interval) === true) return container.readSourceRanges(interval);
|
|
26
|
+
// The table is begun, or joined, and not waited for.
|
|
27
|
+
if (container.packetTableWouldWait?.() === true) {
|
|
28
|
+
whenBuilt(container.readPacketIndex(interval).then(() => undefined, () => undefined));
|
|
29
|
+
return { kind: "pending" };
|
|
30
|
+
}
|
|
31
|
+
const index = await container.readPacketIndex(interval);
|
|
32
|
+
await index.prepareAudioDependencies?.(interval, container.readRange);
|
|
33
|
+
return new SegmentInputs({ index, tracks }).forInterval({ ...interval, mode });
|
|
34
|
+
}
|