fix: review round 1 — row press after a rename, related reset, dead items on removal, honest Prev/Next
- A press that begins while a field in the row is edited only ends the editing (rowOpen latches it at pointerdown); the card layout's row press is now tested. - A related video reset in the player forgets the session's stored position. - Removing the playing video passes over known-dead items and steps the way it went. - Prev/Next off only because of dead items stay focusable and say why (HU/EN). - The docked bar's scroller leaves room for focus rings. - A focus-opened About card is not closed by its own scroll into view. - EN "Clear watch progress" for the video reset, distinct from a page's "Reset view". - The signed-out title read goes to the page yt-dlp read; the retitle writes are conditional. - Tests: the cap of three errors, the bar's own Fullscreen, the group glyph, the backfill's reads.
This commit is contained in:
@@ -6,11 +6,18 @@ no post text to fall back on, and the download name copied the placeholder too.
|
||||
the same reel (yt-dlp 2026.08.19, as on prod) still carries the post's text in its description.
|
||||
"""
|
||||
|
||||
import threading
|
||||
|
||||
from sqlalchemy import update
|
||||
|
||||
from app.config import settings
|
||||
from app.db import SessionLocal
|
||||
from app.downloads import adapters, backfill, pipeline
|
||||
from app.downloads.models import DownloadJob, MediaAsset
|
||||
|
||||
_URL = "https://www.facebook.com/reel/1860682468422402/"
|
||||
# The page yt-dlp says it read for it (`webpage_url`); a group post's link resolves the same way.
|
||||
_PAGE = "https://www.facebook.com/watch/?v=1860682468422402"
|
||||
# The measured signed-out read of that reel.
|
||||
_PUBLIC = {
|
||||
"title": "163K reactions · 14K shares | sorry not helping #workhumor #officelife | Work dot exe",
|
||||
@@ -20,12 +27,13 @@ _PUBLIC = {
|
||||
|
||||
|
||||
def _fake_ydl(monkeypatch, outcome):
|
||||
"""yt-dlp faked at its `YoutubeDL` boundary: records each read's options, answers `outcome`."""
|
||||
"""yt-dlp faked at its `YoutubeDL` boundary: records each read (its options and its `url`),
|
||||
answers `outcome`."""
|
||||
seen: list[dict] = []
|
||||
|
||||
class FakeYDL:
|
||||
def __init__(self, opts):
|
||||
seen.append(opts)
|
||||
self.opts = opts
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
@@ -34,6 +42,7 @@ def _fake_ydl(monkeypatch, outcome):
|
||||
return False
|
||||
|
||||
def extract_info(self, url, download):
|
||||
seen.append({**self.opts, "url": url})
|
||||
return outcome
|
||||
|
||||
monkeypatch.setattr(backfill.yt_dlp, "YoutubeDL", FakeYDL)
|
||||
@@ -61,6 +70,14 @@ def test_a_real_title_reads_nothing_more(monkeypatch):
|
||||
assert seen == []
|
||||
|
||||
|
||||
def test_a_placeholder_with_the_posts_text_behind_it_reads_nothing_more(monkeypatch):
|
||||
seen = _fake_ydl(monkeypatch, _PUBLIC)
|
||||
info = {"title": "Video", "description": "Office jokes, part two"}
|
||||
|
||||
assert backfill.public_title_info(info, _URL, adapters.FacebookAdapter(), 7) is info
|
||||
assert seen == []
|
||||
|
||||
|
||||
def test_a_placeholder_the_signed_out_page_cannot_better_stays(monkeypatch):
|
||||
_fake_ydl(monkeypatch, {"title": "Facebook", "description": None})
|
||||
fb = adapters.FacebookAdapter()
|
||||
@@ -81,7 +98,7 @@ def test_another_source_is_never_read_again(monkeypatch):
|
||||
def test_the_backfill_retitles_a_placeholder_download_and_the_names_that_repeated_it(
|
||||
db, make_user, monkeypatch
|
||||
):
|
||||
_fake_ydl(monkeypatch, _PUBLIC)
|
||||
seen = _fake_ydl(monkeypatch, _PUBLIC)
|
||||
owner, other = make_user(), make_user()
|
||||
asset = MediaAsset(
|
||||
source_kind="url",
|
||||
@@ -120,6 +137,7 @@ def test_the_backfill_retitles_a_placeholder_download_and_the_names_that_repeate
|
||||
db.commit()
|
||||
|
||||
assert backfill.run()["retitled"] == 1
|
||||
assert len(seen) == 1
|
||||
|
||||
db.expire_all()
|
||||
assert db.get(MediaAsset, asset.id).title == "sorry not helping"
|
||||
@@ -127,6 +145,66 @@ def test_the_backfill_retitles_a_placeholder_download_and_the_names_that_repeate
|
||||
assert db.get(DownloadJob, renamed.id).display_name == "Office jokes"
|
||||
# Run again: nothing left to retitle, and no page read for it.
|
||||
assert backfill.run()["retitled"] == 0
|
||||
assert len(seen) == 1
|
||||
|
||||
|
||||
def test_a_name_given_while_the_backfill_runs_stays(db, make_user, monkeypatch):
|
||||
# The owner renames the download between the backfill's retitle and its commit (the poster step
|
||||
# sits between them): the owner's name wins, it is not overwritten by what was read before it.
|
||||
_fake_ydl(monkeypatch, _PUBLIC)
|
||||
owner = make_user()
|
||||
asset = MediaAsset(
|
||||
source_kind="url",
|
||||
source_ref=_URL,
|
||||
format_sig="fb",
|
||||
status="ready",
|
||||
rel_path="facebook/x.mp4",
|
||||
uploader_url="https://www.facebook.com/1",
|
||||
title="Facebook",
|
||||
ref_count=1,
|
||||
)
|
||||
db.add(asset)
|
||||
db.flush()
|
||||
job = DownloadJob(
|
||||
user_id=owner.id,
|
||||
asset_id=asset.id,
|
||||
source_kind="url",
|
||||
source_ref=_URL,
|
||||
status="done",
|
||||
queue_pos=0,
|
||||
profile_snapshot={},
|
||||
display_name="Facebook",
|
||||
)
|
||||
db.add(job)
|
||||
db.commit()
|
||||
|
||||
def rename():
|
||||
with SessionLocal() as other:
|
||||
other.execute(
|
||||
update(DownloadJob)
|
||||
.where(DownloadJob.id == job.id)
|
||||
.values(display_name="Office jokes")
|
||||
)
|
||||
other.commit()
|
||||
|
||||
def poster_while_renamed(a, root):
|
||||
# A rename that must wait for the backfill's write waits here, and lands after its commit.
|
||||
t = threading.Thread(target=rename)
|
||||
t.start()
|
||||
t.join(timeout=0.5)
|
||||
renamers.append(t)
|
||||
return None
|
||||
|
||||
renamers: list[threading.Thread] = []
|
||||
monkeypatch.setattr(backfill.editmod, "ensure_poster", poster_while_renamed)
|
||||
|
||||
assert backfill.run()["retitled"] == 1
|
||||
for t in renamers:
|
||||
t.join(timeout=10)
|
||||
assert not t.is_alive()
|
||||
|
||||
db.expire_all()
|
||||
assert db.get(DownloadJob, job.id).display_name == "Office jokes"
|
||||
|
||||
|
||||
def test_a_download_titled_facebook_is_named_from_the_signed_out_page(
|
||||
@@ -134,7 +212,7 @@ def test_a_download_titled_facebook_is_named_from_the_signed_out_page(
|
||||
):
|
||||
# The whole download path with yt-dlp and the media tools faked: the signed-in read gives only
|
||||
# the placeholder, and the file and the download's name get the post's text.
|
||||
_fake_ydl(monkeypatch, _PUBLIC)
|
||||
seen = _fake_ydl(monkeypatch, _PUBLIC)
|
||||
monkeypatch.setattr(settings, "files_root", str(tmp_path))
|
||||
monkeypatch.setattr(pipeline.urlguard, "check_url", lambda url: None)
|
||||
monkeypatch.setattr(pipeline, "_ensure_phone_safe", lambda _j, produced, *_a: produced)
|
||||
@@ -168,12 +246,16 @@ def test_a_download_titled_facebook_is_named_from_the_signed_out_page(
|
||||
"id": "1860682468422402",
|
||||
"title": "Facebook",
|
||||
"uploader": "Work dot exe",
|
||||
"webpage_url": _PAGE,
|
||||
"requested_downloads": [{"filepath": str(f)}],
|
||||
}
|
||||
|
||||
monkeypatch.setattr(pipeline, "_extract_with_fallback", signed_in_read)
|
||||
pipeline._download(job.id, asset.id, "url", _URL, {}, owner.id)
|
||||
|
||||
# The signed-out read goes to the page yt-dlp read, not the link queued: a group post's link
|
||||
# resolves to its video, and signed out the post itself is the login wall.
|
||||
assert [r["url"] for r in seen] == [_PAGE]
|
||||
db.expire_all()
|
||||
assert db.get(DownloadJob, job.id).status == "done"
|
||||
assert db.get(MediaAsset, asset.id).title == "sorry not helping"
|
||||
|
||||
@@ -579,7 +579,7 @@ def _display_write_sites() -> dict[tuple[str, str], set[str]]:
|
||||
# enqueue_clip slices the source's title to the same width.
|
||||
# files.ingest_spooled passes through `spool_upload`'s value, bounded there.
|
||||
# routes enqueue_clip the `display_name=` keyword passes on the name bound above it.
|
||||
# pipeline._download / _process_clip / worker._finish_from_cache
|
||||
# pipeline._download / _process_clip / worker._finish_from_cache / backfill._retitle
|
||||
# slice a fetched or stored title to the column's width.
|
||||
#
|
||||
# Held as EXACT EQUALITY rather than as a list of offenders. The offender form could only fail
|
||||
|
||||
Reference in New Issue
Block a user