@torrent-tv/proxy 2.96.2 → 2.96.3
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
|
@@ -258,6 +258,19 @@ export class OutputSpec {
|
|
|
258
258
|
return this.audio?.fileIndex ?? -1;
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
+
/**
|
|
262
|
+
* The files of the torrent whose bytes this output reads: the picture's file
|
|
263
|
+
* where it carries a picture, the soundtrack's where it carries sound. A
|
|
264
|
+
* soundtrack shipped beside the picture is a file of its own, and its bytes
|
|
265
|
+
* are wanted from that file and not from the picture's.
|
|
266
|
+
*
|
|
267
|
+
* @returns {number[]}
|
|
268
|
+
*/
|
|
269
|
+
get sourceFileIndexes() {
|
|
270
|
+
return [...new Set([this.video?.fileIndex, this.audio?.fileIndex]
|
|
271
|
+
.filter((fileIndex) => Number.isInteger(fileIndex) && fileIndex >= 0))];
|
|
272
|
+
}
|
|
273
|
+
|
|
261
274
|
/** @returns {number} */
|
|
262
275
|
get audioSourceTrackIndex() {
|
|
263
276
|
return this.audio?.trackIndex ?? 0;
|
|
@@ -584,8 +584,7 @@ export class ViewerRequests {
|
|
|
584
584
|
output.segmentFormat.servedMediaRanges(ranges, { initBytes: sessionInit }) : undefined
|
|
585
585
|
};
|
|
586
586
|
});
|
|
587
|
-
const sourceIndexes = [output.spec.
|
|
588
|
-
.filter((fileIndex) => Number.isInteger(fileIndex) && fileIndex >= 0);
|
|
587
|
+
const sourceIndexes = [...output.spec.sourceFileIndexes];
|
|
589
588
|
if (sourceIndexes.length === 0) {
|
|
590
589
|
sourceIndexes.push(output.file.fileIndex);
|
|
591
590
|
}
|
|
@@ -216,23 +216,34 @@ export class PriorityOrchestrator {
|
|
|
216
216
|
if (typeof sourceKey !== "string" || !sourceKey || !Number.isSafeInteger(fileIndex) || fileIndex < 0) {
|
|
217
217
|
throw new TypeError("A priority map requires its output file's source and file index.");
|
|
218
218
|
}
|
|
219
|
-
const key = `${sourceKey}:${fileIndex}`;
|
|
220
219
|
const durationSeconds = Number(session.file?.durationSeconds) || 0;
|
|
221
220
|
// The first band is as wide as an interruption this file has actually
|
|
222
221
|
// shown on this swarm, never a chosen number.
|
|
223
222
|
const allowanceSeconds = this.#allowanceFor(session);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
byFile.
|
|
235
|
-
|
|
223
|
+
// EVERY FILE THE OUTPUT READS, not only the one it is named after. A
|
|
224
|
+
// soundtrack shipped beside the picture is an output of the picture's
|
|
225
|
+
// film whose bytes live in another file; mapped under the picture's
|
|
226
|
+
// file only, nobody asked the swarm for that file, its encoder waited
|
|
227
|
+
// for pieces for ever and the viewer who chose the soundtrack stood
|
|
228
|
+
// still (Home Assistant 2026-10-09, torrent-tv/meta#8).
|
|
229
|
+
const read = session.spec?.sourceFileIndexes;
|
|
230
|
+
const files = Array.isArray(read) && read.length ? read : [fileIndex];
|
|
231
|
+
const helds = files.map((index) => {
|
|
232
|
+
const fileKey = `${sourceKey}:${index}`;
|
|
233
|
+
let held = byFile.get(fileKey);
|
|
234
|
+
if (!held) {
|
|
235
|
+
held = {
|
|
236
|
+
sourceKey,
|
|
237
|
+
fileIndex: index,
|
|
238
|
+
durationSeconds,
|
|
239
|
+
allowanceSeconds,
|
|
240
|
+
viewers: [],
|
|
241
|
+
demandKey: []
|
|
242
|
+
};
|
|
243
|
+
byFile.set(fileKey, held);
|
|
244
|
+
}
|
|
245
|
+
return held;
|
|
246
|
+
});
|
|
236
247
|
// Every output anybody holds a session for, whether or not a viewer is
|
|
237
248
|
// consuming it — an output with nobody on it must get a map with
|
|
238
249
|
// nothing in it, which is how the plan is told to stop its encoders.
|
|
@@ -240,16 +251,19 @@ export class PriorityOrchestrator {
|
|
|
240
251
|
const address = session.outputKey ?? "";
|
|
241
252
|
let mine = byOutput.get(address);
|
|
242
253
|
if (!mine) {
|
|
243
|
-
|
|
254
|
+
// Counted over a file the output itself reads, which is always among
|
|
255
|
+
// the files mapped above; the picture's file is not one for a
|
|
256
|
+
// soundtrack read from a file of its own.
|
|
257
|
+
mine = { durationSeconds, allowanceSeconds, viewers: [], fileKey: `${sourceKey}:${files[0]}` };
|
|
244
258
|
byOutput.set(address, mine);
|
|
245
259
|
}
|
|
246
260
|
for (const viewer of this.#viewers.forOutput(session).values()) {
|
|
247
261
|
if (!viewer.isPresent()) {
|
|
248
262
|
continue;
|
|
249
263
|
}
|
|
250
|
-
|
|
264
|
+
const demand = [session.outputKey, viewer.id, viewer.audio?.trackIndex,
|
|
251
265
|
viewer.audio?.transcode, viewer.activeVariantId, viewer.warmingVariantId,
|
|
252
|
-
viewer.warmingAudioId, this.#watchedBy(session, viewer)]
|
|
266
|
+
viewer.warmingAudioId, this.#watchedBy(session, viewer)];
|
|
253
267
|
const stated = {
|
|
254
268
|
id: viewer.id,
|
|
255
269
|
atSeconds: viewer.positionSeconds(now) ?? 0,
|
|
@@ -267,7 +281,10 @@ export class PriorityOrchestrator {
|
|
|
267
281
|
? viewer.wantsFilmNow()
|
|
268
282
|
: viewer.playing === true || viewer.waiting === true)
|
|
269
283
|
};
|
|
270
|
-
held
|
|
284
|
+
for (const held of helds) {
|
|
285
|
+
held.demandKey.push(demand);
|
|
286
|
+
held.viewers.push(stated);
|
|
287
|
+
}
|
|
271
288
|
if (this.#watchedBy(session, viewer)) {
|
|
272
289
|
mine.viewers.push(stated);
|
|
273
290
|
}
|