Files
pigway-frame-flow/docs/PHOTO_SOURCES.md
T

6.3 KiB
Raw Blame History

Photo sources

Photo sources are independent read-only providers. They never call a frame driver. SQLite persists source definitions and Scheduler jobs; passwords are not stored there. The shared DisplayService handles fitting, upload, idempotency, overrides and restore.

NAS local folder

Add the actual existing photo directory to .env:

NAS_PHOTOS_DIR=/volume2/photo
# Optional: existing NAS group allowed to read that folder (check its ACL).
# NAS_PHOTOS_GID=101

The path above is an example, not a detected directory. Enable the optional mount:

docker compose -f docker-compose.yml -f deploy/docker-compose.photos.yml config -q
docker compose -f docker-compose.yml -f deploy/docker-compose.photos.yml up -d

The folder is mounted read-only at /photos. The existing container user must already have read/traverse permission. If the Synology ACL grants a group access, set NAS_PHOTOS_GID to that existing group ID; the optional Compose overlay adds only container group membership, keeping UID 10333 and the photo bind mount read-only. Group 101 is a deployment example, not a universal default. Frame Flow does not change NAS permissions. Unreadable roots return an explicit HTTP 403 rather than an empty catalog. Missing host folders fail explicitly rather than being created automatically.

Open Gallery → Photo sources → Add source, choose NAS local folder, enter a relative folder (. for root or family for a subfolder). Supported formats: JPEG, PNG, WebP. Optional recursion excludes hidden directories, Synology @eaDir thumbnail trees, and symlinks. Original files remain unchanged.

WebDAV

Open Settings and allow the server hostname under Image URL hosts. Add a WebDAV source using a plain HTTPS directory URL on port 443. The implementation uses read-only PROPFIND Depth: 1 and GET, following RFC 4918. This version lists images immediately inside one folder; recursive WebDAV traversal is not supported. Basic authentication is supported; OAuth, SSO and Digest are not. Redirects, private-address endpoints and URL-embedded credentials are rejected.

For authentication, reference an environment variable such as FRAME_FLOW_SOURCE_CLOUD; set its value to a JSON object containing username and password, or set FRAME_FLOW_SOURCE_CLOUD_FILE to a mounted Secret file. Compose's env_file supplies the variable; a Secret file belongs in the existing /config mount with restricted permissions and container read access. Never commit credentials. The UI/API stores only the variable name.

Use

  • Browse photos returns paginated metadata (50 items/page), without fetching originals.
  • Preview random photo imports one selected photo into local Frame Flow storage; the frame remains unchanged. Display uses that exact previewed asset.
  • Schedule random photos creates a device-bound Cron job, paused by default. Each execution picks a random photo; ordinary random selection can repeat. Editing the job supports other schedule types, fitting/profile via advanced JSON, and the existing temporary override/restore options.
  • Sources can be edited, disabled or removed. Remove referencing jobs before deletion.

Metadata is cached for 60 seconds, with explicit refresh. Each catalog is limited to 10,000 supported images (not a complete inventory for larger folders). Maximum selected image size is 20 MiB; WebDAV XML responses are limited to 2 MiB. Preview imports use the existing local asset store; monitor disk space over time. Unreadable/invalid images fail the operation without retrying frame writes.

API

  • GET /api/v1/photo-sources
  • PUT /api/v1/photo-sources/{id} (admin)
  • DELETE /api/v1/photo-sources/{id} (admin)
  • GET /api/v1/photo-sources/{id}/images?offset=0&limit=50&refresh=false

Display or Scheduler content:

{"type":"photo_source","source_id":"family","fit":"contain","profile":"color"}

Optional item_id selects an exact catalog item. Omit it for random selection. The device upload endpoint accepts the same content with display_now=false (default) to import/preview locally. POST /api/v1/display performs the usual protected asynchronous device display. Schemas are in /openapi.json and /docs.

Native Aliyun Drive/Baidu Drive/Google Drive adapters are not implemented. A compatible WebDAV gateway or an independently managed NAS sync folder can be used. Frame Flow does not install a gateway or receive vendor API credentials automatically.

Date-folder captions / 整理照片文字

Enable Only photos in date-prefixed folders and Show folder caption below the photo when editing a source. Curated sources created by the UI increase the catalog limit to 100,000 photos; other sources default to 10,000. The API exposes catalog_limit explicitly. It remains a bounded catalog; reaching the limit is shown in the UI.

Example folder name: 20261005 家庭出游@示例地点. The image contains the photo and three separate caption lines:

家庭出游
2026-10-05
示例地点

Without @, the location line is omitted. Folder names support YYYYMMDD, YYYY-MM-DD, YYYY.MM.DD, and YYYY年MM月DD日, with calendar-valid dates. Subfolders inherit their nearest dated ancestor; image filenames and EXIF do not replace this curated date. Synology #recycle, hidden folders, and @eaDir are excluded. Extremely long captions shrink and then truncate visually; full values remain available in catalog metadata.

Output is 1200×1600: a 1200×1280 photo area plus a white caption area. Original files remain unchanged. Contain/cover/smart and color/grayscale profiles still apply. A prepared source definition is in deploy/organized-photos-source.json; use it with PUT /api/v1/photo-sources/organized-photos after mounting the library.

For Synology Photos shared libraries, synology_previews: true allows images over 20 MiB to use their existing @eaDir/<filename>/SYNOPHOTO_THUMB_XL.jpg preview. This is a read-only fallback: original files and Photos indexes remain unchanged, no thumbnails are generated on the NAS, and the ordinary size limit still applies to the selected preview. The catalog marks these entries provider_preview: true. If the preview is missing, the oversized original remains excluded. The folder caption still comes from the original curated directory.