@torrent-tv/proxy 2.87.21 → 2.88.1
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/.claude/commands/opsx/apply.md +155 -155
- package/.claude/commands/opsx/archive.md +160 -160
- package/.claude/commands/opsx/explore.md +174 -174
- package/.claude/commands/opsx/propose.md +109 -109
- package/.claude/commands/opsx/sync.md +143 -143
- package/.claude/skills/openspec-apply-change/SKILL.md +159 -159
- package/.claude/skills/openspec-archive-change/SKILL.md +117 -117
- package/.claude/skills/openspec-explore/SKILL.md +289 -289
- package/.claude/skills/openspec-propose/SKILL.md +113 -113
- package/.claude/skills/openspec-sync-specs/SKILL.md +147 -147
- package/.dockerignore +5 -5
- package/AGENTS.md +322 -322
- package/CHANGELOG.md +2242 -2234
- package/Dockerfile +30 -30
- package/LICENSE +16 -16
- package/README.md +369 -369
- package/assets/calibration/NOTICE.md +100 -100
- package/assets/diagnostics/sctpstate.gdb +31 -31
- package/bin/cli.js +684 -684
- package/bin/thread-pool.js +30 -30
- package/biome.json +411 -411
- package/docs/browser-proxy-contract.md +1 -1
- package/docs/container-architecture.md +218 -218
- package/docs/download-architecture.md +261 -261
- package/docs/encode-architecture.md +729 -729
- package/docs/encode-run-state.md +96 -96
- package/docs/logs.md +97 -97
- package/docs/socks5-egress-research.md +114 -114
- package/docs/storage-architecture.md +267 -267
- package/knip.json +14 -14
- package/openspec/changes/adaptive-bitrate/design.md +92 -92
- package/openspec/changes/adaptive-bitrate/proposal.md +56 -56
- package/openspec/changes/adaptive-bitrate/specs/adaptive-bitrate/spec.md +51 -51
- package/openspec/changes/adaptive-bitrate/tasks.md +40 -40
- package/openspec/changes/binary-distribution/.openspec.yaml +2 -2
- package/openspec/changes/binary-distribution/proposal.md +53 -53
- package/openspec/changes/chunked-request-bodies/design.md +81 -81
- package/openspec/changes/chunked-request-bodies/proposal.md +53 -53
- package/openspec/changes/chunked-request-bodies/specs/chunked-request-bodies/spec.md +30 -30
- package/openspec/changes/chunked-request-bodies/tasks.md +40 -40
- package/openspec/changes/cold-start/design.md +98 -98
- package/openspec/changes/cold-start/proposal.md +62 -62
- package/openspec/changes/cold-start/specs/cold-start/spec.md +47 -47
- package/openspec/changes/cold-start/tasks.md +48 -48
- package/openspec/changes/disk-cap/.openspec.yaml +2 -2
- package/openspec/changes/disk-cap/proposal.md +37 -37
- package/openspec/changes/disk-cap/specs/disk-cap/spec.md +25 -25
- package/openspec/changes/disk-cap/tasks.md +19 -19
- package/openspec/changes/proxy-observability/.openspec.yaml +2 -2
- package/openspec/changes/proxy-observability/design.md +38 -38
- package/openspec/changes/proxy-observability/proposal.md +49 -49
- package/openspec/changes/proxy-observability/specs/observability/spec.md +33 -33
- package/openspec/changes/proxy-observability/tasks.md +21 -21
- package/openspec/changes/seek-debounce/design.md +118 -118
- package/openspec/changes/seek-debounce/proposal.md +59 -59
- package/openspec/changes/seek-debounce/specs/seek-debounce/spec.md +41 -41
- package/openspec/changes/seek-debounce/tasks.md +33 -33
- package/openspec/changes/subtitle-language/.openspec.yaml +2 -2
- package/openspec/changes/subtitle-language/proposal.md +50 -50
- package/openspec/changes/subtitle-language/specs/subtitle-language/spec.md +34 -34
- package/openspec/changes/subtitle-language/tasks.md +26 -26
- package/openspec/changes/track-selection/.openspec.yaml +2 -2
- package/openspec/changes/track-selection/design.md +47 -47
- package/openspec/changes/track-selection/proposal.md +45 -45
- package/openspec/changes/track-selection/specs/track-selection/spec.md +41 -41
- package/openspec/changes/track-selection/tasks.md +20 -20
- package/openspec/changes/transcode-quality/.openspec.yaml +2 -2
- package/openspec/changes/transcode-quality/proposal.md +51 -51
- package/openspec/changes/transcode-quality/specs/transcode-quality/spec.md +139 -139
- package/openspec/changes/transcode-quality/tasks.md +63 -63
- package/openspec/config.yaml +38 -38
- package/package.json +50 -50
- package/public/.well-known/appspecific/com.chrome.devtools.json +1 -1
- package/research/delivery-wedge-stand-ladder-2026-09-13.md +329 -329
- package/research/double-spawn-2026-09-10.md +171 -171
- package/research/handover-2026-09-13.md +209 -209
- package/research/handover-reader-claims-removal-2026-09-12.md +166 -166
- package/research/piece-withdrawn-but-still-claimed-2026-09-12.md +175 -175
- package/research/preset-benchmark-size-scaling-2026-08-22.md +55 -55
- package/research/priority-map-is-the-truth-2026-09-12.md +225 -225
- package/routes/api/client-logs/post.js +86 -86
- package/routes/api/delivery-sink/get.js +72 -72
- package/routes/api/link-probe/get.js +51 -51
- package/routes/api/playback-plan/audio-tracks/post.js +29 -29
- package/routes/api/playback-plan/post.js +53 -53
- package/routes/api/sources/files/get.js +106 -100
- package/routes/api/sources/post.js +36 -36
- package/routes/api/sources/stats/get.js +132 -132
- package/routes/api/sources/warm/post.js +217 -217
- package/routes/api/subtitles/get.js +230 -230
- package/routes/api/transcode-sessions/fragment-far/post.js +60 -60
- package/routes/api/transcode-sessions/net-report/post.js +138 -138
- package/routes/api/transcode-sessions/post.js +173 -173
- package/routes/api/transcode-sessions/progress/get.js +27 -27
- package/routes/api/transcode-sessions/release/post.js +41 -41
- package/routes/api/transcode-sessions/seek/post.js +63 -63
- package/routes/health/get.js +13 -13
- package/routes/healthz/get.js +13 -13
- package/routes/stream/get.js +380 -380
- package/routes/transcode/audio-file/get.js +64 -64
- package/routes/transcode/audio-warm/get.js +84 -84
- package/routes/transcode/session-file/get.js +52 -52
- package/routes/transcode/variant-file/get.js +95 -95
- package/routes/transcode/variant-warm/get.js +84 -84
- package/scripts/render-run-graph.js +173 -173
- package/server.js +725 -725
- package/services/encode/CoverageMap.js +428 -428
- package/services/encode/CushionReport.js +345 -345
- package/services/encode/EncodeAdmission.js +376 -376
- package/services/encode/EncodeOrchestrator.js +1217 -1217
- package/services/encode/EncodePlan.js +1366 -1366
- package/services/encode/EncodeRun.js +813 -813
- package/services/encode/EncodeRuns.js +1235 -1235
- package/services/encode/Encoder.js +142 -142
- package/services/encode/EncoderSelection.js +38 -38
- package/services/encode/LocalObservations.js +359 -359
- package/services/encode/NvencEncoder.js +50 -50
- package/services/encode/OutputOpening.js +758 -758
- package/services/encode/OutputTimes.js +579 -579
- package/services/encode/QsvEncoder.js +58 -58
- package/services/encode/Renditions.js +2184 -2184
- package/services/encode/RunProgress.js +84 -84
- package/services/encode/SegmentDemand.js +95 -95
- package/services/encode/SoftwareEncoder.js +121 -121
- package/services/encode/V4l2m2mEncoder.js +53 -53
- package/services/encode/VaapiEncoder.js +66 -66
- package/services/encode/args.js +416 -416
- package/services/encode/available-share.js +89 -89
- package/services/encode/calibration.js +361 -361
- package/services/encode/contention.js +128 -128
- package/services/encode/decode-cost-fit.js +363 -363
- package/services/encode/encode-exit.js +114 -114
- package/services/encode/encode-run-state.js +551 -551
- package/services/encode/encoder-readings.js +45 -45
- package/services/encode/fingerprint.js +322 -322
- package/services/encode/host-load.js +174 -174
- package/services/encode/hwaccel.js +1894 -1894
- package/services/encode/index.js +9 -9
- package/services/encode/learned-median.js +90 -90
- package/services/encode/output/EncodedOutput.js +57 -57
- package/services/encode/output/Output.js +131 -131
- package/services/encode/output/OutputCatalog.js +414 -414
- package/services/encode/output/OutputSpec.js +390 -390
- package/services/encode/output/Timeline.js +308 -308
- package/services/encode/output/cut-grid.js +107 -107
- package/services/encode/output/index.js +20 -20
- package/services/encode/output/ladder.js +32 -32
- package/services/encode/output/playlists.js +284 -284
- package/services/encode/output/rates.js +125 -125
- package/services/encode/output-key-format.js +21 -21
- package/services/encode/quality/EncodeCost.js +1141 -1141
- package/services/encode/quality/HostLoad.js +525 -525
- package/services/encode/quality/HostTimings.js +249 -249
- package/services/encode/quality/OutputQualityState.js +28 -28
- package/services/encode/quality/QualityController.js +935 -935
- package/services/encode/quality/QualityOffer.js +416 -416
- package/services/encode/quality/drain-threat.js +47 -47
- package/services/encode/quality/link-budget.js +254 -254
- package/services/encode/quality/output-format.js +315 -315
- package/services/encode/quality/serving-output.js +216 -216
- package/services/encode/quality/visible-rung.js +57 -57
- package/services/encode/run-budget.js +97 -97
- package/services/encode/run-command.js +754 -754
- package/services/encode/run-costs.js +155 -155
- package/services/encode/run-inputs.js +42 -42
- package/services/encode/segment-formats/fmp4.js +456 -456
- package/services/encode/segment-formats/index.js +85 -85
- package/services/encode/segment-formats/init-compat.js +324 -324
- package/services/encode/segment-formats/mp4-boxes.js +515 -515
- package/services/encode/segment-formats/mpegts.js +134 -134
- package/services/encode/start-stop-cost.js +178 -178
- package/services/encode/throughput.js +97 -97
- package/services/encode/torrent-cost.js +88 -88
- package/services/identity/installation-id.js +38 -38
- package/services/media/ContainerOrchestrator.js +149 -149
- package/services/media/KeyframeTables.js +316 -316
- package/services/media/SourceFile.js +298 -298
- package/services/media/SubtitleCues.js +520 -520
- package/services/media/SubtitleOrchestrator.js +167 -167
- package/services/media/audio-inventory.js +245 -245
- package/services/media/container/AviContainer.js +266 -266
- package/services/media/container/Container.js +603 -603
- package/services/media/container/ContainerFactory.js +56 -56
- package/services/media/container/KeyframeTable.js +272 -272
- package/services/media/container/MatroskaContainer.js +1494 -1494
- package/services/media/container/Mp4Container.js +1244 -1244
- package/services/media/container/SubtitleFileContainer.js +339 -322
- package/services/media/container/ebml-reader.js +159 -159
- package/services/media/ffmpeg-banner.js +260 -260
- package/services/media/keyframe-probe.js +157 -157
- package/services/media/media-info-probe.js +93 -93
- package/services/media/playback-planner.js +931 -931
- package/services/media/tracks/AudioTrack.js +131 -131
- package/services/media/tracks/ContainerTrack.js +75 -75
- package/services/media/tracks/ImageSubtitleTrack.js +19 -19
- package/services/media/tracks/SubtitleTrack.js +38 -38
- package/services/media/tracks/TextSubtitleTrack.js +287 -287
- package/services/media/tracks/VideoTrack.js +33 -33
- package/services/media/tracks/index.js +15 -15
- package/services/media/tracks/language-detect.js +174 -174
- package/services/server/OutputLifecycle.js +418 -418
- package/services/server/SegmentServing.js +1150 -1150
- package/services/server/ViewerRequests.js +760 -760
- package/services/server/WaitLedger.js +142 -142
- package/services/server/controllers/PlaybackController.js +40 -40
- package/services/server/controllers/SubtitleController.js +109 -109
- package/services/server/http-responses.js +60 -60
- package/services/server/playback-readiness.js +696 -696
- package/services/server/transcode-session-files.js +325 -325
- package/services/server/wire-outputs.js +992 -992
- package/services/storage/Diagnostics.js +202 -202
- package/services/storage/MachineBudget.js +235 -235
- package/services/storage/allowance.js +107 -107
- package/services/storage/core-dumps.js +106 -106
- package/services/storage/files/CompletedFiles.js +391 -391
- package/services/storage/files/piece-from-whole-file.js +118 -118
- package/services/storage/free.js +71 -71
- package/services/storage/keep.js +48 -48
- package/services/storage/machine-memory.js +56 -56
- package/services/storage/memory-report.js +575 -575
- package/services/storage/piece-store/piece-disk-store.js +539 -539
- package/services/storage/piece-store/piece-lru.js +495 -495
- package/services/storage/piece-store/shared-piece-store.js +1931 -1931
- package/services/storage/returns.js +103 -103
- package/services/storage/segment-store/SegmentStore.js +1240 -1240
- package/services/storage/wire.js +175 -175
- package/services/torrent/Contents.js +382 -324
- package/services/torrent/demand/DemandRegister.js +202 -202
- package/services/torrent/demand/Urgency.js +137 -137
- package/services/torrent/demand/Window.js +118 -118
- package/services/torrent/demand/index.js +8 -8
- package/services/torrent/demand/pieces.js +140 -140
- package/services/torrent/download/SwarmSelection.js +386 -386
- package/services/torrent/download/registry.js +102 -102
- package/services/torrent/download/withdraw-claim.js +80 -80
- package/services/torrent/episode-naming.js +182 -0
- package/services/torrent/files.js +455 -455
- package/services/torrent/naming.js +619 -619
- package/services/torrent/piece-store-of.js +29 -29
- package/services/torrent/supply-margin.js +262 -262
- package/services/torrent/torrent-pool.js +2675 -2675
- package/services/torrent/worker/background-fill.js +213 -213
- package/services/torrent/worker/channel.js +271 -271
- package/services/torrent/worker/client.js +765 -765
- package/services/torrent/worker/fastest-wires.js +342 -342
- package/services/torrent/worker/handle-state.js +23 -23
- package/services/torrent/worker/held-bytes.js +155 -155
- package/services/torrent/worker/install-webrtc-shim.js +32 -32
- package/services/torrent/worker/piece-reader.js +1078 -1078
- package/services/torrent/worker/pool-adapter.js +371 -371
- package/services/torrent/worker/protocol.js +184 -184
- package/services/torrent/worker/resume-warm.js +107 -107
- package/services/torrent/worker/webrtc-shim.js +219 -219
- package/services/torrent/worker/worker.js +1129 -1129
- package/services/transport/data-channel-handler.js +1369 -1369
- package/services/transport/delivery-probe.js +842 -842
- package/services/transport/health-collector.js +53 -53
- package/services/transport/nat-classifier.js +231 -231
- package/services/transport/packet-witness.js +808 -808
- package/services/transport/port-mapper.js +235 -235
- package/services/transport/registry-api.js +81 -81
- package/services/transport/tunnel-client.js +447 -447
- package/services/transport/usrsctp-state.js +175 -175
- package/services/transport/webrtc-manager.js +484 -484
- package/services/viewer/Assignments.js +340 -340
- package/services/viewer/PriorityMap.js +390 -390
- package/services/viewer/PriorityOrchestrator.js +325 -325
- package/services/viewer/Viewer.js +691 -691
- package/services/viewer/Viewers.js +368 -368
- package/services/viewer/active-output.js +37 -37
- package/services/viewer/audio-start.js +46 -46
- package/services/viewer/buffer-trend.js +81 -81
- package/services/viewer/choices.js +647 -647
- package/services/viewer/positions.js +126 -126
- package/services/viewer/report-intake.js +46 -46
- package/store/source-registry.js +71 -71
- package/test/asset-paths.test.js +28 -28
- package/test/audio-inventory.test.js +212 -212
- package/test/audio-track-bitrate.test.js +40 -40
- package/test/auto-quality-step.test.js +707 -707
- package/test/available-share.test.js +76 -76
- package/test/background-fill.test.js +190 -190
- package/test/client-log-file.test.js +110 -110
- package/test/completed-files.test.js +115 -115
- package/test/concurrent-cost.test.js +148 -148
- package/test/container-media-info.test.js +228 -228
- package/test/contention.test.js +76 -76
- package/test/core-dumps.test.js +57 -57
- package/test/coverage-follows-the-disk.test.js +228 -228
- package/test/coverage-map.test.js +195 -195
- package/test/cue-push-carries-what-the-walk-found.test.js +58 -58
- package/test/cut-times-timeline.test.js +65 -65
- package/test/cuts-follow-published-grid.test.js +109 -109
- package/test/data-channel-frame.test.js +63 -63
- package/test/data-channel-viewer-lifecycle.test.js +92 -92
- package/test/dead-torrent-handle.test.js +52 -52
- package/test/declared-rates.test.js +116 -116
- package/test/declared-tracks.test.js +43 -43
- package/test/decode-cost-fit.test.js +202 -202
- package/test/decode-cost.test.js +462 -462
- package/test/delivery-probe.test.js +393 -393
- package/test/demand-register.test.js +206 -206
- package/test/dht-bootstrap.test.js +72 -72
- package/test/drain-threat.test.js +65 -65
- package/test/duplicate-add.test.js +48 -48
- package/test/encode-admission.test.js +146 -146
- package/test/encode-cost.test.js +283 -283
- package/test/encode-exit.test.js +111 -111
- package/test/encode-orchestrator.test.js +419 -419
- package/test/encode-plan-viewers.test.js +718 -718
- package/test/encode-plan.test.js +545 -545
- package/test/encode-run-state.test.js +314 -314
- package/test/encode-run.test.js +162 -162
- package/test/encode-slope.test.js +46 -46
- package/test/encoded-output.test.js +39 -39
- package/test/encoder-kinds.test.js +122 -122
- package/test/encoder-readings.test.js +46 -46
- package/test/episode-naming.test.js +131 -0
- package/test/every-claimant-is-told-its-share.test.js +152 -152
- package/test/failed-encoder-still-serves-what-exists.test.js +354 -354
- package/test/failed-start-breaker.test.js +202 -202
- package/test/fastest-wires.test.js +143 -143
- package/test/ffmpeg-stream-counts.test.js +78 -78
- package/test/file-edges.test.js +191 -191
- package/test/fmp4-presentation-clock.test.js +147 -147
- package/test/fmp4-self-contained.test.js +80 -80
- package/test/fmp4-timestamps.test.js +140 -140
- package/test/fmp4-track-completeness.test.js +41 -41
- package/test/format-keyed-outputs.test.js +78 -78
- package/test/health-metrics.test.js +38 -38
- package/test/held-request-width.test.js +157 -157
- package/test/helpers/encode-run.js +136 -136
- package/test/helpers/held-file.js +29 -29
- package/test/helpers/manager.js +57 -57
- package/test/helpers/output-spec.js +63 -63
- package/test/host-load.test.js +68 -68
- package/test/index-accuracy-is-about-the-file.test.js +128 -128
- package/test/init-compat.test.js +219 -219
- package/test/input-lost-quiets-the-plan.test.js +261 -261
- package/test/input-unavailable.test.js +48 -48
- package/test/installation-id.test.js +39 -39
- package/test/keeping-period.test.js +83 -83
- package/test/keyframe-index-accuracy.test.js +188 -188
- package/test/keyframe-table-budget.test.js +102 -102
- package/test/keyframes-belong-to-the-file.test.js +249 -249
- package/test/learned-median.test.js +37 -37
- package/test/letting-go-asks-who-is-watching.test.js +191 -191
- package/test/limit-row-by-area.test.js +60 -60
- package/test/link-budget.test.js +111 -111
- package/test/link-probe.test.js +56 -56
- package/test/local-encoding-data.test.js +273 -273
- package/test/logger-repeats.test.js +134 -134
- package/test/look-ahead-coverage.test.js +56 -56
- package/test/manager-surface.test.js +292 -292
- package/test/matroska-cues-track.test.js +192 -192
- package/test/memory-budget.test.js +390 -390
- package/test/move-cost.test.js +216 -216
- package/test/mp4-subtitles.test.js +173 -173
- package/test/one-authority.test.js +285 -285
- package/test/one-budget.test.js +149 -149
- package/test/one-output-one-session.test.js +204 -204
- package/test/one-resource-divided.test.js +185 -185
- package/test/one-serving-output-per-height.test.js +458 -458
- package/test/orchestrator-wired.test.js +206 -206
- package/test/output-catalog.test.js +39 -39
- package/test/output-shape.test.js +21 -21
- package/test/output-spec.test.js +251 -251
- package/test/output-speed.test.js +88 -88
- package/test/outputs-being-prepared.test.js +40 -40
- package/test/packet-witness-ring.test.js +236 -236
- package/test/packet-witness.test.js +148 -148
- package/test/piece-disk-store.test.js +401 -401
- package/test/piece-from-whole-file.test.js +129 -129
- package/test/piece-lru.test.js +319 -319
- package/test/piece-reader.test.js +162 -162
- package/test/piece-selection-offset.test.js +85 -85
- package/test/piece-store-eviction.test.js +595 -595
- package/test/piece-store-never-refuses.test.js +153 -153
- package/test/piece-store-reservations.test.js +403 -403
- package/test/piece-store-slow-disk.test.js +159 -159
- package/test/piece-tail.test.js +97 -97
- package/test/plan-host-timings.test.js +68 -68
- package/test/plan-is-steady.test.js +225 -225
- package/test/playback-readiness.test.js +453 -453
- package/test/playback-start-regressions.test.js +99 -99
- package/test/priority-map-download.test.js +174 -174
- package/test/priority-map-emptied.test.js +204 -204
- package/test/priority-map-per-output.test.js +215 -215
- package/test/priority-map.test.js +163 -163
- package/test/probe-wedge-certainty.test.js +60 -60
- package/test/produced-copy-choice.test.js +213 -213
- package/test/published-timeline.test.js +83 -83
- package/test/quality-offer.test.js +162 -162
- package/test/quality-variants.test.js +1229 -1229
- package/test/rate-control-in-the-output.test.js +180 -180
- package/test/read-survives-withdrawal.test.js +164 -164
- package/test/read-window.test.js +365 -365
- package/test/resume-warm.test.js +39 -39
- package/test/run-graph-drift.test.js +37 -37
- package/test/run-inputs.test.js +80 -80
- package/test/run-intervals.test.js +100 -100
- package/test/run-position-follows-published-grid.test.js +89 -89
- package/test/run-progress.test.js +65 -65
- package/test/same-height-switch.test.js +664 -664
- package/test/seek-frees-the-viewers-requests.test.js +217 -217
- package/test/seek-landing.test.js +109 -109
- package/test/seek-target-not-superseded.test.js +195 -195
- package/test/segment-closed-on-both-branches.test.js +96 -96
- package/test/segment-cut-times.test.js +63 -63
- package/test/segment-demand.test.js +80 -80
- package/test/segment-hold-supersede.test.js +91 -91
- package/test/segment-judged-by-its-own-header.test.js +221 -221
- package/test/segment-serve-wiring.test.js +475 -475
- package/test/segment-store-eviction.test.js +247 -247
- package/test/segment-store.test.js +323 -323
- package/test/segment-true-start.test.js +86 -86
- package/test/segments-are-shared.test.js +176 -176
- package/test/send-chunk-bytes.test.js +86 -86
- package/test/serving-existing-output.test.js +102 -102
- package/test/serving-output.test.js +102 -102
- package/test/shared-piece-store.test.js +310 -310
- package/test/sidecar-naming.test.js +142 -142
- package/test/source-file.test.js +133 -133
- package/test/source-files-route.test.js +12 -2
- package/test/source-registry.test.js +18 -18
- package/test/split-a-stretch.test.js +139 -139
- package/test/stale-request-after-seek.test.js +158 -158
- package/test/startup-readings.test.js +124 -124
- package/test/stream-route.test.js +209 -209
- package/test/subtitle-cue-framing.test.js +200 -200
- package/test/subtitle-cue-source.test.js +102 -102
- package/test/subtitle-cue-walk.test.js +370 -370
- package/test/subtitle-cursor.test.js +63 -63
- package/test/subtitle-defaults.test.js +118 -118
- package/test/subtitle-language.test.js +252 -252
- package/test/subtitle-metadata.test.js +15 -0
- package/test/subtitle-track-numbering.test.js +386 -386
- package/test/supply-margin.test.js +177 -177
- package/test/swarm-follows-readers.test.js +174 -174
- package/test/swarm-reach.test.js +130 -130
- package/test/swarm-selection.test.js +220 -220
- package/test/tail-duplication.test.js +167 -167
- package/test/the-channel-has-both-ends.test.js +91 -91
- package/test/the-torrent-thread-serves-bytes.test.js +107 -107
- package/test/thread-pool.test.js +53 -53
- package/test/timeline.test.js +84 -84
- package/test/torrent-contents.test.js +235 -235
- package/test/torrent-cost.test.js +71 -71
- package/test/torrent-files.test.js +221 -221
- package/test/torrent-naming.test.js +255 -255
- package/test/tracks-begin-together.test.js +209 -209
- package/test/tunnel-renewal.test.js +167 -167
- package/test/two-viewers-one-picture.test.js +407 -407
- package/test/upload-hurry.test.js +186 -186
- package/test/usrsctp-state.test.js +131 -131
- package/test/video-facts.test.js +102 -102
- package/test/viewer-assignments.test.js +143 -143
- package/test/viewer-outputs.test.js +285 -285
- package/test/viewer-presence.test.js +116 -116
- package/test/viewer-requests-admission.test.js +89 -89
- package/test/viewer-states.test.js +189 -189
- package/test/viewer-subtitle-subscription.test.js +96 -96
- package/test/viewer.test.js +139 -139
- package/test/viewing-generations.test.js +390 -390
- package/test/visible-rung.test.js +37 -37
- package/test/wait-ledger.test.js +100 -100
- package/test/webrtc-shim.test.js +149 -149
- package/test/wedge-certainty.test.js +131 -131
- package/test/withdraw-piece-claim.test.js +212 -212
- package/test/worker-channel.test.js +158 -158
- package/utils/client-log-file.js +151 -151
- package/utils/logger.js +312 -312
- package/utils/parse-range.js +25 -25
- package/utils/perf.js +59 -59
- package/utils/torrent-source-key.js +38 -38
package/test/encode-exit.test.js
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file The four things an ffmpeg exit can mean, by their field cases.
|
|
3
|
-
*
|
|
4
|
-
* Each test names the release the classification cost. None of them needs a
|
|
5
|
-
* process: what went wrong in every case was the reading of the exit, not the
|
|
6
|
-
* handling of it.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import assert from "node:assert/strict";
|
|
10
|
-
import test from "node:test";
|
|
11
|
-
|
|
12
|
-
import { ENCODE_EXIT, classifyEncodeExit } from "../services/encode/encode-exit.js";
|
|
13
|
-
|
|
14
|
-
test("the predecessor a seek kills says nothing about the session", () => {
|
|
15
|
-
// The handler decides "is this exit mine" by comparing against the session's
|
|
16
|
-
// current process — and during a restart that field still names the process
|
|
17
|
-
// being killed, because the replacement is spawned afterwards. So a SIGKILLed
|
|
18
|
-
// predecessor passed the check and was read as the session's own run dying:
|
|
19
|
-
// a spurious "failed" that a segment request landing in that window is
|
|
20
|
-
// answered 500 for, and on a hardware host a permanent downgrade to libx264.
|
|
21
|
-
assert.equal(
|
|
22
|
-
classifyEncodeExit({ superseded: true, code: null, inputUnavailable: false }),
|
|
23
|
-
ENCODE_EXIT.IGNORED
|
|
24
|
-
);
|
|
25
|
-
// Including when it looks like a clean finish.
|
|
26
|
-
assert.equal(classifyEncodeExit({ superseded: true, code: 0 }), ENCODE_EXIT.IGNORED);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("exit 0 short of the last segment is a failure, not a finished file", () => {
|
|
30
|
-
// 2.9.104. A run that had made 188 segments of 624 reported itself complete,
|
|
31
|
-
// the player consumed what was on disk and froze on the first segment nobody
|
|
32
|
-
// was making.
|
|
33
|
-
assert.equal(
|
|
34
|
-
classifyEncodeExit({ code: 0, producedThrough: 188, lastSegmentIndex: 623 }),
|
|
35
|
-
ENCODE_EXIT.SHORT
|
|
36
|
-
);
|
|
37
|
-
assert.equal(
|
|
38
|
-
classifyEncodeExit({ code: 0, producedThrough: 623, lastSegmentIndex: 623 }),
|
|
39
|
-
ENCODE_EXIT.COMPLETE
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("exit 0 is complete when there is nothing to check it against", () => {
|
|
44
|
-
// No published last segment, or nothing readable on disk: the claim cannot be
|
|
45
|
-
// contradicted, so it stands. Guessing "short" here would fail every session
|
|
46
|
-
// whose directory could not be read.
|
|
47
|
-
assert.equal(classifyEncodeExit({ code: 0, producedThrough: null, lastSegmentIndex: 623 }), ENCODE_EXIT.COMPLETE);
|
|
48
|
-
assert.equal(classifyEncodeExit({ code: 0, producedThrough: 12, lastSegmentIndex: null }), ENCODE_EXIT.COMPLETE);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("data that went away is recoverable, and is not an encoder fault", () => {
|
|
52
|
-
// Field 2026-08-06: a torrent evicted mid-seek took the film with it, the run
|
|
53
|
-
// died on `File 0 not found`, and the session answered 500 from then on while
|
|
54
|
-
// the swarm was there and the data would have come back in seconds.
|
|
55
|
-
assert.equal(
|
|
56
|
-
classifyEncodeExit({ code: 1, inputUnavailable: true }),
|
|
57
|
-
ENCODE_EXIT.INPUT_LOST
|
|
58
|
-
);
|
|
59
|
-
// And the distinction is what keeps a working hardware encoder: the caller
|
|
60
|
-
// downgrades to software on FAILED, so an input that vanished must not
|
|
61
|
-
// arrive there.
|
|
62
|
-
assert.notEqual(classifyEncodeExit({ code: 1, inputUnavailable: true }), ENCODE_EXIT.FAILED);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("anything else is a failure of this target", () => {
|
|
66
|
-
assert.equal(classifyEncodeExit({ code: 1, inputUnavailable: false }), ENCODE_EXIT.FAILED);
|
|
67
|
-
assert.equal(classifyEncodeExit({ code: null, inputUnavailable: false }), ENCODE_EXIT.FAILED);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
test("every combination answers, and no input produces undefined", () => {
|
|
71
|
-
for (const superseded of [true, false]) {
|
|
72
|
-
for (const code of [0, 1, null]) {
|
|
73
|
-
for (const producedThrough of [null, 0, 10]) {
|
|
74
|
-
for (const lastSegmentIndex of [null, 0, 10]) {
|
|
75
|
-
for (const inputUnavailable of [true, false]) {
|
|
76
|
-
const answer = classifyEncodeExit({
|
|
77
|
-
superseded,
|
|
78
|
-
code,
|
|
79
|
-
producedThrough,
|
|
80
|
-
lastSegmentIndex,
|
|
81
|
-
inputUnavailable
|
|
82
|
-
});
|
|
83
|
-
assert.ok(
|
|
84
|
-
Object.values(ENCODE_EXIT).includes(answer),
|
|
85
|
-
`answered ${String(answer)} for ${JSON.stringify({ superseded, code, producedThrough, lastSegmentIndex, inputUnavailable })}`
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
assert.ok(Object.values(ENCODE_EXIT).includes(classifyEncodeExit()));
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
test("a run that made nothing has not finished, whatever its exit code", () => {
|
|
96
|
-
// Field 2026-09-11: a run given #541..#541 was handed a start later than its
|
|
97
|
-
// own end, wrote 190 bytes that are not a fragment, and exited zero. Making
|
|
98
|
-
// no segment and being unable to read the directory were the same `null`, and
|
|
99
|
-
// the second reading — "cannot be contradicted, so it stands" — was applied
|
|
100
|
-
// to the first.
|
|
101
|
-
assert.equal(
|
|
102
|
-
classifyEncodeExit({ code: 0, producedThrough: null, producedCount: 0, lastSegmentIndex: 541 }),
|
|
103
|
-
ENCODE_EXIT.SHORT
|
|
104
|
-
);
|
|
105
|
-
// And the case that reading was written for still stands: nothing readable on
|
|
106
|
-
// disk is not a claim that nothing was made.
|
|
107
|
-
assert.equal(
|
|
108
|
-
classifyEncodeExit({ code: 0, producedThrough: null, producedCount: null, lastSegmentIndex: 623 }),
|
|
109
|
-
ENCODE_EXIT.COMPLETE
|
|
110
|
-
);
|
|
111
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* @file The four things an ffmpeg exit can mean, by their field cases.
|
|
3
|
+
*
|
|
4
|
+
* Each test names the release the classification cost. None of them needs a
|
|
5
|
+
* process: what went wrong in every case was the reading of the exit, not the
|
|
6
|
+
* handling of it.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import test from "node:test";
|
|
11
|
+
|
|
12
|
+
import { ENCODE_EXIT, classifyEncodeExit } from "../services/encode/encode-exit.js";
|
|
13
|
+
|
|
14
|
+
test("the predecessor a seek kills says nothing about the session", () => {
|
|
15
|
+
// The handler decides "is this exit mine" by comparing against the session's
|
|
16
|
+
// current process — and during a restart that field still names the process
|
|
17
|
+
// being killed, because the replacement is spawned afterwards. So a SIGKILLed
|
|
18
|
+
// predecessor passed the check and was read as the session's own run dying:
|
|
19
|
+
// a spurious "failed" that a segment request landing in that window is
|
|
20
|
+
// answered 500 for, and on a hardware host a permanent downgrade to libx264.
|
|
21
|
+
assert.equal(
|
|
22
|
+
classifyEncodeExit({ superseded: true, code: null, inputUnavailable: false }),
|
|
23
|
+
ENCODE_EXIT.IGNORED
|
|
24
|
+
);
|
|
25
|
+
// Including when it looks like a clean finish.
|
|
26
|
+
assert.equal(classifyEncodeExit({ superseded: true, code: 0 }), ENCODE_EXIT.IGNORED);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("exit 0 short of the last segment is a failure, not a finished file", () => {
|
|
30
|
+
// 2.9.104. A run that had made 188 segments of 624 reported itself complete,
|
|
31
|
+
// the player consumed what was on disk and froze on the first segment nobody
|
|
32
|
+
// was making.
|
|
33
|
+
assert.equal(
|
|
34
|
+
classifyEncodeExit({ code: 0, producedThrough: 188, lastSegmentIndex: 623 }),
|
|
35
|
+
ENCODE_EXIT.SHORT
|
|
36
|
+
);
|
|
37
|
+
assert.equal(
|
|
38
|
+
classifyEncodeExit({ code: 0, producedThrough: 623, lastSegmentIndex: 623 }),
|
|
39
|
+
ENCODE_EXIT.COMPLETE
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("exit 0 is complete when there is nothing to check it against", () => {
|
|
44
|
+
// No published last segment, or nothing readable on disk: the claim cannot be
|
|
45
|
+
// contradicted, so it stands. Guessing "short" here would fail every session
|
|
46
|
+
// whose directory could not be read.
|
|
47
|
+
assert.equal(classifyEncodeExit({ code: 0, producedThrough: null, lastSegmentIndex: 623 }), ENCODE_EXIT.COMPLETE);
|
|
48
|
+
assert.equal(classifyEncodeExit({ code: 0, producedThrough: 12, lastSegmentIndex: null }), ENCODE_EXIT.COMPLETE);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("data that went away is recoverable, and is not an encoder fault", () => {
|
|
52
|
+
// Field 2026-08-06: a torrent evicted mid-seek took the film with it, the run
|
|
53
|
+
// died on `File 0 not found`, and the session answered 500 from then on while
|
|
54
|
+
// the swarm was there and the data would have come back in seconds.
|
|
55
|
+
assert.equal(
|
|
56
|
+
classifyEncodeExit({ code: 1, inputUnavailable: true }),
|
|
57
|
+
ENCODE_EXIT.INPUT_LOST
|
|
58
|
+
);
|
|
59
|
+
// And the distinction is what keeps a working hardware encoder: the caller
|
|
60
|
+
// downgrades to software on FAILED, so an input that vanished must not
|
|
61
|
+
// arrive there.
|
|
62
|
+
assert.notEqual(classifyEncodeExit({ code: 1, inputUnavailable: true }), ENCODE_EXIT.FAILED);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("anything else is a failure of this target", () => {
|
|
66
|
+
assert.equal(classifyEncodeExit({ code: 1, inputUnavailable: false }), ENCODE_EXIT.FAILED);
|
|
67
|
+
assert.equal(classifyEncodeExit({ code: null, inputUnavailable: false }), ENCODE_EXIT.FAILED);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("every combination answers, and no input produces undefined", () => {
|
|
71
|
+
for (const superseded of [true, false]) {
|
|
72
|
+
for (const code of [0, 1, null]) {
|
|
73
|
+
for (const producedThrough of [null, 0, 10]) {
|
|
74
|
+
for (const lastSegmentIndex of [null, 0, 10]) {
|
|
75
|
+
for (const inputUnavailable of [true, false]) {
|
|
76
|
+
const answer = classifyEncodeExit({
|
|
77
|
+
superseded,
|
|
78
|
+
code,
|
|
79
|
+
producedThrough,
|
|
80
|
+
lastSegmentIndex,
|
|
81
|
+
inputUnavailable
|
|
82
|
+
});
|
|
83
|
+
assert.ok(
|
|
84
|
+
Object.values(ENCODE_EXIT).includes(answer),
|
|
85
|
+
`answered ${String(answer)} for ${JSON.stringify({ superseded, code, producedThrough, lastSegmentIndex, inputUnavailable })}`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
assert.ok(Object.values(ENCODE_EXIT).includes(classifyEncodeExit()));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("a run that made nothing has not finished, whatever its exit code", () => {
|
|
96
|
+
// Field 2026-09-11: a run given #541..#541 was handed a start later than its
|
|
97
|
+
// own end, wrote 190 bytes that are not a fragment, and exited zero. Making
|
|
98
|
+
// no segment and being unable to read the directory were the same `null`, and
|
|
99
|
+
// the second reading — "cannot be contradicted, so it stands" — was applied
|
|
100
|
+
// to the first.
|
|
101
|
+
assert.equal(
|
|
102
|
+
classifyEncodeExit({ code: 0, producedThrough: null, producedCount: 0, lastSegmentIndex: 541 }),
|
|
103
|
+
ENCODE_EXIT.SHORT
|
|
104
|
+
);
|
|
105
|
+
// And the case that reading was written for still stands: nothing readable on
|
|
106
|
+
// disk is not a claim that nothing was made.
|
|
107
|
+
assert.equal(
|
|
108
|
+
classifyEncodeExit({ code: 0, producedThrough: null, producedCount: null, lastSegmentIndex: 623 }),
|
|
109
|
+
ENCODE_EXIT.COMPLETE
|
|
110
|
+
);
|
|
111
|
+
});
|