Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions tests/test_refresh_listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,43 @@ async def test_refresh_picks_up_clips_added_between_calls(
]


async def test_refresh_updates_source_dir_when_clip_moves_to_ro(
db: Database,
) -> None:
"""If the user locks a clip mid-cycle the dashcam moves it
from /DCIM/Movie to /DCIM/Movie/RO. The next reconcile must
refresh source_dir on the existing row, otherwise the
download worker keeps hitting the stale path and 404s out
its retry budget."""
provider = MagicMock()
provider.get.return_value = _make_snap()
hub = Hub()
worker = SyncWorker(db, provider, hub)

with patch.object(worker, "_fetch_listing",
return_value=[_Rec("A.MP4", filepath="/DCIM/Movie")]), \
patch.object(worker, "_present_filenames", return_value=[]):
await worker._refresh_listing_and_reconcile()

with db.conn() as c:
row = c.execute(
"SELECT source_dir FROM download_queue WHERE filename='A.MP4'"
).fetchone()
assert row["source_dir"] == "/DCIM/Movie"

# User locks the clip; dashcam re-reports it under /RO.
with patch.object(worker, "_fetch_listing",
return_value=[_Rec("A.MP4", filepath="/DCIM/Movie/RO")]), \
patch.object(worker, "_present_filenames", return_value=[]):
await worker._refresh_listing_and_reconcile()

with db.conn() as c:
row = c.execute(
"SELECT source_dir FROM download_queue WHERE filename='A.MP4'"
).fetchone()
assert row["source_dir"] == "/DCIM/Movie/RO"


async def test_refresh_filters_by_ro_only_when_setting_on(
db: Database,
) -> None:
Expand Down
20 changes: 19 additions & 1 deletion web/services/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ def reconcile(
added = 0
marked_gone = 0
marked_done = 0
refreshed_source_dir = 0
with db.write() as c:
existing = {
row["filename"]: dict(row)
for row in c.execute(
"SELECT filename, state FROM download_queue"
"SELECT filename, state, source_dir FROM download_queue"
).fetchall()
}

Expand Down Expand Up @@ -115,6 +116,22 @@ def reconcile(
continue

if filename in existing:
# Locking a clip on the dashcam moves it from
# /DCIM/Movie to /DCIM/Movie/RO. The fresh listing
# carries the new path; refresh the queue row so
# the worker doesn't keep retrying the stale URL.
fresh_source = getattr(rec, "filepath", "") or ""
if (
fresh_source
and existing[filename]["source_dir"] != fresh_source
and existing[filename]["state"] in ("pending", "failed")
):
c.execute(
"UPDATE download_queue SET source_dir=? "
"WHERE filename=?",
(fresh_source, filename),
)
refreshed_source_dir += 1
continue

c.execute(
Expand Down Expand Up @@ -158,6 +175,7 @@ def reconcile(
"added": added,
"marked_gone": marked_gone,
"marked_done": marked_done,
"refreshed_source_dir": refreshed_source_dir,
}


Expand Down
Loading