- Share: a link that expired is never copied (the dialog and one-click Share pick a live one, else make one), says it expired, and the copy-on-open claim clears on the next copy. - A password-protected file link asks to open a file, not to watch a video. - Upload: Cancel, the close button or the backdrop while naming a folder makes no folder; a failed refetch keeps the target; a folder being made says so. - Crop: an infinite number is dropped, not a 500; an unprobed clip's size follows a shown-size crop; the edit_spec docs name frame_w/frame_h; the join and rotated paths are tested. - Auto-skip: the wait gives way on a marker too short for it, so the skip still fires. - Tag chips count the followed channels (subscribed_count) and a toggled chip keeps the focus. - Continue watching's See all sorts by last watched when in progress was already on.
149 lines
5.7 KiB
Python
149 lines
5.7 KiB
Python
"""A share link's address says what it opens: /watch/ a video, /file/ anything else, /folder/ a folder.
|
|
|
|
Only a word for the reader: the token is the key, so every path opens every link, and the links
|
|
already sent out on /watch/ keep working for good. DB-lane.
|
|
"""
|
|
|
|
import pytest
|
|
from cryptography.fernet import Fernet
|
|
|
|
from app import main, security
|
|
from app.config import settings
|
|
from app.downloads import og
|
|
from app.downloads import probe as probemod
|
|
|
|
_PAGE = """<!doctype html><html><head>
|
|
<!--OG:START--><meta property="og:title" content="Siftlode" /><!--OG:END-->
|
|
</head><body><script src="/assets/{entry}.js"></script></body></html>"""
|
|
|
|
_VIDEO = {
|
|
"streams": [
|
|
{"codec_type": "video", "codec_name": "h264", "pix_fmt": "yuv420p"},
|
|
{"codec_type": "audio", "codec_name": "aac"},
|
|
],
|
|
"format": {"format_name": "mov,mp4", "duration": "5"},
|
|
}
|
|
_AUDIO = {
|
|
"streams": [{"codec_type": "audio", "codec_name": "aac"}],
|
|
"format": {"format_name": "mov,mp4", "duration": "5"},
|
|
}
|
|
|
|
|
|
@pytest.fixture
|
|
def pages(tmp_path, monkeypatch):
|
|
index, watch = tmp_path / "index.html", tmp_path / "watch.html"
|
|
index.write_text(_PAGE.format(entry="app"), encoding="utf-8")
|
|
watch.write_text(_PAGE.format(entry="watch"), encoding="utf-8")
|
|
monkeypatch.setattr(main, "INDEX_HTML", index)
|
|
monkeypatch.setattr(main, "WATCH_HTML", watch)
|
|
|
|
|
|
@pytest.fixture
|
|
def key(monkeypatch):
|
|
"""A link's address is read back from its encrypted token."""
|
|
monkeypatch.setattr(security, "_fernet", Fernet(Fernet.generate_key()))
|
|
|
|
|
|
@pytest.fixture
|
|
def shared(as_user, make_user, tmp_path, monkeypatch, upload_headers):
|
|
"""Uploads a file ffprobe reads as `data` (None: it cannot read it) and shares it."""
|
|
monkeypatch.setattr(settings, "files_root", str(tmp_path / "media"))
|
|
owner = as_user(make_user())
|
|
|
|
def share(name: str, data: dict | None, **link: object) -> dict:
|
|
monkeypatch.setattr(probemod, "probe_json", lambda _p: data)
|
|
job = owner.post(
|
|
"/api/files/upload",
|
|
content=b"some bytes",
|
|
headers=upload_headers(name, display_name=name),
|
|
)
|
|
assert job.status_code == 200, job.text
|
|
made = owner.post(f"/api/downloads/{job.json()['id']}/links", json=link)
|
|
assert made.status_code == 200, made.text
|
|
return made.json()
|
|
|
|
share.owner = owner # type: ignore[attr-defined]
|
|
return share
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("name", "data", "prefix"),
|
|
[
|
|
("clip.mp4", _VIDEO, "/watch/"),
|
|
("song.m4a", _AUDIO, "/file/"),
|
|
("backup.tar.gz", None, "/file/"),
|
|
],
|
|
)
|
|
def test_a_link_is_given_out_on_the_path_of_what_it_opens(shared, name, data, prefix):
|
|
made = shared(name, data)
|
|
assert made["url"] == f"{prefix}{made['token']}"
|
|
|
|
|
|
def test_a_folder_link_is_given_out_on_folder(shared, key):
|
|
owner = shared.owner
|
|
folder = owner.post("/api/files/folders", json={"name": "Friends"}).json()
|
|
made = owner.post(f"/api/downloads/folders/{folder['id']}/links", json={}).json()
|
|
assert made["url"] == f"/folder/{made['token']}"
|
|
listed = owner.get(f"/api/downloads/folders/{folder['id']}/links").json()
|
|
assert [entry["url"] for entry in listed] == [made["url"]]
|
|
|
|
|
|
def test_the_list_gives_the_same_address_as_the_making(shared, key):
|
|
made = shared("backup.tar.gz", None)
|
|
owner = shared.owner
|
|
files = owner.get("/api/files").json()
|
|
job_id = next(f["id"] for f in files if f["display_name"] == "backup.tar.gz")
|
|
listed = owner.get(f"/api/downloads/{job_id}/links").json()
|
|
assert [entry["url"] for entry in listed] == [made["url"]]
|
|
|
|
|
|
@pytest.mark.parametrize("path", ["watch", "file", "folder"])
|
|
@pytest.mark.parametrize(
|
|
("name", "data"), [("clip.mp4", _VIDEO), ("backup.tar.gz", None)], ids=["video", "file"]
|
|
)
|
|
def test_every_path_opens_every_link(pages, shared, client, path, name, data):
|
|
"""The links already sent on /watch/ open whatever they open, for good."""
|
|
token = shared(name, data)["token"]
|
|
r = client.get(f"/{path}/{token}")
|
|
assert r.status_code == 200
|
|
assert "/assets/watch.js" in r.text and "/assets/app.js" not in r.text
|
|
assert f'content="{name}"' in r.text
|
|
|
|
|
|
@pytest.mark.parametrize("path", ["/file/no-such-token", "/folder/no-such-token", "/file/a/b"])
|
|
def test_a_new_path_without_a_live_link_still_gets_the_player(pages, client, path):
|
|
r = client.get(path)
|
|
assert r.status_code == 200
|
|
assert "/assets/watch.js" in r.text and "/assets/app.js" not in r.text
|
|
|
|
|
|
def test_a_card_names_a_file_as_a_file(shared, db):
|
|
made = shared("backup.tar.gz", None)
|
|
tags = og._watch_tags(made["token"], db)
|
|
assert f'{made["url"]}"' in tags
|
|
assert "video.other" not in tags
|
|
|
|
locked = shared("notes.tar.gz", None, password="pw")
|
|
hidden = og._watch_tags(locked["token"], db)
|
|
assert "Password-protected file" in hidden and "notes" not in hidden
|
|
assert "video.other" not in hidden
|
|
|
|
|
|
def test_a_card_of_a_video_stays_a_video(shared, db):
|
|
made = shared("clip.mp4", _VIDEO)
|
|
tags = og._watch_tags(made["token"], db)
|
|
assert f"/watch/{made['token']}" in tags and "video.other" in tags
|
|
locked = shared("other.mp4", _VIDEO, password="pw")
|
|
assert "Password-protected video" in og._watch_tags(locked["token"], db)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("name", "data", "video"),
|
|
[("clip.mp4", _VIDEO, True), ("song.m4a", _AUDIO, False), ("backup.tar.gz", None, False)],
|
|
)
|
|
def test_a_password_link_says_whether_it_opens_a_video(shared, client, name, data, video):
|
|
"""The lock screen asks to watch a video and to open anything else, whichever path it is on."""
|
|
token = shared(name, data, password="pw")["token"]
|
|
meta = client.get(f"/api/public/watch/{token}").json()
|
|
assert meta == {"needs_password": True, "kind": "file", "video": video}
|