Synology Photos “on this day” reminders delivered through Apprise.
Memories picks a photo taken on this day in past years from your Synology Photos library and sends it to you through Apprise (SMS/MMS, Push, Email, Discord, etc.). Wake up to a little nostalgia ☕📸
- ✨ Smart photo weighting – Prioritizes favorites, faces, and photos with rich EXIF data so the best memories surface first.
- 📸 Burst smoothing – Detects rapid-fire shots and picks a single representative image to avoid spammy notifications.
- 🔄 Thoughtful rotation – Previously shared photos take a gentle score penalty, keeping fresh shots in the lead while still letting beloved ones return occasionally.
- 🎉 Apprise integration – Sends through Apprise, unlocking SMS, email, Discord, Pushbullet, Matrix, and every other channel Apprise supports.
- 📦 Docker-friendly – Ships as a small Node.js container with environment-driven configuration—drop straight into Synology Container Manager’s Project editor and go.
- A Synology NAS with DSM and Synology Photos enabled.
- Container Manager (Docker) on your NAS.
- Either:
- An existing Apprise API server you can point to, or
- Run Apprise API alongside Memories
- DSM → Control Panel → User & Group → add a user like
memories. - Give it read-only access to the shared folders where your Photos live.
When prompted, choose Create using docker‑compose, then copy and paste one of the examples below directly into the editor. Adjust the values for your environment, then click Next to deploy.
services:
memories:
image: ghcr.io/hursey013/memories:latest
restart: unless-stopped
environment:
# --- Synology connection ---
NAS_IP: "your-nas-host-or-ip" # Reachable host/IP for Synology Photos (HTTPS)
USER_ID: "memories" # DSM username with read access to your photos
USER_PASSWORD: "supersecret" # Password for that DSM account
FOTO_TEAM: "false" # Set to "true" when using Synology Team folders
# --- Behavior & filtering ---
FAVORITE_PEOPLE: "" # Optional comma-separated list to prioritize
IGNORED_PEOPLE: "" # Optional comma-separated list to skip completely
MIN_YEAR: "2000" # Ignore photos taken before this year
YEARS_BACK: "0" # Limit to this many years back (0 = no limit beyond MIN_YEAR)
DAY_OFFSET: "-1" # Shift the queried calendar day (helps timezones)
MIN_WEIGHT: "3" # Minimum score a photo must reach to be considered
REPEAT_PENALTY: "3" # Points to subtract for each time a photo was already sent
REPEAT_PENALTY_CAP: "12" # Optional ceiling so classics can still bubble up
# --- Observability ---
HEALTHCHECKS_PING_URL: "" # Optional healthchecks.io project URL for uptime pings
# --- Scheduling (omit to run once and exit) ---
CRON_EXPRESSION: "0 9 * * *" # Run every day at 9:00 AM
# --- Apprise (existing server) ---
APPRISE_URL: "http://your-apprise-api:8000"
APPRISE_KEY: "" # Provide if your Apprise API is keyed
# OR stateless direct URLs (skip APPRISE_URL if using this):
# APPRISE_URLS: "discord://webhook_id/webhook_token,mailto://[email protected][email protected]"
# --- Timezone ---
TZ: "America/New_York" # Keeps cron/log output aligned with your morning
volumes:
- ./cache:/app/cacheservices:
apprise-api:
image: lscr.io/linuxserver/apprise-api:latest
environment:
PUID: "1026" # adjust to your DSM user/group if needed
PGID: "100"
TZ: "America/New_York"
volumes:
- ./apprise-config:/config
- ./apprise-attachments:/attachments
ports:
- "8000:8000"
restart: unless-stopped
memories:
image: ghcr.io/hursey013/memories:latest
depends_on:
- apprise-api
restart: unless-stopped
environment:
# --- Synology connection ---
NAS_IP: "your-nas-host-or-ip" # Reachable host/IP for Synology Photos (HTTPS)
USER_ID: "memories" # DSM username with read access to your photos
USER_PASSWORD: "supersecret" # Password for that DSM account
FOTO_TEAM: "false" # Set to "true" when using Synology Team folders
# --- Behavior & filtering ---
FAVORITE_PEOPLE: "" # Optional comma-separated list to prioritize
IGNORED_PEOPLE: "" # Optional comma-separated list to skip completely
MIN_YEAR: "2000" # Ignore photos taken before this year
YEARS_BACK: "0" # Limit to this many years back (0 = no limit beyond MIN_YEAR)
DAY_OFFSET: "-1" # Shift the queried calendar day (helps timezones)
MIN_WEIGHT: "3" # Minimum score a photo must reach to be considered
REPEAT_PENALTY: "3" # Points to subtract for each time a photo was already sent
REPEAT_PENALTY_CAP: "12" # Optional ceiling so classics can still bubble up
# --- Observability ---
HEALTHCHECKS_PING_URL: "" # Optional healthchecks.io project URL for uptime pings
# --- Scheduling (omit to run once and exit) ---
CRON_EXPRESSION: "0 9 * * *" # Run every day at 9:00 AM
# --- Apprise (bundled server) ---
APPRISE_URL: "http://apprise-api:8000"
APPRISE_KEY: ""
# OR stateless direct URLs (skip APPRISE_URL if using this):
# APPRISE_URLS: "discord://webhook_id/webhook_token,mailto://[email protected][email protected]"
# --- Timezone ---
TZ: "America/New_York"
volumes:
- ./cache:/app/cacheThat’s it! Each run picks a “this day in history” item from your Synology Photos and sends it via Apprise.
Every photo gets a “nostalgia score.” Higher numbers win, and anything below your MIN_WEIGHT value is skipped. Here’s the cheat sheet:
| Signal | Score impact |
|---|---|
| Favorites (your “VIPs”) | +5 each (cap +10) |
| Named people (user curated) | +2 each (cap +8) |
| Face count | +1 per face (cap +4) |
| Unnamed faces | −1 each (cap −3) |
| EXIF present / camera model | +1 / +3 |
| No EXIF metadata at all | −4 |
| Already sent before | −REPEAT_PENALTY each time (cap −REPEAT_PENALTY_CAP) |
| Date nostalgia: 3–10 years old | +2 |
| Date nostalgia: 10–20 years old | +1 |
| Tie-breaker jitter | +0 to +0.25 |
Each time a photo gets delivered, its base score is reduced by REPEAT_PENALTY
(default 3) on future runs. That reduction stacks until it reaches the optional
REPEAT_PENALTY_CAP (default 12), keeping repeats in circulation but making
room for fresher shots to win first.
It’s an open-source notification router that can fan out a message to over 90 services—SMS gateways, email, Slack, Pushbullet, Discord, Matrix, you name it. Memories just needs the Apprise API to be running somewhere it can reach.
- Spin up the API. Easiest path: use the bundled compose example above. The container listens on port 8000 by default.
- Decide on auth.
- Stateful mode (recommended): add a Key inside the Apprise web UI and provide it via
APPRISE_KEY. This keeps your targets hidden server-side. - Stateless mode: skip the key and provide one or more target URLs in
APPRISE_URLS(comma-separated), e.g.discord://webhook/token,mailto://[email protected].
- Stateful mode (recommended): add a Key inside the Apprise web UI and provide it via
- Add services. Browse the Apprise notification support matrix to copy the right URL format for each service you want (Discord, Telegram, Pushover, etc.). If you’re using stateful mode, add these targets in the Apprise UI. For stateless mode, paste them directly into
APPRISE_URLS. - Test it. Hit your Apprise API’s
/notifyendpoint manually or runcurlwith a simple payload to confirm you get pinged. Once that works, Memories will reuse the same setup each morning.
Need more detail? The Apprise docs include step-by-step guides for every integration and a handy command-line utility for testing locally: https://github.com/caronc/apprise
This project was inspired by treyg/synology-photos-memories and also benefits from the excellent work documenting Synology’s unofficial API by zeichensatz/SynologyPhotosAPI.