Snapshots page shows empty when source JPGs are deleted after transcode #90

Closed
opened 2026-06-05 07:40:39 +00:00 by coding-agent-marvin8 · 1 comment
coding-agent-marvin8 commented 2026-06-05 07:40:39 +00:00 (Migrated from codeberg.org)

When a camera is configured with , the pipeline deletes all source snapshot files alongside the after transcoding completes. The route only searches , so it finds nothing and renders "No snapshots found" — even though a thumbnail copy survives in and is recorded in .

The static clip preview is served from the thumbnail copy just fine, so the "No snapshots found" message is clearly wrong whenever is set and the file exists.

When a camera is configured with , the pipeline deletes all source snapshot files alongside the after transcoding completes. The route only searches , so it finds nothing and renders "No snapshots found" — even though a thumbnail copy survives in and is recorded in . The static clip preview is served from the thumbnail copy just fine, so the "No snapshots found" message is clearly wrong whenever is set and the file exists.
coding-agent-marvin8 commented 2026-06-05 07:40:53 +00:00 (Migrated from codeberg.org)

Findings

The pipeline's delete path (pipeline.py _delete_source) removes both the .dav and every associated .jpg snapshot after transcoding when delete_after_transcode is enabled. The clip-snapshots route in src/cang/web/routes/snapshots.py only globs camera.root/day/channel/jpg and never consults clips.thumbnail. The thumbnail copy in output_dir is the only surviving snapshot but is never consulted.

Secondary: _snapshot_time in snapshots.py parses the second component with int(stem) while the Dahua adapter uses a leading-digits regex. If a filename has trailing non-digit characters the route silently drops the snapshot.

Plan of attack

  1. In the clip_snapshot_album and clip_snapshot_image route handlers, after collect_snapshots_for_clip returns empty, fall back to Path(clip[thumbnail]) if it is set and exists on disk.
  2. Extend the safety allow-list in clip_snapshot_image to also accept paths within cfg.server.output_dir (currently only camera_roots are allowed).
  3. Fix _snapshot_time to use a leading-digits regex like the adapter instead of int(stem).
  4. Add failing tests first (TDD) for all three changes, then implement.

Files changed: src/cang/web/routes/snapshots.py, tests/web/test_clip_snapshots.py, tests/test_snapshots.py

**Findings** The pipeline's delete path (pipeline.py _delete_source) removes both the .dav and every associated .jpg snapshot after transcoding when delete_after_transcode is enabled. The clip-snapshots route in src/cang/web/routes/snapshots.py only globs camera.root/day/channel/jpg and never consults clips.thumbnail. The thumbnail copy in output_dir is the only surviving snapshot but is never consulted. Secondary: _snapshot_time in snapshots.py parses the second component with int(stem) while the Dahua adapter uses a leading-digits regex. If a filename has trailing non-digit characters the route silently drops the snapshot. **Plan of attack** 1. In the clip_snapshot_album and clip_snapshot_image route handlers, after collect_snapshots_for_clip returns empty, fall back to Path(clip[thumbnail]) if it is set and exists on disk. 2. Extend the safety allow-list in clip_snapshot_image to also accept paths within cfg.server.output_dir (currently only camera_roots are allowed). 3. Fix _snapshot_time to use a leading-digits regex like the adapter instead of int(stem). 4. Add failing tests first (TDD) for all three changes, then implement. Files changed: src/cang/web/routes/snapshots.py, tests/web/test_clip_snapshots.py, tests/test_snapshots.py
Sign in to join this conversation.
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marvin8/cang#90
No description provided.