Never serve a partial file: it makes Jellyfin transcode
The 12s first-byte grace was the wrong trade and a real play found it within the hour. A 2-hour upload took 3 minutes to start, played 6 seconds, and stalled. Jellyfin had run ffmpeg with -probesize 1G against the growing stream and then transcoded to HLS with libx264. The cause is the container. A fragmented MP4 with empty_moov has no duration in its header, so the only way to get one is to sum every fragment -- probing a growing file reads all of it. Jellyfin cannot establish duration, codec or bitrate, so it abandons direct play and transcodes a stream it also cannot seek. It was targeting 4.83 Mbps against a source measured at 3.29: re-encoding a stream that already fit, because it could not measure it. The same video once complete reports SupportsDirectPlay with the exact runtime and bitrate. So FIRST_BYTE_GRACE defaults to infinite again, with --wait-timeout raised to 600s for a 2-hour upload. A cold long video is slow to start, which is accepted: the fetch outlives the request so a retry is instant, and a retryable stall beats a transcode that wastes a gigabyte and cannot work. Both failure modes are recorded at the constant in the order measured so the 12s cap is not reintroduced. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+27
-4
@@ -341,14 +341,37 @@ def test_growing_flag_means_no_wait_at_all(tmp_path):
|
||||
server.close()
|
||||
|
||||
|
||||
def test_status_reports_the_serving_mode_and_grace(manager_factory):
|
||||
"""/healthz has to show this: it is the difference between 'plays' and
|
||||
'playback error', and it is otherwise invisible without the unit file."""
|
||||
def test_the_default_is_to_wait_for_a_complete_file(manager_factory):
|
||||
"""The default must not serve a partial file. Jellyfin responds to one by
|
||||
dragging a gigabyte through the proxy to probe a fragmented MP4 that has no
|
||||
duration in its header, then transcoding a stream it cannot seek: measured
|
||||
2026-08-13, 3 minutes to start, 6 seconds of video, permanent stall."""
|
||||
assert proxy.FIRST_BYTE_GRACE == float("inf")
|
||||
|
||||
status = manager_factory().status()
|
||||
assert status["mode"] == "wait-for-complete"
|
||||
assert status["first_byte_grace_s"] is None
|
||||
|
||||
|
||||
def test_status_is_valid_json_with_no_grace_cap(manager_factory):
|
||||
"""json.dumps emits `Infinity` for an infinite float, which is not JSON and
|
||||
breaks any client that parses /healthz strictly."""
|
||||
payload = json.dumps(manager_factory().status())
|
||||
assert "Infinity" not in payload
|
||||
assert json.loads(payload)["first_byte_grace_s"] is None
|
||||
|
||||
|
||||
def test_status_reports_a_finite_grace_when_one_is_set(manager_factory):
|
||||
manager = manager_factory()
|
||||
manager.strict = False
|
||||
manager.first_byte_grace = 12.0
|
||||
|
||||
status = manager.status()
|
||||
assert status["mode"] == "wait-then-stream"
|
||||
assert status["first_byte_grace_s"] == proxy.FIRST_BYTE_GRACE
|
||||
assert status["first_byte_grace_s"] == 12.0
|
||||
|
||||
|
||||
def test_status_reports_growing_mode(manager_factory):
|
||||
growing = manager_factory(growing=True)
|
||||
assert growing.status()["mode"] == "growing"
|
||||
assert growing.status()["first_byte_grace_s"] == 0.0
|
||||
|
||||
Reference in New Issue
Block a user