@torrent-tv/proxy 2.87.20 → 2.88.0
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 +8 -0
- 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 +133 -133
- 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 +322 -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 -1908
- 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 -365
- 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-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
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file What an ffmpeg exit MEANS — as a pure classification, so the four
|
|
3
|
-
* possibilities can be exercised without spawning anything.
|
|
4
|
-
*
|
|
5
|
-
* The exit handler is where two of this project's most expensive failures
|
|
6
|
-
* lived, and both were classification faults rather than logic faults:
|
|
7
|
-
*
|
|
8
|
-
* - 2.9.104: ffmpeg exits 0 when it reaches the end of the file AND when its
|
|
9
|
-
* input simply stops delivering bytes — over HTTP the two look identical to
|
|
10
|
-
* it. A run that had made 188 segments of 624 reported itself complete, the
|
|
11
|
-
* player consumed what was on disk and froze on the first segment nobody
|
|
12
|
-
* was making. The difference is not in the exit code; it is in how far the
|
|
13
|
-
* run got against the playlist we published.
|
|
14
|
-
* - The predecessor a seek kills exits with a signal and used to be handled
|
|
15
|
-
* as the session's own run dying. Which is why "was this process already
|
|
16
|
-
* replaced" is the FIRST question here rather than a check somewhere in the
|
|
17
|
-
* caller: an exit that belongs to a superseded run means nothing at all,
|
|
18
|
-
* and reading it as a failure downgraded a hardware encoder for good.
|
|
19
|
-
*
|
|
20
|
-
* Nothing here touches a session, a process or a clock. The caller decides what
|
|
21
|
-
* to DO about each answer.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* What this exit says about the run.
|
|
26
|
-
*
|
|
27
|
-
* @readonly
|
|
28
|
-
*/
|
|
29
|
-
export const ENCODE_EXIT = Object.freeze({
|
|
30
|
-
/** The process was already replaced or the session is gone: it says nothing. */
|
|
31
|
-
IGNORED: "ignored",
|
|
32
|
-
/**
|
|
33
|
-
* We stopped it on purpose — moved off covered material, no longer wanted,
|
|
34
|
-
* the output was dropped.
|
|
35
|
-
*
|
|
36
|
-
* Abnormal by the rule this vocabulary exists to serve: exactly one ending is
|
|
37
|
-
* normal, and our own kill is not it. Hiding it among the normal endings is
|
|
38
|
-
* what would make the count of abnormal endings useless.
|
|
39
|
-
*/
|
|
40
|
-
STOPPED: "stopped",
|
|
41
|
-
/**
|
|
42
|
-
* It was found to be over without having said so.
|
|
43
|
-
*
|
|
44
|
-
* Only a run handed over from elsewhere can end this way; one that owns its
|
|
45
|
-
* own process reports its own ending. Counted apart precisely because it
|
|
46
|
-
* means nobody watched it end.
|
|
47
|
-
*/
|
|
48
|
-
GONE: "gone",
|
|
49
|
-
/** Reached the end of the file. */
|
|
50
|
-
COMPLETE: "complete",
|
|
51
|
-
/** Claimed success, stopped short of the last segment — the input dried up. */
|
|
52
|
-
SHORT: "short",
|
|
53
|
-
/** The input was not there. Recoverable: the data can come back. */
|
|
54
|
-
INPUT_LOST: "input-lost",
|
|
55
|
-
/** Anything else. Terminal for this target until something restarts it. */
|
|
56
|
-
FAILED: "failed"
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Classify one exit.
|
|
61
|
-
*
|
|
62
|
-
* `inputUnavailable` is decided by the caller from ffmpeg's own message, and it
|
|
63
|
-
* is asked BEFORE the hardware-encoder question deliberately: a run that died
|
|
64
|
-
* because its torrent data went away says nothing whatever about the encoder,
|
|
65
|
-
* and treating it as an encoder failure is how a host with NVENC came to
|
|
66
|
-
* downgrade itself to software over a missing piece.
|
|
67
|
-
*
|
|
68
|
-
* @param {object} facts
|
|
69
|
-
* @param {boolean} [facts.superseded] - This process was replaced or the
|
|
70
|
-
* session disposed before the exit arrived.
|
|
71
|
-
* @param {number | null} [facts.code] - Exit code, null when killed by a signal.
|
|
72
|
-
* @param {number | null} [facts.producedThrough] - Highest segment index this
|
|
73
|
-
* session has on disk, or null when that could not be read.
|
|
74
|
-
* @param {number | null} [facts.lastSegmentIndex] - Index of the file's last
|
|
75
|
-
* segment according to the published playlist, or null when unknown.
|
|
76
|
-
* @param {number | null} [facts.producedCount] - How many segments THIS run
|
|
77
|
-
* made. Zero and "could not be read" are different facts and were both `null`
|
|
78
|
-
* until 2026-09-11: a run that made nothing exited zero and was recorded as
|
|
79
|
-
* having finished, which is how a segment that does not exist came to be
|
|
80
|
-
* believed present for forty-six minutes.
|
|
81
|
-
* @param {boolean} [facts.inputUnavailable] - The error names a missing input.
|
|
82
|
-
* @returns {string} One of {@link ENCODE_EXIT}.
|
|
83
|
-
*/
|
|
84
|
-
export function classifyEncodeExit({
|
|
85
|
-
superseded = false,
|
|
86
|
-
code = null,
|
|
87
|
-
producedThrough = null,
|
|
88
|
-
lastSegmentIndex = null,
|
|
89
|
-
producedCount = null,
|
|
90
|
-
inputUnavailable = false
|
|
91
|
-
} = {}) {
|
|
92
|
-
if (superseded) {
|
|
93
|
-
return ENCODE_EXIT.IGNORED;
|
|
94
|
-
}
|
|
95
|
-
if (code === 0) {
|
|
96
|
-
// PRODUCING NOTHING IS THE CLEAREST CASE OF NOT FINISHING, and it used to be
|
|
97
|
-
// the one case that read as success: `producedThrough` is null when the run
|
|
98
|
-
// made no segment at all, null is "unknown", and unknown fell through to
|
|
99
|
-
// complete. Field 2026-09-11: a run given #541..#541 was handed a start
|
|
100
|
-
// later than its own end, wrote 190 bytes that are not a fragment, exited
|
|
101
|
-
// zero — and was recorded as having reached the end of what it was given.
|
|
102
|
-
// Nothing asked for that segment again for forty-six minutes, until the
|
|
103
|
-
// viewer arrived at it and waited 23 s for a 404.
|
|
104
|
-
if (producedCount === 0 && lastSegmentIndex !== null) {
|
|
105
|
-
return ENCODE_EXIT.SHORT;
|
|
106
|
-
}
|
|
107
|
-
const stoppedShort =
|
|
108
|
-
lastSegmentIndex !== null &&
|
|
109
|
-
producedThrough !== null &&
|
|
110
|
-
producedThrough < lastSegmentIndex;
|
|
111
|
-
return stoppedShort ? ENCODE_EXIT.SHORT : ENCODE_EXIT.COMPLETE;
|
|
112
|
-
}
|
|
113
|
-
return inputUnavailable ? ENCODE_EXIT.INPUT_LOST : ENCODE_EXIT.FAILED;
|
|
114
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* @file What an ffmpeg exit MEANS — as a pure classification, so the four
|
|
3
|
+
* possibilities can be exercised without spawning anything.
|
|
4
|
+
*
|
|
5
|
+
* The exit handler is where two of this project's most expensive failures
|
|
6
|
+
* lived, and both were classification faults rather than logic faults:
|
|
7
|
+
*
|
|
8
|
+
* - 2.9.104: ffmpeg exits 0 when it reaches the end of the file AND when its
|
|
9
|
+
* input simply stops delivering bytes — over HTTP the two look identical to
|
|
10
|
+
* it. A run that had made 188 segments of 624 reported itself complete, the
|
|
11
|
+
* player consumed what was on disk and froze on the first segment nobody
|
|
12
|
+
* was making. The difference is not in the exit code; it is in how far the
|
|
13
|
+
* run got against the playlist we published.
|
|
14
|
+
* - The predecessor a seek kills exits with a signal and used to be handled
|
|
15
|
+
* as the session's own run dying. Which is why "was this process already
|
|
16
|
+
* replaced" is the FIRST question here rather than a check somewhere in the
|
|
17
|
+
* caller: an exit that belongs to a superseded run means nothing at all,
|
|
18
|
+
* and reading it as a failure downgraded a hardware encoder for good.
|
|
19
|
+
*
|
|
20
|
+
* Nothing here touches a session, a process or a clock. The caller decides what
|
|
21
|
+
* to DO about each answer.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* What this exit says about the run.
|
|
26
|
+
*
|
|
27
|
+
* @readonly
|
|
28
|
+
*/
|
|
29
|
+
export const ENCODE_EXIT = Object.freeze({
|
|
30
|
+
/** The process was already replaced or the session is gone: it says nothing. */
|
|
31
|
+
IGNORED: "ignored",
|
|
32
|
+
/**
|
|
33
|
+
* We stopped it on purpose — moved off covered material, no longer wanted,
|
|
34
|
+
* the output was dropped.
|
|
35
|
+
*
|
|
36
|
+
* Abnormal by the rule this vocabulary exists to serve: exactly one ending is
|
|
37
|
+
* normal, and our own kill is not it. Hiding it among the normal endings is
|
|
38
|
+
* what would make the count of abnormal endings useless.
|
|
39
|
+
*/
|
|
40
|
+
STOPPED: "stopped",
|
|
41
|
+
/**
|
|
42
|
+
* It was found to be over without having said so.
|
|
43
|
+
*
|
|
44
|
+
* Only a run handed over from elsewhere can end this way; one that owns its
|
|
45
|
+
* own process reports its own ending. Counted apart precisely because it
|
|
46
|
+
* means nobody watched it end.
|
|
47
|
+
*/
|
|
48
|
+
GONE: "gone",
|
|
49
|
+
/** Reached the end of the file. */
|
|
50
|
+
COMPLETE: "complete",
|
|
51
|
+
/** Claimed success, stopped short of the last segment — the input dried up. */
|
|
52
|
+
SHORT: "short",
|
|
53
|
+
/** The input was not there. Recoverable: the data can come back. */
|
|
54
|
+
INPUT_LOST: "input-lost",
|
|
55
|
+
/** Anything else. Terminal for this target until something restarts it. */
|
|
56
|
+
FAILED: "failed"
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Classify one exit.
|
|
61
|
+
*
|
|
62
|
+
* `inputUnavailable` is decided by the caller from ffmpeg's own message, and it
|
|
63
|
+
* is asked BEFORE the hardware-encoder question deliberately: a run that died
|
|
64
|
+
* because its torrent data went away says nothing whatever about the encoder,
|
|
65
|
+
* and treating it as an encoder failure is how a host with NVENC came to
|
|
66
|
+
* downgrade itself to software over a missing piece.
|
|
67
|
+
*
|
|
68
|
+
* @param {object} facts
|
|
69
|
+
* @param {boolean} [facts.superseded] - This process was replaced or the
|
|
70
|
+
* session disposed before the exit arrived.
|
|
71
|
+
* @param {number | null} [facts.code] - Exit code, null when killed by a signal.
|
|
72
|
+
* @param {number | null} [facts.producedThrough] - Highest segment index this
|
|
73
|
+
* session has on disk, or null when that could not be read.
|
|
74
|
+
* @param {number | null} [facts.lastSegmentIndex] - Index of the file's last
|
|
75
|
+
* segment according to the published playlist, or null when unknown.
|
|
76
|
+
* @param {number | null} [facts.producedCount] - How many segments THIS run
|
|
77
|
+
* made. Zero and "could not be read" are different facts and were both `null`
|
|
78
|
+
* until 2026-09-11: a run that made nothing exited zero and was recorded as
|
|
79
|
+
* having finished, which is how a segment that does not exist came to be
|
|
80
|
+
* believed present for forty-six minutes.
|
|
81
|
+
* @param {boolean} [facts.inputUnavailable] - The error names a missing input.
|
|
82
|
+
* @returns {string} One of {@link ENCODE_EXIT}.
|
|
83
|
+
*/
|
|
84
|
+
export function classifyEncodeExit({
|
|
85
|
+
superseded = false,
|
|
86
|
+
code = null,
|
|
87
|
+
producedThrough = null,
|
|
88
|
+
lastSegmentIndex = null,
|
|
89
|
+
producedCount = null,
|
|
90
|
+
inputUnavailable = false
|
|
91
|
+
} = {}) {
|
|
92
|
+
if (superseded) {
|
|
93
|
+
return ENCODE_EXIT.IGNORED;
|
|
94
|
+
}
|
|
95
|
+
if (code === 0) {
|
|
96
|
+
// PRODUCING NOTHING IS THE CLEAREST CASE OF NOT FINISHING, and it used to be
|
|
97
|
+
// the one case that read as success: `producedThrough` is null when the run
|
|
98
|
+
// made no segment at all, null is "unknown", and unknown fell through to
|
|
99
|
+
// complete. Field 2026-09-11: a run given #541..#541 was handed a start
|
|
100
|
+
// later than its own end, wrote 190 bytes that are not a fragment, exited
|
|
101
|
+
// zero — and was recorded as having reached the end of what it was given.
|
|
102
|
+
// Nothing asked for that segment again for forty-six minutes, until the
|
|
103
|
+
// viewer arrived at it and waited 23 s for a 404.
|
|
104
|
+
if (producedCount === 0 && lastSegmentIndex !== null) {
|
|
105
|
+
return ENCODE_EXIT.SHORT;
|
|
106
|
+
}
|
|
107
|
+
const stoppedShort =
|
|
108
|
+
lastSegmentIndex !== null &&
|
|
109
|
+
producedThrough !== null &&
|
|
110
|
+
producedThrough < lastSegmentIndex;
|
|
111
|
+
return stoppedShort ? ENCODE_EXIT.SHORT : ENCODE_EXIT.COMPLETE;
|
|
112
|
+
}
|
|
113
|
+
return inputUnavailable ? ENCODE_EXIT.INPUT_LOST : ENCODE_EXIT.FAILED;
|
|
114
|
+
}
|