@torrent-tv/proxy 2.99.17 → 2.99.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
|
@@ -680,6 +680,26 @@ export class MatroskaContainer extends Container {
|
|
|
680
680
|
return cues.points.some(point => point.positions.some(position => !video || position.track === video.trackNumber));
|
|
681
681
|
}
|
|
682
682
|
|
|
683
|
+
/**
|
|
684
|
+
* Whether `statement` is answered from what this container has already
|
|
685
|
+
* read, so it may be answered beside a read of the same file in progress
|
|
686
|
+
* (`ContainerOrchestrator.inspect`), as an AVI's are. The picture's
|
|
687
|
+
* ranges are arithmetic over the Cues once they are read; asked behind a
|
|
688
|
+
* soundtrack's packet walk in the file's one queue, the picture's next
|
|
689
|
+
* input after a seek was ready only after the sound's, one piece every
|
|
690
|
+
* 7-8 s, where the two had been prepared side by side every 2 s (r57 against
|
|
691
|
+
* r50, torrent-tv/meta#178).
|
|
692
|
+
*
|
|
693
|
+
* @param {string} statement
|
|
694
|
+
* @returns {boolean}
|
|
695
|
+
*/
|
|
696
|
+
answersWithoutReading(statement) {
|
|
697
|
+
if (statement === "media-info") return this.mediaInfo?.durationSeconds != null;
|
|
698
|
+
if (statement === "source-navigation") return this.#cues !== undefined && this.#tracks !== null;
|
|
699
|
+
if (statement === "source-ranges") return this.#sourceSeekPoints !== null;
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
|
|
683
703
|
async readMappedSourceRanges(interval) { return this.readSourceRanges(interval); }
|
|
684
704
|
|
|
685
705
|
/**
|
|
@@ -834,6 +854,17 @@ export class MatroskaContainer extends Container {
|
|
|
834
854
|
const declared = new Map([[id, track]]);
|
|
835
855
|
const asked = interval ? { ...interval, trackIds: [id] } : null;
|
|
836
856
|
const depth = track.type === "video" ? track.reorderDepth : 0;
|
|
857
|
+
// WHERE THE WALK WILL READ, as the Cues name it (`packetWalkRanges`):
|
|
858
|
+
// read a portion at a time across cluster boundaries too. Read a
|
|
859
|
+
// cluster's header and its contents apart, a soundtrack piece took
|
|
860
|
+
// about sixteen reads of the torrent thread, each waiting for its loop
|
|
861
|
+
// (0.5-0.8 s late on Home Assistant), and 7-12 s to prepare with every
|
|
862
|
+
// byte held (r56, torrent-tv/meta#178).
|
|
863
|
+
const walked = interval ? await this.packetWalkRanges(interval) : null;
|
|
864
|
+
const readsThrough = walked ? start => {
|
|
865
|
+
const range = walked.ranges.find(([from, to]) => from <= start && start <= to);
|
|
866
|
+
return range ? range[1] + 1 : null;
|
|
867
|
+
} : null;
|
|
837
868
|
let current = null;
|
|
838
869
|
const covered = () => {
|
|
839
870
|
if (!asked) return false;
|
|
@@ -851,7 +882,7 @@ export class MatroskaContainer extends Container {
|
|
|
851
882
|
const following = readings.find(reading => reading.startAt > current.startAt);
|
|
852
883
|
const outcome = await walkMatroskaPackets({ readRange: this.readRange, fileSize: this.fileSize,
|
|
853
884
|
portionBytes: this.portionBytes, layout, tracks, trackIds: [id], interval, packetMemory: this.packetMemory,
|
|
854
|
-
state: current, until: following?.startAt ?? null, isCovered: covered });
|
|
885
|
+
state: current, until: following?.startAt ?? null, isCovered: covered, readsThrough });
|
|
855
886
|
if (outcome !== "until") break;
|
|
856
887
|
current.next = following;
|
|
857
888
|
}
|
|
@@ -40,9 +40,13 @@ function recordedTracks(tracks, trackIds) {
|
|
|
40
40
|
* Only the named tracks are recorded: a soundtrack read on its own kept the
|
|
41
41
|
* picture's table as well, half of 37.9 MB on r47's order (torrent-tv/meta#178).
|
|
42
42
|
*
|
|
43
|
+
* `readsThrough(start)` is one past the last byte the walk will read from
|
|
44
|
+
* `start` on, where the caller knows it: those are read a portion at a time
|
|
45
|
+
* across clusters too.
|
|
46
|
+
*
|
|
43
47
|
* @returns {Promise<"covered" | "until" | "end">}
|
|
44
48
|
*/
|
|
45
|
-
export async function walkMatroskaPackets({ readRange, fileSize, portionBytes, layout, tracks, trackIds, interval, packetMemory, state, until = null, isCovered = null }) {
|
|
49
|
+
export async function walkMatroskaPackets({ readRange, fileSize, portionBytes, layout, tracks, trackIds, interval, packetMemory, state, until = null, isCovered = null, readsThrough = null }) {
|
|
46
50
|
// INSIDE A CLUSTER EVERY BLOCK HEADER IS READ, so its bytes are read a
|
|
47
51
|
// portion at a time up to the cluster's end, and never past it. Read a
|
|
48
52
|
// header at a time, each a read of a few bytes from the torrent thread, the
|
|
@@ -55,7 +59,7 @@ export async function walkMatroskaPackets({ readRange, fileSize, portionBytes, l
|
|
|
55
59
|
// Between clusters only their headers are read.
|
|
56
60
|
let readableUntil = null;
|
|
57
61
|
const reader = new ElementReader({ read: readRange, fileSize, portionBytes, prefetch: true,
|
|
58
|
-
readableUntil: start => readableUntil ?? start });
|
|
62
|
+
readableUntil: start => Math.max(readableUntil ?? start, readsThrough?.(start) ?? start) });
|
|
59
63
|
const declared = recordedTracks(tracks, trackIds);
|
|
60
64
|
if (!state.packets) {
|
|
61
65
|
state.packets = new Map([...declared.keys()].map(id => [id, new PacketRecords(packetMemory)]));
|