@torrent-tv/proxy 2.89.17 → 2.89.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.
Files changed (300) hide show
  1. package/README.md +14 -3
  2. package/package.json +10 -2
  3. package/server.js +0 -11
  4. package/utils/client-log-file.js +147 -42
  5. package/.claude/commands/opsx/apply.md +0 -155
  6. package/.claude/commands/opsx/archive.md +0 -160
  7. package/.claude/commands/opsx/explore.md +0 -174
  8. package/.claude/commands/opsx/propose.md +0 -109
  9. package/.claude/commands/opsx/sync.md +0 -143
  10. package/.claude/skills/openspec-apply-change/SKILL.md +0 -159
  11. package/.claude/skills/openspec-archive-change/SKILL.md +0 -117
  12. package/.claude/skills/openspec-explore/SKILL.md +0 -289
  13. package/.claude/skills/openspec-propose/SKILL.md +0 -113
  14. package/.claude/skills/openspec-sync-specs/SKILL.md +0 -147
  15. package/.dockerignore +0 -5
  16. package/AGENTS.md +0 -363
  17. package/CHANGELOG.md +0 -2377
  18. package/Dockerfile +0 -30
  19. package/biome.json +0 -412
  20. package/corpus.tmp.json +0 -1
  21. package/docs/browser-proxy-contract.md +0 -155
  22. package/docs/container-architecture.md +0 -273
  23. package/docs/download-architecture.md +0 -261
  24. package/docs/encode-architecture.md +0 -765
  25. package/docs/encode-run-state.md +0 -96
  26. package/docs/logs.md +0 -151
  27. package/docs/playback-start-forecast.md +0 -113
  28. package/docs/socks5-egress-research.md +0 -114
  29. package/docs/storage-architecture.md +0 -273
  30. package/knip.json +0 -14
  31. package/main2.cpuprofile +0 -1
  32. package/openspec/changes/adaptive-bitrate/.openspec.yaml +0 -0
  33. package/openspec/changes/adaptive-bitrate/design.md +0 -92
  34. package/openspec/changes/adaptive-bitrate/proposal.md +0 -56
  35. package/openspec/changes/adaptive-bitrate/specs/adaptive-bitrate/spec.md +0 -51
  36. package/openspec/changes/adaptive-bitrate/tasks.md +0 -40
  37. package/openspec/changes/binary-distribution/.openspec.yaml +0 -2
  38. package/openspec/changes/binary-distribution/proposal.md +0 -53
  39. package/openspec/changes/chunked-request-bodies/design.md +0 -81
  40. package/openspec/changes/chunked-request-bodies/proposal.md +0 -53
  41. package/openspec/changes/chunked-request-bodies/specs/chunked-request-bodies/spec.md +0 -30
  42. package/openspec/changes/chunked-request-bodies/tasks.md +0 -40
  43. package/openspec/changes/cold-start/design.md +0 -98
  44. package/openspec/changes/cold-start/proposal.md +0 -62
  45. package/openspec/changes/cold-start/specs/cold-start/spec.md +0 -47
  46. package/openspec/changes/cold-start/tasks.md +0 -48
  47. package/openspec/changes/disk-cap/.openspec.yaml +0 -2
  48. package/openspec/changes/disk-cap/proposal.md +0 -37
  49. package/openspec/changes/disk-cap/specs/disk-cap/spec.md +0 -25
  50. package/openspec/changes/disk-cap/tasks.md +0 -19
  51. package/openspec/changes/proxy-observability/.openspec.yaml +0 -2
  52. package/openspec/changes/proxy-observability/design.md +0 -38
  53. package/openspec/changes/proxy-observability/proposal.md +0 -49
  54. package/openspec/changes/proxy-observability/specs/observability/spec.md +0 -33
  55. package/openspec/changes/proxy-observability/tasks.md +0 -21
  56. package/openspec/changes/seek-debounce/.openspec.yaml +0 -0
  57. package/openspec/changes/seek-debounce/design.md +0 -118
  58. package/openspec/changes/seek-debounce/proposal.md +0 -59
  59. package/openspec/changes/seek-debounce/specs/seek-debounce/spec.md +0 -41
  60. package/openspec/changes/seek-debounce/tasks.md +0 -33
  61. package/openspec/changes/subtitle-language/.openspec.yaml +0 -2
  62. package/openspec/changes/subtitle-language/proposal.md +0 -50
  63. package/openspec/changes/subtitle-language/specs/subtitle-language/spec.md +0 -34
  64. package/openspec/changes/subtitle-language/tasks.md +0 -26
  65. package/openspec/changes/track-selection/.openspec.yaml +0 -2
  66. package/openspec/changes/track-selection/design.md +0 -47
  67. package/openspec/changes/track-selection/proposal.md +0 -45
  68. package/openspec/changes/track-selection/specs/track-selection/spec.md +0 -41
  69. package/openspec/changes/track-selection/tasks.md +0 -20
  70. package/openspec/changes/transcode-quality/.openspec.yaml +0 -2
  71. package/openspec/changes/transcode-quality/proposal.md +0 -51
  72. package/openspec/changes/transcode-quality/specs/transcode-quality/spec.md +0 -139
  73. package/openspec/changes/transcode-quality/tasks.md +0 -63
  74. package/openspec/config.yaml +0 -38
  75. package/public/.well-known/appspecific/com.chrome.devtools.json +0 -1
  76. package/research/delivery-wedge-stand-ladder-2026-09-13.md +0 -329
  77. package/research/double-spawn-2026-09-10.md +0 -171
  78. package/research/handover-2026-09-13.md +0 -209
  79. package/research/handover-reader-claims-removal-2026-09-12.md +0 -166
  80. package/research/piece-withdrawn-but-still-claimed-2026-09-12.md +0 -175
  81. package/research/preset-benchmark-size-scaling-2026-08-22.md +0 -55
  82. package/research/priority-map-is-the-truth-2026-09-12.md +0 -225
  83. package/research/valgrind-replica-2026-08-27/logs.tar.gz +0 -0
  84. package/scripts/build-audio-samples.mjs +0 -31
  85. package/scripts/render-run-graph.js +0 -173
  86. package/test/asset-paths.test.js +0 -28
  87. package/test/audio-buffer-continuity.test.js +0 -77
  88. package/test/audio-calibration.test.js +0 -23
  89. package/test/audio-inventory.test.js +0 -212
  90. package/test/audio-track-bitrate.test.js +0 -40
  91. package/test/audio-warm-recorded.test.js +0 -63
  92. package/test/auto-quality-step.test.js +0 -762
  93. package/test/available-share.test.js +0 -76
  94. package/test/background-fill.test.js +0 -190
  95. package/test/client-log-file.test.js +0 -126
  96. package/test/client-logs-route.test.js +0 -34
  97. package/test/coalesce.test.js +0 -39
  98. package/test/completed-files.test.js +0 -115
  99. package/test/concurrent-cost.test.js +0 -148
  100. package/test/container-media-info.test.js +0 -228
  101. package/test/contention.test.js +0 -76
  102. package/test/core-dumps.test.js +0 -57
  103. package/test/coverage-follows-the-disk.test.js +0 -233
  104. package/test/coverage-map.test.js +0 -195
  105. package/test/cue-push-carries-what-the-walk-found.test.js +0 -58
  106. package/test/cut-times-timeline.test.js +0 -65
  107. package/test/cuts-follow-published-grid.test.js +0 -109
  108. package/test/data-channel-frame.test.js +0 -63
  109. package/test/data-channel-viewer-lifecycle.test.js +0 -193
  110. package/test/dead-torrent-handle.test.js +0 -52
  111. package/test/declared-rates.test.js +0 -116
  112. package/test/declared-tracks.test.js +0 -43
  113. package/test/decode-cost-fit.test.js +0 -202
  114. package/test/decode-cost.test.js +0 -475
  115. package/test/delivery-probe-field.test.js +0 -173
  116. package/test/delivery-probe.test.js +0 -382
  117. package/test/demand-register.test.js +0 -206
  118. package/test/dht-bootstrap.test.js +0 -72
  119. package/test/drain-threat.test.js +0 -65
  120. package/test/duplicate-add.test.js +0 -48
  121. package/test/encode-admission.test.js +0 -170
  122. package/test/encode-cost.test.js +0 -275
  123. package/test/encode-exit.test.js +0 -111
  124. package/test/encode-orchestrator.test.js +0 -426
  125. package/test/encode-plan-viewers.test.js +0 -725
  126. package/test/encode-plan.test.js +0 -545
  127. package/test/encode-run-state.test.js +0 -314
  128. package/test/encode-run.test.js +0 -248
  129. package/test/encode-slope.test.js +0 -46
  130. package/test/encoded-output.test.js +0 -39
  131. package/test/encoder-kinds.test.js +0 -122
  132. package/test/encoder-readings.test.js +0 -68
  133. package/test/episode-naming.test.js +0 -131
  134. package/test/every-claimant-is-told-its-share.test.js +0 -152
  135. package/test/failed-encoder-still-serves-what-exists.test.js +0 -354
  136. package/test/failed-start-breaker.test.js +0 -202
  137. package/test/fastest-wires.test.js +0 -143
  138. package/test/ffmpeg-stream-counts.test.js +0 -101
  139. package/test/file-edges.test.js +0 -191
  140. package/test/files-in-use.test.js +0 -34
  141. package/test/fixtures/audio-frame-boundary.json +0 -1
  142. package/test/fixtures/refused-audio-20261002.json +0 -10
  143. package/test/fmp4-presentation-clock.test.js +0 -148
  144. package/test/fmp4-self-contained.test.js +0 -80
  145. package/test/fmp4-timestamps.test.js +0 -140
  146. package/test/fmp4-track-completeness.test.js +0 -41
  147. package/test/format-keyed-outputs.test.js +0 -78
  148. package/test/health-metrics.test.js +0 -36
  149. package/test/held-read-ownership.test.js +0 -77
  150. package/test/held-request-width.test.js +0 -157
  151. package/test/helpers/encode-run.js +0 -248
  152. package/test/helpers/held-file.js +0 -77
  153. package/test/helpers/manager.js +0 -62
  154. package/test/helpers/matroska-file.js +0 -296
  155. package/test/helpers/output-spec.js +0 -63
  156. package/test/host-load.test.js +0 -68
  157. package/test/index-accuracy-is-about-the-file.test.js +0 -128
  158. package/test/init-compat.test.js +0 -219
  159. package/test/input-lost-quiets-the-plan.test.js +0 -261
  160. package/test/input-unavailable.test.js +0 -48
  161. package/test/installation-id.test.js +0 -39
  162. package/test/keeping-period.test.js +0 -83
  163. package/test/keyframe-index-accuracy.test.js +0 -188
  164. package/test/keyframe-table-budget.test.js +0 -123
  165. package/test/keyframes-belong-to-the-file.test.js +0 -249
  166. package/test/learned-median.test.js +0 -37
  167. package/test/letting-go-asks-who-is-watching.test.js +0 -191
  168. package/test/limit-row-by-area.test.js +0 -60
  169. package/test/link-budget.test.js +0 -111
  170. package/test/link-probe.test.js +0 -56
  171. package/test/local-encoding-data.test.js +0 -273
  172. package/test/logger-repeats.test.js +0 -134
  173. package/test/look-ahead-coverage.test.js +0 -56
  174. package/test/manager-surface.test.js +0 -291
  175. package/test/matroska-blocks.test.js +0 -0
  176. package/test/matroska-cluster-discovery.test.js +0 -323
  177. package/test/matroska-cues-track.test.js +0 -192
  178. package/test/media-time.test.js +0 -62
  179. package/test/memory-budget.test.js +0 -390
  180. package/test/move-cost.test.js +0 -216
  181. package/test/mp4-composition-times.test.js +0 -0
  182. package/test/mp4-subtitles.test.js +0 -173
  183. package/test/one-authority.test.js +0 -285
  184. package/test/one-budget.test.js +0 -149
  185. package/test/one-output-one-session.test.js +0 -273
  186. package/test/one-resource-divided.test.js +0 -185
  187. package/test/one-serving-output-per-height.test.js +0 -458
  188. package/test/orchestrator-wired.test.js +0 -207
  189. package/test/output-catalog.test.js +0 -39
  190. package/test/output-shape.test.js +0 -21
  191. package/test/output-spec.test.js +0 -251
  192. package/test/output-speed.test.js +0 -92
  193. package/test/outputs-being-prepared.test.js +0 -40
  194. package/test/packet-witness-ring.test.js +0 -236
  195. package/test/packet-witness.test.js +0 -148
  196. package/test/piece-completeness.test.js +0 -78
  197. package/test/piece-disk-store.test.js +0 -401
  198. package/test/piece-from-whole-file.test.js +0 -129
  199. package/test/piece-lru.test.js +0 -319
  200. package/test/piece-reader.test.js +0 -162
  201. package/test/piece-selection-offset.test.js +0 -85
  202. package/test/piece-store-eviction.test.js +0 -595
  203. package/test/piece-store-never-refuses.test.js +0 -153
  204. package/test/piece-store-reservations.test.js +0 -403
  205. package/test/piece-store-slow-disk.test.js +0 -159
  206. package/test/piece-tail.test.js +0 -97
  207. package/test/plan-host-timings.test.js +0 -68
  208. package/test/plan-is-steady.test.js +0 -225
  209. package/test/playback-readiness.test.js +0 -518
  210. package/test/playback-start-regressions.test.js +0 -101
  211. package/test/priority-map-download.test.js +0 -174
  212. package/test/priority-map-emptied.test.js +0 -204
  213. package/test/priority-map-per-output.test.js +0 -215
  214. package/test/priority-map.test.js +0 -163
  215. package/test/probe-wedge-certainty.test.js +0 -60
  216. package/test/produced-copy-choice.test.js +0 -213
  217. package/test/published-timeline.test.js +0 -83
  218. package/test/quality-offer.test.js +0 -160
  219. package/test/quality-variants.test.js +0 -1274
  220. package/test/rate-control-in-the-output.test.js +0 -181
  221. package/test/read-survives-withdrawal.test.js +0 -164
  222. package/test/read-window.test.js +0 -365
  223. package/test/reads-not-yet-arrived.test.js +0 -218
  224. package/test/resume-warm.test.js +0 -39
  225. package/test/run-graph-drift.test.js +0 -37
  226. package/test/run-inputs.test.js +0 -80
  227. package/test/run-intervals.test.js +0 -100
  228. package/test/run-position-follows-published-grid.test.js +0 -89
  229. package/test/run-progress.test.js +0 -64
  230. package/test/same-height-switch.test.js +0 -663
  231. package/test/seek-frees-the-viewers-requests.test.js +0 -217
  232. package/test/seek-landing.test.js +0 -109
  233. package/test/seek-target-not-superseded.test.js +0 -195
  234. package/test/segment-closed-on-both-branches.test.js +0 -114
  235. package/test/segment-cut-times.test.js +0 -63
  236. package/test/segment-demand.test.js +0 -80
  237. package/test/segment-hold-supersede.test.js +0 -91
  238. package/test/segment-judged-by-its-own-header.test.js +0 -222
  239. package/test/segment-serve-wiring.test.js +0 -481
  240. package/test/segment-store-eviction.test.js +0 -247
  241. package/test/segment-store.test.js +0 -352
  242. package/test/segment-true-start.test.js +0 -86
  243. package/test/segments-are-shared.test.js +0 -176
  244. package/test/send-chunk-bytes.test.js +0 -86
  245. package/test/serving-existing-output.test.js +0 -111
  246. package/test/serving-output.test.js +0 -102
  247. package/test/shared-piece-store.test.js +0 -310
  248. package/test/sidecar-naming.test.js +0 -142
  249. package/test/soundtrack-rate-bound.test.js +0 -289
  250. package/test/source-file.test.js +0 -133
  251. package/test/source-files-route.test.js +0 -113
  252. package/test/source-registry.test.js +0 -18
  253. package/test/split-a-stretch.test.js +0 -139
  254. package/test/stale-request-after-seek.test.js +0 -158
  255. package/test/startup-readings.test.js +0 -124
  256. package/test/stream-route.test.js +0 -237
  257. package/test/subtitle-cue-framing.test.js +0 -200
  258. package/test/subtitle-cue-source.test.js +0 -102
  259. package/test/subtitle-cue-walk.test.js +0 -385
  260. package/test/subtitle-cursor.test.js +0 -63
  261. package/test/subtitle-defaults.test.js +0 -118
  262. package/test/subtitle-language.test.js +0 -252
  263. package/test/subtitle-metadata.test.js +0 -15
  264. package/test/subtitle-plan-waits.test.js +0 -125
  265. package/test/subtitle-track-numbering.test.js +0 -391
  266. package/test/supply-margin.test.js +0 -190
  267. package/test/swarm-follows-readers.test.js +0 -174
  268. package/test/swarm-reach.test.js +0 -130
  269. package/test/swarm-selection.test.js +0 -220
  270. package/test/tail-duplication.test.js +0 -167
  271. package/test/the-channel-has-both-ends.test.js +0 -91
  272. package/test/the-torrent-thread-serves-bytes.test.js +0 -107
  273. package/test/thread-pool.test.js +0 -53
  274. package/test/timeline.test.js +0 -84
  275. package/test/torrent-contents.test.js +0 -235
  276. package/test/torrent-cost.test.js +0 -71
  277. package/test/torrent-files.test.js +0 -221
  278. package/test/torrent-naming.test.js +0 -255
  279. package/test/tracks-begin-together.test.js +0 -209
  280. package/test/tunnel-renewal.test.js +0 -167
  281. package/test/two-viewers-one-picture.test.js +0 -508
  282. package/test/upload-hurry.test.js +0 -186
  283. package/test/usrsctp-state.test.js +0 -131
  284. package/test/video-facts.test.js +0 -102
  285. package/test/viewer-assignments.test.js +0 -143
  286. package/test/viewer-outputs.test.js +0 -285
  287. package/test/viewer-presence.test.js +0 -116
  288. package/test/viewer-requests-admission.test.js +0 -92
  289. package/test/viewer-starts-on-map.test.js +0 -27
  290. package/test/viewer-states.test.js +0 -192
  291. package/test/viewer-subtitle-subscription.test.js +0 -96
  292. package/test/viewer.test.js +0 -139
  293. package/test/viewing-generations.test.js +0 -390
  294. package/test/visible-rung.test.js +0 -37
  295. package/test/wait-ledger.test.js +0 -100
  296. package/test/webrtc-shim.test.js +0 -149
  297. package/test/wedge-certainty.test.js +0 -131
  298. package/test/whole-file-held-read.test.js +0 -30
  299. package/test/withdraw-piece-claim.test.js +0 -212
  300. package/test/worker-channel.test.js +0 -158
@@ -1,212 +0,0 @@
1
- /**
2
- * @file One numbered list of soundtracks, from two readings of the same file.
3
- *
4
- * Two things are being pinned here, and each has cost a real failure elsewhere
5
- * in this project:
6
- *
7
- * 1. **The alignment guard.** The container reading is used ONLY when it can be
8
- * lined up with ffmpeg's own numbering, because `0:a:N` is what the encoder
9
- * is handed — a flag attributed to the wrong track is worse than a missing
10
- * one. Same discipline as `subtitle-defaults.js`, for the same reason.
11
- * 2. **The flat numbering.** The browser's menu, the `audioTrackIndex` on a
12
- * session request and the `a/<n>/` address of a rendition are one number.
13
- * Embedded tracks must keep the numbers they have always had, so that a
14
- * session created against an older cached plan means the same thing.
15
- */
16
-
17
- import test from "node:test";
18
- import { Container } from "../services/media/container/Container.js";
19
- import { AudioTrack } from "../services/media/tracks/AudioTrack.js";
20
- import assert from "node:assert/strict";
21
- import {
22
- audioRenditionName,
23
- buildAudioInventory,
24
- enrichAudioInventoryFromSidecar,
25
- resolveAudioIndex
26
- } from "../services/media/audio-inventory.js";
27
-
28
- test("a pair agreeing on language is accepted", () => {
29
- assert.equal(Container.pairingHolds({ language: "jpn" }, { language: "jpn" }), true);
30
- });
31
-
32
- test("a pair disagreeing on language is refused", () => {
33
- assert.equal(Container.pairingHolds({ language: "jpn" }, { language: "rus" }), false);
34
- });
35
-
36
- test("two tracks that say nothing about themselves do not break the alignment", () => {
37
- assert.equal(Container.pairingHolds({ language: "und", title: "" }, { language: "", name: "" }), true);
38
- });
39
-
40
- test("the container's own flags reach the merged track", () => {
41
- const merged = Container.mergeAudioFlags(
42
- [
43
- { index: 0, language: "eng", title: "", isDefault: true, codec: "aac" },
44
- { index: 1, language: "eng", title: "Director", isDefault: true, codec: "ac3" }
45
- ],
46
- [
47
- { language: "eng", name: "", isOriginal: true, isDefault: true, declaresDefault: true, channels: 6 },
48
- { language: "eng", name: "Director", isCommentary: true, isDefault: false, declaresDefault: true, channels: 2 }
49
- ]
50
- );
51
- assert.equal(merged.aligned, true);
52
- assert.equal(merged.tracks[0].isOriginal, true);
53
- assert.equal(merged.tracks[0].channels, 6);
54
- assert.equal(merged.tracks[1].isCommentary, true);
55
- // Matroska defaults FlagDefault to 1 and ffmpeg prints the applied default, so
56
- // the banner said both tracks were default. The container says otherwise.
57
- assert.equal(merged.tracks[1].isDefault, false);
58
- });
59
-
60
- test("a count that differs drops the container reading whole", () => {
61
- const merged = Container.mergeAudioFlags(
62
- [{ index: 0, language: "eng", isDefault: true }],
63
- [{ language: "eng" }, { language: "rus" }]
64
- );
65
- assert.equal(merged.aligned, false);
66
- assert.match(merged.reason, /declares 2 audio tracks and the probe found 1/);
67
- // Nothing of it is used — not even the flags that happened to line up.
68
- assert.equal(merged.tracks[0].isCommentary, false);
69
- assert.equal(merged.tracks[0].declaresDefault, false);
70
- });
71
-
72
- test("one pair that agrees on neither language nor title drops it too", () => {
73
- const merged = Container.mergeAudioFlags(
74
- [{ index: 0, language: "jpn", title: "" }, { index: 1, language: "rus", title: "" }],
75
- [{ language: "jpn", name: "" }, { language: "eng", name: "" }]
76
- );
77
- assert.equal(merged.aligned, false);
78
- assert.match(merged.reason, /audio 1 is/);
79
- });
80
-
81
- test("embedded tracks keep the numbers they have always had, sidecars follow", () => {
82
- const inventory = buildAudioInventory({
83
- embedded: [
84
- { language: "jpn", codec: "aac", isDefault: true },
85
- { language: "eng", codec: "ac3", title: "Commentary", isCommentary: true }
86
- ],
87
- videoFileIndex: 24,
88
- sidecars: [
89
- {
90
- file: { fileIndex: 12, name: "ep.mka", folders: ["Rus Sound"], extension: ".mka" },
91
- tracks: [{ language: "rus", codecId: "A_AC3", channels: 6 }]
92
- }
93
- ]
94
- });
95
-
96
- assert.deepEqual(inventory.map((entry) => entry.index), [0, 1, 2]);
97
- assert.deepEqual(inventory.map((entry) => entry.fileIndex), [24, 24, 12]);
98
- assert.deepEqual(inventory.map((entry) => entry.sourceTrackIndex), [0, 1, 0]);
99
- assert.deepEqual(inventory.map((entry) => entry.kind), ["embedded", "embedded", "sidecar"]);
100
- assert.equal(inventory[2].codec, "ac3");
101
- assert.deepEqual(inventory[2].folders, ["Rus Sound"]);
102
- assert.equal(inventory[2].fileName, "ep.mka");
103
- });
104
-
105
- test("late sidecar metadata enriches the existing entry without changing its address", () => {
106
- const file = { fileIndex: 12, name: "ep.mka", folders: ["Rus Sound"], extension: ".mka" };
107
- const inventory = buildAudioInventory({
108
- embedded: [{ language: "jpn", codec: "aac" }],
109
- videoFileIndex: 24,
110
- sidecars: [{ file, tracks: [] }]
111
- });
112
- const addresses = inventory.map(({ index, fileIndex, sourceTrackIndex, kind }) => ({
113
- index,
114
- fileIndex,
115
- sourceTrackIndex,
116
- kind
117
- }));
118
-
119
- assert.equal(enrichAudioInventoryFromSidecar(inventory, file, {
120
- language: "rus",
121
- languageBcp47: "ru",
122
- codecId: "A_AC3",
123
- channels: 6,
124
- isOriginal: true
125
- }), true);
126
-
127
- assert.deepEqual(inventory.map(({ index, fileIndex, sourceTrackIndex, kind }) => ({
128
- index,
129
- fileIndex,
130
- sourceTrackIndex,
131
- kind
132
- })), addresses);
133
- assert.equal(inventory.length, 2);
134
- assert.equal(inventory[1].codec, "ac3");
135
- assert.equal(inventory[1].languageBcp47, "ru");
136
- assert.equal(inventory[1].channels, 6);
137
- assert.equal(inventory[1].isOriginal, true);
138
- });
139
-
140
- test("a sidecar whose table could not be read is still offered, as one track", () => {
141
- const inventory = buildAudioInventory({
142
- embedded: [{ language: "eng", codec: "aac" }],
143
- videoFileIndex: 0,
144
- sidecars: [{ file: { fileIndex: 1, name: "dub.ac3", folders: [], extension: ".ac3" }, tracks: [] }]
145
- });
146
- assert.equal(inventory.length, 2);
147
- assert.equal(inventory[1].sourceTrackIndex, 0);
148
- // The extension of a bare elementary stream IS its codec.
149
- assert.equal(inventory[1].codec, "ac3");
150
- });
151
-
152
- test("a sidecar carrying two tracks contributes both", () => {
153
- const inventory = buildAudioInventory({
154
- embedded: [],
155
- videoFileIndex: 0,
156
- sidecars: [
157
- {
158
- file: { fileIndex: 3, name: "dubs.mka", folders: [], extension: ".mka" },
159
- tracks: [{ language: "rus" }, { language: "ukr" }]
160
- }
161
- ]
162
- });
163
- assert.deepEqual(inventory.map((entry) => [entry.index, entry.sourceTrackIndex]), [[0, 0], [1, 1]]);
164
- });
165
-
166
- test("the flat number resolves back to a file and a track inside it", () => {
167
- const inventory = buildAudioInventory({
168
- embedded: [{ language: "jpn" }],
169
- videoFileIndex: 24,
170
- sidecars: [{ file: { fileIndex: 12, name: "ep.mka", folders: [], extension: ".mka" }, tracks: [{}] }]
171
- });
172
- assert.equal(resolveAudioIndex(inventory, 1).fileIndex, 12);
173
- assert.equal(resolveAudioIndex(inventory, 1).sourceTrackIndex, 0);
174
- assert.equal(resolveAudioIndex(inventory, 9), null);
175
- });
176
-
177
- test("codec identifiers are translated to the names the browser judges by", () => {
178
- assert.equal(AudioTrack.codecNameOf({ codec: "AAC" }), "aac");
179
- assert.equal(AudioTrack.codecNameOf({ codecId: "A_AC3" }), "ac3");
180
- assert.equal(AudioTrack.codecNameOf({ codecId: "A_AAC/MPEG4/LC" }), "aac");
181
- assert.equal(AudioTrack.codecNameOf({ codecId: "A_PCM/INT/LIT" }), "pcm");
182
- assert.equal(AudioTrack.codecNameOf({ codecId: "ec-3" }), "eac3");
183
- assert.equal(AudioTrack.codecNameOf({}, ".dts"), "dts");
184
- assert.equal(AudioTrack.codecNameOf({}, ".unknown"), "");
185
- });
186
-
187
- test("a rendition is named by what the file says, and two never share a name", () => {
188
- const inventory = buildAudioInventory({
189
- embedded: [{ language: "jpn" }],
190
- videoFileIndex: 0,
191
- sidecars: [
192
- { file: { fileIndex: 1, name: "a.mka", folders: ["Rus Sound"], extension: ".mka" }, tracks: [{}] },
193
- { file: { fileIndex: 2, name: "b.mka", folders: ["Rus Sound"], extension: ".mka" }, tracks: [{}] }
194
- ]
195
- });
196
- assert.equal(audioRenditionName(inventory[0], inventory), "jpn");
197
- // Both sidecars sit in the same folder and neither names itself, so the names
198
- // would collide — and hls.js groups renditions by name.
199
- assert.notEqual(
200
- audioRenditionName(inventory[1], inventory),
201
- audioRenditionName(inventory[2], inventory)
202
- );
203
- });
204
-
205
- test("a commentary says so in its rendition name", () => {
206
- const inventory = buildAudioInventory({
207
- embedded: [{ language: "eng" }, { language: "eng", title: "Director", isCommentary: true }],
208
- videoFileIndex: 0,
209
- sidecars: []
210
- });
211
- assert.match(audioRenditionName(inventory[1], inventory), /commentary/);
212
- });
@@ -1,40 +0,0 @@
1
- /**
2
- * @file The rate a copied soundtrack puts on a viewer's link is the rate the
3
- * file states for THAT track — roadmap item 97, step 11.
4
- *
5
- * Not the first rate the banner prints and not the file's total: two tracks of
6
- * one film can differ fivefold (a stereo AAC and a 5.1 AC3), and the viewer
7
- * receives only the one they chose. Parsed text, no process.
8
- */
9
-
10
- import test from "node:test";
11
- import assert from "node:assert/strict";
12
- import { parseStreamCodecs } from "../services/media/playback-planner.js";
13
- import { buildAudioInventory } from "../services/media/audio-inventory.js";
14
-
15
- const BANNER = [
16
- "Input #0, matroska,webm, from 'http://127.0.0.1/stream':",
17
- " Duration: 01:30:00.00, start: 0.000000, bitrate: 9000 kb/s",
18
- " Stream #0:0: Video: h264 (High), yuv420p, 1920x1080, 24 fps (default)",
19
- " Stream #0:1(eng): Audio: aac (LC), 48000 Hz, stereo, fltp, 128 kb/s (default)",
20
- " Stream #0:2(rus): Audio: ac3, 48000 Hz, 5.1(side), fltp",
21
- " Metadata:",
22
- " title : Dub",
23
- " BPS : 640000",
24
- " Stream #0:3(fre): Audio: ac3, 48000 Hz, 5.1(side), fltp",
25
- "At least one output file must be specified"
26
- ].join("\n");
27
-
28
- test("each soundtrack carries its own stated rate, from its own line or its own statistics tag", () => {
29
- const { audioTracks } = parseStreamCodecs(BANNER);
30
-
31
- assert.deepEqual(audioTracks.map((track) => track.bitrateKbps), [128, 640, null]);
32
- assert.notEqual(audioTracks[1].bitrateKbps, 9000, "never the file's total");
33
- });
34
-
35
- test("the inventory keeps each track's rate, so the chosen one can be priced", () => {
36
- const { audioTracks } = parseStreamCodecs(BANNER);
37
- const inventory = buildAudioInventory({ embedded: audioTracks, videoFileIndex: 0, sidecars: [] });
38
-
39
- assert.deepEqual(inventory.map((entry) => entry.bitrateKbps), [128, 640, null]);
40
- });
@@ -1,63 +0,0 @@
1
- import test from "node:test";
2
- import assert from "node:assert/strict";
3
-
4
- import { handleTranscodeAudioWarmGet } from "../routes/transcode/audio-warm/get.js";
5
-
6
- // A page restating its soundtrack after a reconnect has to know whether the
7
- // proxy RECORDED it. Both answers below are 503; only one of them recorded.
8
-
9
- function reply() {
10
- return {
11
- statusCode: 0,
12
- payload: undefined,
13
- header() {
14
- return this;
15
- },
16
- code(status) {
17
- this.statusCode = status;
18
- return this;
19
- },
20
- send(payload) {
21
- this.payload = payload;
22
- return this;
23
- }
24
- };
25
- }
26
-
27
- const request = {
28
- params: { sessionId: "base", track: "0" },
29
- query: { position: "1641.2", consumer: "viewer-1", transcode: "1" }
30
- };
31
-
32
- test("a track still being made says it was recorded", async () => {
33
- let preparedFor = null;
34
- const answer = await handleTranscodeAudioWarmGet(request, reply(), {
35
- renditions: {
36
- prepareAudioTrack: async (...args) => {
37
- preparedFor = args;
38
- return { sessionId: "rendition", fileName: "segment-00268.mp4" };
39
- }
40
- },
41
- serving: {
42
- seekEpoch: () => 0,
43
- // Anything but a file or a failure is "not made yet".
44
- getFileStream: async () => ({ kind: "superseded" })
45
- }
46
- });
47
- assert.deepEqual(preparedFor, ["base", 0, 1641.2, "viewer-1", false]);
48
- assert.equal(answer.statusCode, 503);
49
- assert.equal(answer.payload.warming, true);
50
- });
51
-
52
- test("a preparation that failed says nothing was recorded", async () => {
53
- const answer = await handleTranscodeAudioWarmGet(request, reply(), {
54
- renditions: {
55
- prepareAudioTrack: async () => {
56
- throw new Error("no encoder");
57
- }
58
- },
59
- serving: {}
60
- });
61
- assert.equal(answer.statusCode, 503);
62
- assert.equal(answer.payload.warming, undefined);
63
- });