@torrent-tv/proxy 2.89.6 → 2.89.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/AGENTS.md +32 -12
- package/CHANGELOG.md +2340 -2330
- package/assets/calibration/audio/NOTICE.md +19 -19
- package/assets/calibration/audio/manifest.json +98 -98
- package/biome.json +412 -412
- package/docs/browser-proxy-contract.md +155 -155
- package/docs/container-architecture.md +273 -273
- package/docs/encode-run-state.md +1 -1
- package/docs/playback-start-forecast.md +113 -98
- package/package.json +51 -50
- package/routes/api/sources/files/get.js +106 -106
- package/scripts/build-audio-samples.mjs +31 -31
- package/services/encode/EncodeRun.js +67 -15
- package/services/encode/EncodeRuns.js +19 -7
- package/services/encode/OutputOpening.js +784 -784
- package/services/encode/audio-calibration.js +67 -67
- package/services/encode/audio-work-rate.js +15 -15
- package/services/encode/encode-exit.js +2 -0
- package/services/encode/hwaccel.js +1894 -1894
- package/services/encode/output/index.js +24 -24
- package/services/encode/piece-completeness.js +60 -2
- package/services/encode/run-command.js +757 -755
- package/services/encode/segment-formats/index.js +1 -0
- package/services/encode/segment-formats/mp4-boxes.js +8 -1
- package/services/media/ContainerOrchestrator.js +202 -202
- package/services/media/KeyframeTables.js +356 -356
- package/services/media/SubtitleCues.js +592 -592
- package/services/media/audio-inventory.js +299 -299
- package/services/media/container/AviContainer.js +268 -268
- package/services/media/container/Container.js +632 -632
- package/services/media/container/ContainerFactory.js +38 -38
- package/services/media/container/MatroskaContainer.js +1031 -1031
- package/services/media/container/Mp4Container.js +1354 -1354
- package/services/media/container/SubtitleFileContainer.js +339 -339
- package/services/media/container/ebml-stream.js +174 -174
- package/services/media/container/matroska-clusters.js +1165 -1165
- package/services/media/container/unavailable.js +77 -77
- package/services/media/tracks/ContainerTrack.js +84 -84
- package/services/media/tracks/TextSubtitleTrack.js +295 -295
- package/services/storage/piece-store/shared-piece-store.js +1937 -1937
- package/services/storage/segment-store/SegmentStore.js +1294 -1294
- package/services/torrent/Contents.js +382 -382
- package/services/torrent/episode-naming.js +182 -182
- package/services/torrent/torrent-pool.js +2688 -2688
- package/services/torrent/worker/client.js +836 -836
- package/services/torrent/worker/held-bytes.js +231 -231
- package/services/torrent/worker/worker.js +1137 -1137
- package/services/transport/data-channel-handler.js +1373 -1373
- package/services/viewer/PriorityMap.js +421 -421
- package/test/audio-calibration.test.js +23 -23
- package/test/auto-quality-step.test.js +762 -762
- package/test/coalesce.test.js +39 -39
- package/test/coverage-follows-the-disk.test.js +5 -0
- package/test/decode-cost.test.js +475 -475
- package/test/encode-run.test.js +58 -0
- package/test/episode-naming.test.js +131 -131
- package/test/failed-encoder-still-serves-what-exists.test.js +1 -1
- package/test/fixtures/audio-frame-boundary.json +1 -1
- package/test/fixtures/refused-audio-20261002.json +10 -0
- package/test/fmp4-presentation-clock.test.js +4 -2
- package/test/format-keyed-outputs.test.js +78 -78
- package/test/health-metrics.test.js +11 -13
- package/test/held-read-ownership.test.js +77 -77
- package/test/helpers/encode-run.js +14 -6
- package/test/helpers/held-file.js +77 -77
- package/test/helpers/manager.js +62 -62
- package/test/helpers/matroska-file.js +296 -296
- package/test/keyframe-table-budget.test.js +123 -123
- package/test/matroska-cluster-discovery.test.js +323 -323
- package/test/one-output-one-session.test.js +273 -273
- package/test/output-speed.test.js +6 -1
- package/test/piece-completeness.test.js +37 -1
- package/test/quality-variants.test.js +1274 -1270
- package/test/rate-control-in-the-output.test.js +4 -3
- package/test/reads-not-yet-arrived.test.js +218 -218
- package/test/seek-frees-the-viewers-requests.test.js +1 -1
- package/test/segment-closed-on-both-branches.test.js +114 -114
- package/test/segment-judged-by-its-own-header.test.js +222 -222
- package/test/segment-serve-wiring.test.js +481 -481
- package/test/serving-existing-output.test.js +111 -111
- package/test/source-files-route.test.js +113 -113
- package/test/subtitle-cue-walk.test.js +385 -385
- package/test/subtitle-metadata.test.js +15 -15
- package/test/subtitle-plan-waits.test.js +125 -125
- package/test/subtitle-track-numbering.test.js +391 -391
- package/test/two-viewers-one-picture.test.js +508 -508
- package/test/viewer-requests-admission.test.js +92 -92
- package/test/viewer-starts-on-map.test.js +27 -27
- package/test/viewer-states.test.js +5 -2
- package/test/viewing-generations.test.js +390 -390
- package/test/whole-file-held-read.test.js +30 -30
- package/utils/coalesce.js +41 -41
package/test/encode-run.test.js
CHANGED
|
@@ -13,6 +13,7 @@ import { EventEmitter } from "node:events";
|
|
|
13
13
|
import { EncodeRun } from "../services/encode/EncodeRun.js";
|
|
14
14
|
import { ENCODE_EXIT } from "../services/encode/encode-exit.js";
|
|
15
15
|
import { SoftwareEncoder } from "../services/encode/SoftwareEncoder.js";
|
|
16
|
+
import { fakeProcess, silentLogger } from "./helpers/encode-run.js";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* A process that does nothing until the test says what became of it.
|
|
@@ -188,3 +189,60 @@ test("a segment number behind its own start is not its to claim", () => {
|
|
|
188
189
|
run.noteProduced(4);
|
|
189
190
|
assert.deepEqual(run.produced, []);
|
|
190
191
|
});
|
|
192
|
+
|
|
193
|
+
test("CSV closure times survive split channel chunks and a zero first-entry start", () => {
|
|
194
|
+
const process_ = new FakeProcess();
|
|
195
|
+
process_.stdio = [null, null, null, new EventEmitter()];
|
|
196
|
+
const closed = [];
|
|
197
|
+
const run = new EncodeRun({
|
|
198
|
+
address: "audio", encoder: new SoftwareEncoder(), from: 13, to: 14,
|
|
199
|
+
buildArgs: () => [], spawn: () => process_, logger: { info() {}, warn() {} },
|
|
200
|
+
indexOfName: name => Number(name.match(/(\d+)\.mp4$/)[1]),
|
|
201
|
+
onClosed: (name, timing) => { closed.push({ name, timing }); return name; }
|
|
202
|
+
});
|
|
203
|
+
process_.stdio[3].emit("data", "making-0-00013.mp4,0.000000,81.364");
|
|
204
|
+
process_.stdio[3].emit("data", "000\nmaking-0-00014.mp4,81.364000,91.800000\n");
|
|
205
|
+
process_.exitWith(0);
|
|
206
|
+
assert.equal(run.reached, 14);
|
|
207
|
+
assert.deepEqual(closed.map(({ timing }) => timing), [
|
|
208
|
+
{ endMicros: 81_364_000n },
|
|
209
|
+
{ endMicros: 91_800_000n }
|
|
210
|
+
]);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("a refused publication stops its claim and ends as a publication failure", () => {
|
|
214
|
+
const process_ = new FakeProcess();
|
|
215
|
+
process_.stdio = [null, null, null, new EventEmitter()];
|
|
216
|
+
const ends = [];
|
|
217
|
+
const run = new EncodeRun({
|
|
218
|
+
address: "audio", encoder: new SoftwareEncoder(), from: 13, to: 14,
|
|
219
|
+
buildArgs: () => [], spawn: () => process_, logger: { info() {}, warn() {} },
|
|
220
|
+
onClosed: () => { throw new Error("piece 13 is incomplete"); },
|
|
221
|
+
onEnded: ended => ends.push(ended)
|
|
222
|
+
});
|
|
223
|
+
process_.stdio[3].emit("data", "making-0-00013.mp4,71.55,71.56\nmaking-0-00014.mp4,71.56,91.8\n");
|
|
224
|
+
assert.deepEqual(process_.signals, ["SIGTERM"]);
|
|
225
|
+
process_.exitWith(0);
|
|
226
|
+
assert.equal(run.isAlive, false);
|
|
227
|
+
assert.equal(ends[0].ending, ENCODE_EXIT.PUBLICATION_FAILED);
|
|
228
|
+
assert.equal(ends[0].because, "piece 13 is incomplete");
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("a run whose process never started is not signalled, because pid 0 is our own process group", () => {
|
|
232
|
+
// Node reports a failed start (ENOENT) on a later turn; until then the child's
|
|
233
|
+
// process id is 0, and a signal sent to it is `kill(0, …)` — every process in
|
|
234
|
+
// our group, the proxy included. Measured 2026-10-03 under `node --test`.
|
|
235
|
+
const child = fakeProcess({ pid: null });
|
|
236
|
+
const run = new EncodeRun({
|
|
237
|
+
address: "torrent:abc:video-only:v=0/copy",
|
|
238
|
+
encoder: { name: "libx264", kind: "software" },
|
|
239
|
+
from: 0,
|
|
240
|
+
to: 4,
|
|
241
|
+
buildArgs: () => [],
|
|
242
|
+
spawn: () => child,
|
|
243
|
+
logger: silentLogger,
|
|
244
|
+
because: "a test asked for it"
|
|
245
|
+
});
|
|
246
|
+
run.stop("the viewer left");
|
|
247
|
+
assert.deepEqual(child.signals, [], "a process that did not start was sent a signal");
|
|
248
|
+
});
|
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file What a picture's name says about which episode it is, and what a whole
|
|
3
|
-
* torrent's pictures are taken together.
|
|
4
|
-
*
|
|
5
|
-
* Every name below is taken from a release in the survey collection, except
|
|
6
|
-
* where a test says it is built to reach an edge.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import test from "node:test";
|
|
10
|
-
import assert from "node:assert/strict";
|
|
11
|
-
import { readEpisodeMarker } from "../services/torrent/episode-naming.js";
|
|
12
|
-
import { TorrentContents } from "../services/torrent/Contents.js";
|
|
13
|
-
|
|
14
|
-
test("season and episode with the episode title after them", () => {
|
|
15
|
-
assert.deepEqual(readEpisodeMarker({ name: "s01e02_Murder.in.the.Mews.avi", folders: ["Season_01"] }), {
|
|
16
|
-
season: 1,
|
|
17
|
-
episodes: [2],
|
|
18
|
-
part: null,
|
|
19
|
-
special: false,
|
|
20
|
-
showHint: "",
|
|
21
|
-
titleHint: "Murder.in.the.Mews"
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("a separator between the season and the episode is still one marker", () => {
|
|
26
|
-
const marker = readEpisodeMarker({ name: "s03.e01_The.Mysterious.Affair.at.Styles.avi" });
|
|
27
|
-
assert.equal(marker.season, 3);
|
|
28
|
-
assert.deepEqual(marker.episodes, [1]);
|
|
29
|
-
assert.equal(marker.titleHint, "The.Mysterious.Affair.at.Styles");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("a part of one episode is its own field and leaves the title", () => {
|
|
33
|
-
const marker = readEpisodeMarker({ name: "s02e01_Peril.at.End.House_Part.1.avi" });
|
|
34
|
-
assert.equal(marker.part, 1);
|
|
35
|
-
assert.equal(marker.titleHint, "Peril.at.End.House");
|
|
36
|
-
assert.deepEqual(marker.episodes, [1]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("the show name comes before the marker and release tags after it", () => {
|
|
40
|
-
const marker = readEpisodeMarker({ name: "Reacher.S04E01.1080p.rus.LostFilm.TV.mkv" });
|
|
41
|
-
assert.equal(marker.season, 4);
|
|
42
|
-
assert.equal(marker.showHint, "Reacher");
|
|
43
|
-
assert.equal(marker.titleHint, "1080p.rus.LostFilm.TV");
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("one file carrying several episodes lists all of them", () => {
|
|
47
|
-
assert.deepEqual(readEpisodeMarker({ name: "Show.S01E01E02.mkv" }).episodes, [1, 2]);
|
|
48
|
-
assert.deepEqual(readEpisodeMarker({ name: "Show.S01E01-E03.mkv" }).episodes, [1, 2, 3]);
|
|
49
|
-
assert.deepEqual(readEpisodeMarker({ name: "Show.S01E01-02.mkv" }).episodes, [1, 2]);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("a claim of more episodes than a file carries is not a marker", () => {
|
|
53
|
-
assert.equal(readEpisodeMarker({ name: "Show.S01E01-40.mkv" }), null);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("season 0 and a name calling itself a special are specials", () => {
|
|
57
|
-
assert.equal(readEpisodeMarker({ name: "Show.S00E03.mkv" }).special, true);
|
|
58
|
-
assert.equal(readEpisodeMarker({ name: "Show - 05 Special.mkv" }).special, true);
|
|
59
|
-
assert.equal(readEpisodeMarker({ name: "Show.S01E03.mkv" }).special, false);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("the numbering anime releases use, with no season in it", () => {
|
|
63
|
-
const marker = readEpisodeMarker({ name: "[HorribleSubs] Drifters - 01 [1080p].mkv" });
|
|
64
|
-
assert.equal(marker.season, null);
|
|
65
|
-
assert.deepEqual(marker.episodes, [1]);
|
|
66
|
-
assert.equal(marker.showHint, "[HorribleSubs] Drifters");
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
test("a season stated just before the dash number is read", () => {
|
|
70
|
-
const marker = readEpisodeMarker({ name: "Koukaku Kidoutai (2026) S1 - 01.mkv" });
|
|
71
|
-
assert.equal(marker.season, 1);
|
|
72
|
-
assert.equal(marker.showHint, "Koukaku Kidoutai (2026)");
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test("a season folder gives the season to an episode number without one", () => {
|
|
76
|
-
const marker = readEpisodeMarker({ name: "Episode.05.mkv", folders: ["Сезон 2"] });
|
|
77
|
-
assert.equal(marker.season, 2);
|
|
78
|
-
assert.deepEqual(marker.episodes, [5]);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("names that state no episode say nothing", () => {
|
|
82
|
-
for (const name of [
|
|
83
|
-
"Despicable.Me.4.2024.1080p.BluRay.x264-EniaHD.mkv",
|
|
84
|
-
"Movie - 2024 [1080p].mkv",
|
|
85
|
-
"WALL-E.2008.1080p.mkv",
|
|
86
|
-
"Mortal.Kombat.II.1080p.rus.LostFilm.TV.mkv",
|
|
87
|
-
"Video.1920x1080.mkv",
|
|
88
|
-
"VTS_01_1.VOB"
|
|
89
|
-
]) {
|
|
90
|
-
assert.equal(readEpisodeMarker({ name }), null, name);
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* @param {string} name
|
|
96
|
-
* @param {string[]} relatives
|
|
97
|
-
* @returns {TorrentContents}
|
|
98
|
-
*/
|
|
99
|
-
function contents(name, relatives) {
|
|
100
|
-
return new TorrentContents({
|
|
101
|
-
name,
|
|
102
|
-
files: relatives.map((relative) => ({
|
|
103
|
-
path: `${name}/${relative}`,
|
|
104
|
-
name: relative.slice(relative.lastIndexOf("/") + 1),
|
|
105
|
-
length: 1
|
|
106
|
-
}))
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
test("one picture is a single work", () => {
|
|
111
|
-
assert.equal(new TorrentContents({ name: "Film.mkv", files: [{ path: "Film.mkv", name: "Film.mkv", length: 1 }] }).shape, "single");
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test("numbered pictures of one show are a series, and an unnumbered one stays in it", () => {
|
|
115
|
-
const pack = contents("Poirot", ["Season_01/s01e01_A.avi", "Season_01/s01e02_B.avi", "Special.avi"]);
|
|
116
|
-
assert.equal(pack.shape, "series");
|
|
117
|
-
assert.equal(pack.items.find((item) => item.name === "Special.avi").episode, null);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("pictures without numbers are not called a collection, only not known", () => {
|
|
121
|
-
assert.equal(contents("Trilogy", ["One.2010.mkv", "Two.2013.mkv", "Three.2017.mkv"]).shape, "undetermined");
|
|
122
|
-
assert.equal(contents("Film", ["Film.mkv", "Film.S01E01.mkv"]).shape, "undetermined");
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
test("two differently named shows are not one series", () => {
|
|
126
|
-
assert.equal(contents("Mixed", ["Alpha.S01E01.mkv", "Beta.S01E01.mkv"]).shape, "undetermined");
|
|
127
|
-
assert.equal(
|
|
128
|
-
contents("Drifters", ["[HorribleSubs] Drifters - 01 [1080p].mkv", "[Other] Drifters - 02 [720p].mkv"]).shape,
|
|
129
|
-
"series"
|
|
130
|
-
);
|
|
131
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file What a picture's name says about which episode it is, and what a whole
|
|
3
|
+
* torrent's pictures are taken together.
|
|
4
|
+
*
|
|
5
|
+
* Every name below is taken from a release in the survey collection, except
|
|
6
|
+
* where a test says it is built to reach an edge.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import test from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { readEpisodeMarker } from "../services/torrent/episode-naming.js";
|
|
12
|
+
import { TorrentContents } from "../services/torrent/Contents.js";
|
|
13
|
+
|
|
14
|
+
test("season and episode with the episode title after them", () => {
|
|
15
|
+
assert.deepEqual(readEpisodeMarker({ name: "s01e02_Murder.in.the.Mews.avi", folders: ["Season_01"] }), {
|
|
16
|
+
season: 1,
|
|
17
|
+
episodes: [2],
|
|
18
|
+
part: null,
|
|
19
|
+
special: false,
|
|
20
|
+
showHint: "",
|
|
21
|
+
titleHint: "Murder.in.the.Mews"
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("a separator between the season and the episode is still one marker", () => {
|
|
26
|
+
const marker = readEpisodeMarker({ name: "s03.e01_The.Mysterious.Affair.at.Styles.avi" });
|
|
27
|
+
assert.equal(marker.season, 3);
|
|
28
|
+
assert.deepEqual(marker.episodes, [1]);
|
|
29
|
+
assert.equal(marker.titleHint, "The.Mysterious.Affair.at.Styles");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("a part of one episode is its own field and leaves the title", () => {
|
|
33
|
+
const marker = readEpisodeMarker({ name: "s02e01_Peril.at.End.House_Part.1.avi" });
|
|
34
|
+
assert.equal(marker.part, 1);
|
|
35
|
+
assert.equal(marker.titleHint, "Peril.at.End.House");
|
|
36
|
+
assert.deepEqual(marker.episodes, [1]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("the show name comes before the marker and release tags after it", () => {
|
|
40
|
+
const marker = readEpisodeMarker({ name: "Reacher.S04E01.1080p.rus.LostFilm.TV.mkv" });
|
|
41
|
+
assert.equal(marker.season, 4);
|
|
42
|
+
assert.equal(marker.showHint, "Reacher");
|
|
43
|
+
assert.equal(marker.titleHint, "1080p.rus.LostFilm.TV");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("one file carrying several episodes lists all of them", () => {
|
|
47
|
+
assert.deepEqual(readEpisodeMarker({ name: "Show.S01E01E02.mkv" }).episodes, [1, 2]);
|
|
48
|
+
assert.deepEqual(readEpisodeMarker({ name: "Show.S01E01-E03.mkv" }).episodes, [1, 2, 3]);
|
|
49
|
+
assert.deepEqual(readEpisodeMarker({ name: "Show.S01E01-02.mkv" }).episodes, [1, 2]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("a claim of more episodes than a file carries is not a marker", () => {
|
|
53
|
+
assert.equal(readEpisodeMarker({ name: "Show.S01E01-40.mkv" }), null);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("season 0 and a name calling itself a special are specials", () => {
|
|
57
|
+
assert.equal(readEpisodeMarker({ name: "Show.S00E03.mkv" }).special, true);
|
|
58
|
+
assert.equal(readEpisodeMarker({ name: "Show - 05 Special.mkv" }).special, true);
|
|
59
|
+
assert.equal(readEpisodeMarker({ name: "Show.S01E03.mkv" }).special, false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("the numbering anime releases use, with no season in it", () => {
|
|
63
|
+
const marker = readEpisodeMarker({ name: "[HorribleSubs] Drifters - 01 [1080p].mkv" });
|
|
64
|
+
assert.equal(marker.season, null);
|
|
65
|
+
assert.deepEqual(marker.episodes, [1]);
|
|
66
|
+
assert.equal(marker.showHint, "[HorribleSubs] Drifters");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("a season stated just before the dash number is read", () => {
|
|
70
|
+
const marker = readEpisodeMarker({ name: "Koukaku Kidoutai (2026) S1 - 01.mkv" });
|
|
71
|
+
assert.equal(marker.season, 1);
|
|
72
|
+
assert.equal(marker.showHint, "Koukaku Kidoutai (2026)");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("a season folder gives the season to an episode number without one", () => {
|
|
76
|
+
const marker = readEpisodeMarker({ name: "Episode.05.mkv", folders: ["Сезон 2"] });
|
|
77
|
+
assert.equal(marker.season, 2);
|
|
78
|
+
assert.deepEqual(marker.episodes, [5]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("names that state no episode say nothing", () => {
|
|
82
|
+
for (const name of [
|
|
83
|
+
"Despicable.Me.4.2024.1080p.BluRay.x264-EniaHD.mkv",
|
|
84
|
+
"Movie - 2024 [1080p].mkv",
|
|
85
|
+
"WALL-E.2008.1080p.mkv",
|
|
86
|
+
"Mortal.Kombat.II.1080p.rus.LostFilm.TV.mkv",
|
|
87
|
+
"Video.1920x1080.mkv",
|
|
88
|
+
"VTS_01_1.VOB"
|
|
89
|
+
]) {
|
|
90
|
+
assert.equal(readEpisodeMarker({ name }), null, name);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} name
|
|
96
|
+
* @param {string[]} relatives
|
|
97
|
+
* @returns {TorrentContents}
|
|
98
|
+
*/
|
|
99
|
+
function contents(name, relatives) {
|
|
100
|
+
return new TorrentContents({
|
|
101
|
+
name,
|
|
102
|
+
files: relatives.map((relative) => ({
|
|
103
|
+
path: `${name}/${relative}`,
|
|
104
|
+
name: relative.slice(relative.lastIndexOf("/") + 1),
|
|
105
|
+
length: 1
|
|
106
|
+
}))
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
test("one picture is a single work", () => {
|
|
111
|
+
assert.equal(new TorrentContents({ name: "Film.mkv", files: [{ path: "Film.mkv", name: "Film.mkv", length: 1 }] }).shape, "single");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("numbered pictures of one show are a series, and an unnumbered one stays in it", () => {
|
|
115
|
+
const pack = contents("Poirot", ["Season_01/s01e01_A.avi", "Season_01/s01e02_B.avi", "Special.avi"]);
|
|
116
|
+
assert.equal(pack.shape, "series");
|
|
117
|
+
assert.equal(pack.items.find((item) => item.name === "Special.avi").episode, null);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("pictures without numbers are not called a collection, only not known", () => {
|
|
121
|
+
assert.equal(contents("Trilogy", ["One.2010.mkv", "Two.2013.mkv", "Three.2017.mkv"]).shape, "undetermined");
|
|
122
|
+
assert.equal(contents("Film", ["Film.mkv", "Film.S01E01.mkv"]).shape, "undetermined");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("two differently named shows are not one series", () => {
|
|
126
|
+
assert.equal(contents("Mixed", ["Alpha.S01E01.mkv", "Beta.S01E01.mkv"]).shape, "undetermined");
|
|
127
|
+
assert.equal(
|
|
128
|
+
contents("Drifters", ["[HorribleSubs] Drifters - 01 [1080p].mkv", "[Other] Drifters - 02 [720p].mkv"]).shape,
|
|
129
|
+
"series"
|
|
130
|
+
);
|
|
131
|
+
});
|
|
@@ -27,7 +27,7 @@ import { ENCODE_RUN_STATE } from "../services/encode/encode-run-state.js";
|
|
|
27
27
|
import { fmp4Format } from "../services/encode/segment-formats/fmp4.js";
|
|
28
28
|
import { EncodeRun } from "../services/encode/EncodeRun.js";
|
|
29
29
|
import { fakeProcess, silentLogger } from "./helpers/encode-run.js";
|
|
30
|
-
import { waitForSessionFile } from "../
|
|
30
|
+
import { waitForSessionFile } from "../services/server/transcode-session-files.js";
|
|
31
31
|
import { outputSpec } from "./helpers/output-spec.js";
|
|
32
32
|
|
|
33
33
|
const SESSION_ID = "3333333344445555";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"description":"MP4 metadata boxes captured from adjacent AAC segments. Media payloads are omitted.","files":{"init.mp4":"AAAAHGZ0eXBpc281AAACAGlzbzVpc282bXA0MQAAAvRtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAAAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAB9nRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAAAAAAAAAAEAAAAAAVttZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAALuAAAAAAFXEAAAAAAAtaGRscgAAAAAAAAAAc291bgAAAAAAAAAAAAAAAFNvdW5kSGFuZGxlcgAAAAEGbWluZgAAABBzbWhkAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAADKc3RibAAAAH5zdHNkAAAAAAAAAAEAAABubXA0YQAAAAAAAAABAAAAAAAAAAAAAgAQAAAAALuAAAAAAAA2ZXNkcwAAAAADgICAJQABAASAgIAXQBUAAAAAAfQAAAH0AAWAgIAFEZBW5QAGgICAAQIAAAAUYnRydAAAAAAAAfQAAAH0AAAAABBzdHRzAAAAAAAAAAAAAAAQc3RzYwAAAAAAAAAAAAAAFHN0c3oAAAAAAAAAAAAAAAAAAAAQc3RjbwAAAAAAAAAAAAAAE3VkdGEAAAALbmFtZVJVUwAAAChtdmV4AAAAIHRyZXgAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjYyLjEyLjEwMg==","segment-00171.mp4":"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","segment-00172.mp4":"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"},"browserBufferedRanges":[[1782.997,1793.428999],[1782.997,1803.827333]]}
|
|
1
|
+
{"description":"MP4 metadata boxes captured from adjacent AAC segments. Media payloads are omitted.","files":{"init.mp4":"AAAAHGZ0eXBpc281AAACAGlzbzVpc282bXA0MQAAAvRtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAAAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAB9nRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAAAAAAAAAAEAAAAAAVttZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAALuAAAAAAFXEAAAAAAAtaGRscgAAAAAAAAAAc291bgAAAAAAAAAAAAAAAFNvdW5kSGFuZGxlcgAAAAEGbWluZgAAABBzbWhkAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAADKc3RibAAAAH5zdHNkAAAAAAAAAAEAAABubXA0YQAAAAAAAAABAAAAAAAAAAAAAgAQAAAAALuAAAAAAAA2ZXNkcwAAAAADgICAJQABAASAgIAXQBUAAAAAAfQAAAH0AAWAgIAFEZBW5QAGgICAAQIAAAAUYnRydAAAAAAAAfQAAAH0AAAAABBzdHRzAAAAAAAAAAAAAAAQc3RzYwAAAAAAAAAAAAAAFHN0c3oAAAAAAAAAAAAAAAAAAAAQc3RjbwAAAAAAAAAAAAAAE3VkdGEAAAALbmFtZVJVUwAAAChtdmV4AAAAIHRyZXgAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjYyLjEyLjEwMg==","segment-00171.mp4":"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","segment-00172.mp4":"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"},"browserBufferedRanges":[[1782.997,1793.428999],[1782.997,1803.827333]]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"source": "Headers captured on Home Assistant, proxy 2.89.6, 2026-10-02; media payload omitted.",
|
|
3
|
+
"files": {
|
|
4
|
+
"making-0-00013.mp4": "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",
|
|
5
|
+
"making-0-00090.mp4": "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",
|
|
6
|
+
"repair-13.mp4": "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",
|
|
7
|
+
"repair-14.mp4": "AAADAG1vb3YAAABsbXZoZAAAAAAAAAAAAAAAAAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAICdHJhawAAAFx0a2hkAAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAMGVkdHMAAAAoZWxzdAAAAAAAAAACAAE91P////8AAQAAAAAAAAAAAAAAAQAAAAABW21kaWEAAAAgbWRoZAAAAAAAAAAAAAAAAAAAu4AAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU291bmRIYW5kbGVyAAAAAQZtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAMpzdGJsAAAAfnN0c2QAAAAAAAAAAQAAAG5tcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAAu4AAAAAAADZlc2RzAAAAAAOAgIAlAAEABICAgBdAFQAAAAAB9AAAAfQABYCAgAURkFblAAaAgIABAgAAABRidHJ0AAAAAAAB9AAAAfQAAAAAEHN0dHMAAAAAAAAAAAAAABBzdHNjAAAAAAAAAAAAAAAUc3RzegAAAAAAAAAAAAAAAAAAABBzdGNvAAAAAAAAAAAAAAATdWR0YQAAAAtuYW1lUlVTAAAAKG12ZXgAAAAgdHJleAAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNjIuMTIuMTAyAAAAcG1vb2YAAAAQbWZoZAAAAAAAAAABAAAAWHRyYWYAAAAcdGZoZAACADgAAAABAAAEAAAAAU8CAAAAAAAAFHRmZHQBAAAAAAAAAAAAAAAAAAAgdHJ1bgAAAgEAAAADAAAAeAAAAU8AAAFZAAABag==",
|
|
8
|
+
"segment-00014.mp4": "AAADAG1vb3YAAABsbXZoZAAAAAAAAAAAAAAAAAAAA+gAAAAAAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAICdHJhawAAAFx0a2hkAAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAMGVkdHMAAAAoZWxzdAAAAAAAAAACAAE91f////8AAQAAAAAAAAAAAAAAAQAAAAABW21kaWEAAAAgbWRoZAAAAAAAAAAAAAAAAAAAu4AAAAAAVcQAAAAAAC1oZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU291bmRIYW5kbGVyAAAAAQZtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAMpzdGJsAAAAfnN0c2QAAAAAAAAAAQAAAG5tcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAAu4AAAAAAADZlc2RzAAAAAAOAgIAlAAEABICAgBdAFQAAAAAB9AAAAfQABYCAgAURkFblAAaAgIABAgAAABRidHJ0AAAAAAAB9AAAAfQAAAAAEHN0dHMAAAAAAAAAAAAAABBzdHNjAAAAAAAAAAAAAAAUc3RzegAAAAAAAAAAAAAAAAAAABBzdGNvAAAAAAAAAAAAAAATdWR0YQAAAAtuYW1lUlVTAAAAKG12ZXgAAAAgdHJleAAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNjIuMTIuMTAyAAAICG1vb2YAAAAQbWZoZAAAAAAAAAABAAAH8HRyYWYAAAAcdGZoZAACADgAAAABAAAEAAAAAVUCAAAAAAAAFHRmZHQBAAAAAAAAAAAAAAAAAAe4dHJ1bgAAAgEAAAHpAAAIEAAAAVUAAAFWAAABVwAAAVsAAAFYAAABYwAAAWEAAAFfAAABXwAAAWAAAAFOAAABSwAAAVsAAAFlAAABWgAAAVMAAAFJAAABXgAAAWMAAAFdAAABWQAAAUsAAAFKAAABTwAAAVkAAAFWAAABXgAAAVQAAAFIAAABWQAAAWQAAAFZAAABYQAAAVMAAAFbAAABSAAAAPUAAAFgAAABRgAAATQAAAFlAAABgQAAAa4AAAGyAAABwwAAAScAAAEpAAABQgAAAS8AAAFXAAABbwAAAVAAAAFOAAABUQAAAWEAAAF0AAABWQAAAUUAAAFMAAABWgAAAVEAAAFXAAABWgAAAUoAAAF2AAABPQAAAWAAAAFtAAABOAAAAXQAAAEwAAABWwAAAWIAAAFEAAABVwAAAX4AAAEoAAABKQAAAY4AAAFnAAABQgAAAaIAAAGjAAABRgAAAVUAAAEmAAABRwAAAVgAAAE2AAABdgAAAWgAAAFUAAABOgAAAWUAAAFgAAABRgAAAXwAAAFZAAABYgAAAUUAAAFSAAABPQAAAV8AAAFlAAABXQAAAWkAAAFUAAABMAAAATgAAAGAAAABUAAAAWIAAAFZAAABUQAAAW0AAAFiAAABPwAAAVQAAAFVAAABLwAAAY0AAAFAAAABMAAAAW4AAAFeAAABYAAAAVwAAAFeAAABewAAAVQAAAIGAAABHQAAASkAAAFJAAABXAAAAWwAAAJfAAABUgAAAUEAAAFSAAABagAAAW0AAAF0AAABXwAAAWIAAAFOAAABagAAAUQAAAFyAAABeQAAAT0AAAFBAAABZwAAAWgAAAFHAAABIQAAAU0AAAFpAAABZwAAAWEAAAFgAAABHwAAAWwAAAGNAAABYQAAAUIAAAF5AAABcwAAAZQAAAFkAAABSgAAASYAAAFtAAABaAAAAWgAAAFMAAABgwAAApMAAAEsAAABVwAAAV4AAAK7AAAB1wAAASsAAAEoAAABQwAAAWMAAAFgAAABfwAAAaQAAAEiAAABPAAAAVoAAAFcAAABfgAAAWcAAAFmAAABcgAAAWEAAAFhAAABtQAAAYwAAAG4AAABXAAAASAAAAEuAAABUAAAAUYAAAEeAAABgQAAAVEAAAFyAAABgwAAAYMAAAFJAAABHAAAAW4AAAF3AAABZwAAAVIAAAFTAAACAgAAAScAAAEnAAABXAAAATgAAAFKAAABVwAAAUkAAAFgAAABVwAAAXQAAAEsAAABQgAAAdoAAAH2AAAB9AAAAYYAAAEjAAABKAAAASEAAAGGAAABMAAAAWgAAAFLAAABiQAAATEAAAEqAAACMAAAAXoAAAHSAAABigAAASkAAAFdAAABGwAAAWcAAAFvAAABbQAAAXwAAAGJAAABIwAAAYcAAAFxAAABQgAAAV8AAAGGAAABbwAAAYIAAAFlAAABYAAAAYQAAAINAAABJgAAAUQAAAFDAAABLwAAAVgAAAFuAAABXQAAAXsAAAFJAAABKgAAAX8AAAF6AAABTwAAAWAAAAFjAAABfgAAAYAAAAFxAAABdgAAAWsAAAFpAAABbAAAAWQAAAFbAAABZwAAAWsAAAFPAAAB5gAAAgEAAAF8AAABJQAAASsAAAFHAAABNQAAATIAAAE3AAABQQAAAUYAAAFfAAABbwAAAXsAAAE8AAABQgAAAYkAAAHoAAABzgAAAWYAAAE0AAABQQAAAWAAAAJjAAABHwAAAVEAAAFBAAABQAAAAWIAAAFKAAABTgAAAbIAAAHtAAABgAAAASAAAAHoAAABMwAAAT0AAAFVAAABPQAAAXIAAAFTAAABVgAAAUgAAAF2AAABXwAAAWoAAAFpAAABWgAAAV4AAAFtAAABRAAAAYcAAAFvAAABJgAAAXcAAAGAAAABTAAAAVYAAAFMAAABdgAAAV8AAAFmAAABgQAAAYYAAAFDAAABbgAAAUAAAAFyAAABYAAAAXMAAAFmAAABXAAAAUgAAAGHAAABXwAAAW0AAAGIAAABSwAAAWoAAANPAAACNwAAAcQAAAGWAAABHQAAASkAAAFHAAABYgAAAXIAAAFJAAABWgAAAX0AAAFsAAABagAAAWwAAAFtAAABcwAAAW8AAAF3AAABYwAAAW4AAAFcAAABYgAAAVkAAAFQAAABcQAAAVsAAAFrAAABZwAAAV0AAAFkAAABWQAAAUcAAAFbAAABVAAAAWQAAAFPAAABVwAAAVoAAAFfAAABYgAAAVAAAAFVAAABQgAAAVwAAAFbAAABXgAAAV4AAAFQAAABUwAAAVoAAAFgAAABWwAAAVkAAAFXAAABJgAAAR4AAAFXAAABZAAAATIAAAFUAAABbAAAAWIAAAE8AAABYwAAAUEAAAFJAAABTwAAAYEAAAFdAAACigAAAaEAAAHQAAABKQAAAVAAAAFaAAABRwAAAXAAAAFfAAABZgAAAWQAAAGyAAABIgAAASQAAAFBAAABIAAAAVUAAAGCAAABSAAAAV0AAAFbAAACGgAAAZoAAAErAAABOwAAAVMAAAFhAAABYQAAAVAAAAFRAAABTgAAATgAAAFuAAABWQAAAr8AAAKTAAABPwAAAWEAAAFRAAABQw=="
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -67,7 +67,8 @@ test("a shared init preserves presentation times without adding composition dela
|
|
|
67
67
|
const prepared = fmp4Format.prepareSegmentBytes(media, {
|
|
68
68
|
startSeconds: 4.125, initBytes: shared, rawBytes: raw
|
|
69
69
|
});
|
|
70
|
-
assert.deepEqual(readPresentationRanges(Buffer.concat([shared, prepared])),
|
|
70
|
+
assert.deepEqual(fmp4Format.servedMediaRanges(readPresentationRanges(Buffer.concat([shared, prepared])), { initBytes: null }),
|
|
71
|
+
fmp4Format.servedMediaRanges(readPresentationRanges(raw), { initBytes: null }));
|
|
71
72
|
const times = [];
|
|
72
73
|
walkBoxes(prepared, (type, start) => {
|
|
73
74
|
if (type === "tfdt") times.push(Number(prepared.readBigUInt64BE(start + 4)));
|
|
@@ -88,7 +89,8 @@ test("a shared init first read after a seek also supports returning to the begin
|
|
|
88
89
|
const prepared = fmp4Format.prepareSegmentBytes(media, {
|
|
89
90
|
startSeconds: 0.083, initBytes: shared, rawBytes: raw
|
|
90
91
|
});
|
|
91
|
-
assert.deepEqual(readPresentationRanges(Buffer.concat([shared, prepared])),
|
|
92
|
+
assert.deepEqual(fmp4Format.servedMediaRanges(readPresentationRanges(Buffer.concat([shared, prepared])), { initBytes: null }),
|
|
93
|
+
fmp4Format.servedMediaRanges(readPresentationRanges(raw), { initBytes: null }));
|
|
92
94
|
});
|
|
93
95
|
|
|
94
96
|
test("HLS fragments use the separate init and the same timeline translation as serving", (t) => {
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file An output is named by the format it produces, and nothing may put
|
|
3
|
-
* pieces of another format under that name.
|
|
4
|
-
*
|
|
5
|
-
* Two ways that could still happen once the name became the format: a
|
|
6
|
-
* directory left by an earlier version, whose key named the box a viewer asked
|
|
7
|
-
* for and so cannot say what format is inside; and a hardware encoder failing,
|
|
8
|
-
* after which the proxy encodes with software while outputs named by the failed
|
|
9
|
-
* encoder are still being watched.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import test from "node:test";
|
|
13
|
-
import assert from "node:assert/strict";
|
|
14
|
-
import { existsSync, writeFileSync } from "node:fs";
|
|
15
|
-
import path from "node:path";
|
|
16
|
-
import { managerWithOwnStore } from "./helpers/manager.js";
|
|
17
|
-
import { outputSpec } from "./helpers/output-spec.js";
|
|
18
|
-
import { ENCODE_EXIT } from "../services/encode/encode-exit.js";
|
|
19
|
-
import { SourceFile } from "../services/media/SourceFile.js";
|
|
20
|
-
|
|
21
|
-
test("a directory whose key names an asked-for box is not adopted, and one naming a format is", (t) => {
|
|
22
|
-
const { store, root, manager, cleanup } = managerWithOwnStore();
|
|
23
|
-
t.after(cleanup);
|
|
24
|
-
const oldKey = "torrent:abc:fmt=fmp4:grid=even@0:video-only:v=0/enc:1280x720:budget";
|
|
25
|
-
const newKey = outputSpec({ sourceKey: "torrent:abc", transcodeVideo: true, width: 1280, height: 720, audioSeparate: true }).toKey();
|
|
26
|
-
const oldDir = store.directoryFor(oldKey);
|
|
27
|
-
const newDir = store.directoryFor(newKey);
|
|
28
|
-
writeFileSync(path.join(oldDir, "segment-00000.mp4"), Buffer.alloc(10));
|
|
29
|
-
writeFileSync(path.join(newDir, "segment-00000.mp4"), Buffer.alloc(10));
|
|
30
|
-
|
|
31
|
-
const result = manager.lifecycle.adoptSegmentsLeftBehind();
|
|
32
|
-
|
|
33
|
-
assert.equal(result.adopted, 1);
|
|
34
|
-
assert.equal(result.dropped, 1);
|
|
35
|
-
assert.equal(existsSync(oldDir), false, "the old directory goes");
|
|
36
|
-
assert.equal(existsSync(newDir), true, "the named format stays");
|
|
37
|
-
assert.ok(root);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("when a hardware encoder fails, the outputs it named are closed rather than continued by software", async (t) => {
|
|
41
|
-
const { manager, cleanup } = managerWithOwnStore({
|
|
42
|
-
videoEncoder: { kind: "vaapi", name: "h264_vaapi", inputArgs: [] }
|
|
43
|
-
});
|
|
44
|
-
t.after(async () => {
|
|
45
|
-
await manager.lifecycle.disposeAll();
|
|
46
|
-
cleanup();
|
|
47
|
-
});
|
|
48
|
-
manager.encodeRuns.planEncodersNow = () => {};
|
|
49
|
-
manager.encodeRuns.planEncodersSoon = () => {};
|
|
50
|
-
const file = new SourceFile({ sourceKey: "torrent:abc", fileIndex: 0, name: "film.mkv" });
|
|
51
|
-
const record = (id, encoder) => {
|
|
52
|
-
const spec = outputSpec({ sourceKey: "torrent:abc", transcodeVideo: true, width: 1280, height: 720, encoder });
|
|
53
|
-
const output = { id, spec, get outputKey() { return this.spec.toKey(); }, file };
|
|
54
|
-
manager.outputs.set(id, output);
|
|
55
|
-
return output;
|
|
56
|
-
};
|
|
57
|
-
const failing = record("aaaaaaaa00000001", "h264_vaapi");
|
|
58
|
-
const software = record("aaaaaaaa00000002", "libx264");
|
|
59
|
-
const run = { from: 0, to: -1, argsDescribed: "ffmpeg …" };
|
|
60
|
-
manager.encodeOrchestrator.adopt(failing.outputKey, run);
|
|
61
|
-
|
|
62
|
-
manager.encodeRuns.noteRunEnded(failing, run, {
|
|
63
|
-
address: failing.outputKey,
|
|
64
|
-
run,
|
|
65
|
-
ending: ENCODE_EXIT.FAILED,
|
|
66
|
-
from: 0,
|
|
67
|
-
to: -1,
|
|
68
|
-
livedMs: 30_000,
|
|
69
|
-
because: "vaapi failed",
|
|
70
|
-
lastError: "vaapi failed",
|
|
71
|
-
producedCount: 3
|
|
72
|
-
});
|
|
73
|
-
await new Promise((resolve) => setImmediate(resolve));
|
|
74
|
-
|
|
75
|
-
assert.equal(manager.encoders.current.kind, "software");
|
|
76
|
-
assert.equal(manager.outputs.has(failing.id), false, "an output of the failed encoder is closed");
|
|
77
|
-
assert.equal(manager.outputs.has(software.id), true, "an output of another encoder is untouched");
|
|
78
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file An output is named by the format it produces, and nothing may put
|
|
3
|
+
* pieces of another format under that name.
|
|
4
|
+
*
|
|
5
|
+
* Two ways that could still happen once the name became the format: a
|
|
6
|
+
* directory left by an earlier version, whose key named the box a viewer asked
|
|
7
|
+
* for and so cannot say what format is inside; and a hardware encoder failing,
|
|
8
|
+
* after which the proxy encodes with software while outputs named by the failed
|
|
9
|
+
* encoder are still being watched.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import test from "node:test";
|
|
13
|
+
import assert from "node:assert/strict";
|
|
14
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { managerWithOwnStore } from "./helpers/manager.js";
|
|
17
|
+
import { outputSpec } from "./helpers/output-spec.js";
|
|
18
|
+
import { ENCODE_EXIT } from "../services/encode/encode-exit.js";
|
|
19
|
+
import { SourceFile } from "../services/media/SourceFile.js";
|
|
20
|
+
|
|
21
|
+
test("a directory whose key names an asked-for box is not adopted, and one naming a format is", (t) => {
|
|
22
|
+
const { store, root, manager, cleanup } = managerWithOwnStore();
|
|
23
|
+
t.after(cleanup);
|
|
24
|
+
const oldKey = "torrent:abc:fmt=fmp4:grid=even@0:video-only:v=0/enc:1280x720:budget";
|
|
25
|
+
const newKey = outputSpec({ sourceKey: "torrent:abc", transcodeVideo: true, width: 1280, height: 720, audioSeparate: true }).toKey();
|
|
26
|
+
const oldDir = store.directoryFor(oldKey);
|
|
27
|
+
const newDir = store.directoryFor(newKey);
|
|
28
|
+
writeFileSync(path.join(oldDir, "segment-00000.mp4"), Buffer.alloc(10));
|
|
29
|
+
writeFileSync(path.join(newDir, "segment-00000.mp4"), Buffer.alloc(10));
|
|
30
|
+
|
|
31
|
+
const result = manager.lifecycle.adoptSegmentsLeftBehind();
|
|
32
|
+
|
|
33
|
+
assert.equal(result.adopted, 1);
|
|
34
|
+
assert.equal(result.dropped, 1);
|
|
35
|
+
assert.equal(existsSync(oldDir), false, "the old directory goes");
|
|
36
|
+
assert.equal(existsSync(newDir), true, "the named format stays");
|
|
37
|
+
assert.ok(root);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("when a hardware encoder fails, the outputs it named are closed rather than continued by software", async (t) => {
|
|
41
|
+
const { manager, cleanup } = managerWithOwnStore({
|
|
42
|
+
videoEncoder: { kind: "vaapi", name: "h264_vaapi", inputArgs: [] }
|
|
43
|
+
});
|
|
44
|
+
t.after(async () => {
|
|
45
|
+
await manager.lifecycle.disposeAll();
|
|
46
|
+
cleanup();
|
|
47
|
+
});
|
|
48
|
+
manager.encodeRuns.planEncodersNow = () => {};
|
|
49
|
+
manager.encodeRuns.planEncodersSoon = () => {};
|
|
50
|
+
const file = new SourceFile({ sourceKey: "torrent:abc", fileIndex: 0, name: "film.mkv" });
|
|
51
|
+
const record = (id, encoder) => {
|
|
52
|
+
const spec = outputSpec({ sourceKey: "torrent:abc", transcodeVideo: true, width: 1280, height: 720, encoder });
|
|
53
|
+
const output = { id, spec, get outputKey() { return this.spec.toKey(); }, file };
|
|
54
|
+
manager.outputs.set(id, output);
|
|
55
|
+
return output;
|
|
56
|
+
};
|
|
57
|
+
const failing = record("aaaaaaaa00000001", "h264_vaapi");
|
|
58
|
+
const software = record("aaaaaaaa00000002", "libx264");
|
|
59
|
+
const run = { from: 0, to: -1, argsDescribed: "ffmpeg …" };
|
|
60
|
+
manager.encodeOrchestrator.adopt(failing.outputKey, run);
|
|
61
|
+
|
|
62
|
+
manager.encodeRuns.noteRunEnded(failing, run, {
|
|
63
|
+
address: failing.outputKey,
|
|
64
|
+
run,
|
|
65
|
+
ending: ENCODE_EXIT.FAILED,
|
|
66
|
+
from: 0,
|
|
67
|
+
to: -1,
|
|
68
|
+
livedMs: 30_000,
|
|
69
|
+
because: "vaapi failed",
|
|
70
|
+
lastError: "vaapi failed",
|
|
71
|
+
producedCount: 3
|
|
72
|
+
});
|
|
73
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
74
|
+
|
|
75
|
+
assert.equal(manager.encoders.current.kind, "software");
|
|
76
|
+
assert.equal(manager.outputs.has(failing.id), false, "an output of the failed encoder is closed");
|
|
77
|
+
assert.equal(manager.outputs.has(software.id), true, "an output of another encoder is untouched");
|
|
78
|
+
});
|
|
@@ -7,23 +7,21 @@ import assert from "node:assert/strict";
|
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
|
|
9
9
|
import { collectHealthMetrics } from "../services/transport/health-collector.js";
|
|
10
|
-
import { availableMemoryBytes } from "../services/storage/machine-memory.js";
|
|
10
|
+
import { availableMemory, availableMemoryBytes } from "../services/storage/machine-memory.js";
|
|
11
11
|
|
|
12
12
|
test("free memory is what could be given out, not what is idle this instant", () => {
|
|
13
|
-
const available =
|
|
14
|
-
assert.ok(Number.isFinite(available) && available > 0);
|
|
13
|
+
const available = availableMemory();
|
|
14
|
+
assert.ok(Number.isFinite(available.bytes) && available.bytes > 0);
|
|
15
15
|
|
|
16
|
-
// On Linux this
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
16
|
+
// On Linux this is the kernel's own `MemAvailable`, not `os.freemem()`: the
|
|
17
|
+
// kernel keeps free memory low on purpose and fills the rest with cache, which
|
|
18
|
+
// it hands back the moment anything asks. The old reading was `os.freemem()`,
|
|
19
|
+
// so a host with 4 GB of cache and 200 MB genuinely free reported itself nearly
|
|
20
|
+
// full while it had 4.2 GB to give — and that figure weighs 0.4 of every
|
|
21
|
+
// proxy's score. Asked of the reading itself: comparing it with a second
|
|
22
|
+
// reading taken a moment later measures whatever else the machine was doing.
|
|
22
23
|
if (os.platform() === "linux") {
|
|
23
|
-
assert.
|
|
24
|
-
available >= os.freemem(),
|
|
25
|
-
`MemAvailable ${available} is below freemem ${os.freemem()}, which cannot be`
|
|
26
|
-
);
|
|
24
|
+
assert.equal(available.measured, true, "the kernel's own estimate was not read");
|
|
27
25
|
}
|
|
28
26
|
});
|
|
29
27
|
|