fix(downloads): a produced file is held to the space left by its real size
yt-dlp's `max_filesize` only stops a plain HTTP file that announces its size: YouTube's fragmented formats never meet it — measured on localdev, a 718 MB download ran to the end with 1 MB left and put its owner four times over the cap. The download now re-reads what is left once its file is made (after the phone-safe pass) and refuses one larger than that as the owner's refusal; an editor clip, which nothing checked, is held the same way, as a player clip already was.
This commit is contained in:
@@ -344,3 +344,51 @@ def test_a_download_over_the_space_left_says_so_and_releases_the_shared_asset(
|
||||
assert (job.status, job.error_code) == ("error", "quota_exceeded")
|
||||
assert job.error == dlerrors.DOWNLOAD_TOO_BIG_MESSAGE
|
||||
assert db.get(MediaAsset, shared.id).status == "pending"
|
||||
|
||||
|
||||
def test_a_download_that_outgrows_the_space_left_unannounced_is_refused_and_not_placed(
|
||||
db, monkeypatch, tmp_path
|
||||
):
|
||||
# yt-dlp's `max_filesize` only stops a plain HTTP file that announces its size: YouTube's
|
||||
# fragmented formats never meet it (measured on localdev: 718 MB fetched with 1 MB left). The
|
||||
# file it produced is held to what is left by its real size, as a clip is.
|
||||
monkeypatch.setattr(settings, "download_root", str(tmp_path))
|
||||
u = User(email="unannounced@example.com")
|
||||
db.add(u)
|
||||
db.flush()
|
||||
db.add(
|
||||
DownloadQuota(user_id=u.id, max_bytes=1000, max_concurrent=2, max_jobs=100, unlimited=False)
|
||||
)
|
||||
held = _sized_asset(db, 400, "unannounced-held")
|
||||
_job(db, u.id, queue_pos=0, status="done", asset_id=held.id)
|
||||
shared = MediaAsset(
|
||||
source_kind="youtube",
|
||||
source_ref="z" * 11,
|
||||
format_sig="s",
|
||||
status="downloading",
|
||||
ref_count=1,
|
||||
)
|
||||
db.add(shared)
|
||||
db.flush()
|
||||
mine = _job(db, u.id, queue_pos=1, status="running", asset_id=shared.id)
|
||||
db.commit()
|
||||
|
||||
def fetched_past_the_cap(job_id, asset_id, url, spec, staging, adapter, **kw):
|
||||
f = staging / "zzzzzzzzzzz.mp4"
|
||||
f.write_bytes(b"v" * 2000) # 600 left
|
||||
return {"id": "z" * 11, "requested_downloads": [{"filepath": str(f)}]}
|
||||
|
||||
monkeypatch.setattr(pipeline, "_extract_with_fallback", fetched_past_the_cap)
|
||||
monkeypatch.setattr(pipeline, "_ensure_phone_safe", lambda _j, produced, *_a: produced)
|
||||
pipeline._download(mine.id, shared.id, "youtube", "z" * 11, {}, u.id)
|
||||
|
||||
db.expire_all()
|
||||
job = db.get(DownloadJob, mine.id)
|
||||
assert (job.status, job.error_code, job.error) == (
|
||||
"error",
|
||||
"quota_exceeded",
|
||||
dlerrors.DOWNLOAD_TOO_BIG_MESSAGE,
|
||||
)
|
||||
asset = db.get(MediaAsset, shared.id)
|
||||
assert (asset.status, asset.rel_path) == ("pending", None)
|
||||
assert not any(p.suffix == ".mp4" for p in tmp_path.rglob("*") if "staging" not in p.parts)
|
||||
|
||||
Reference in New Issue
Block a user