◂ writeups // michaelz.dev

Photo Memories: phone → cloud → living-room TV

There's one feature every big-tech photo app sells you: that little "memories" reel that surfaces old photos and plays them back with a swell of music. I wanted that — but on my hardware, with my photos, playing on the actual television in my living room. No subscription, no cloud company, no algorithm deciding what I get to feel nostalgic about.

Turns out the pieces were all already running in my homelab. They just weren't talking to each other. This is the story of wiring them together — and the one design decision that made it actually pleasant to use.

The cast of characters

Three services, each great at one job:

  • Nextcloud — my self-hosted cloud. My phone auto-uploads every photo here. It's the memory.
  • Jellyfin — my media server, already pushing movies and shows to every TV with GPU transcoding. It's the screen.
  • Home Assistant — the brain that ties the apartment together. It's the glue.

The plan: photos land in Nextcloud, Jellyfin reads them as a photo library, and a single tap in Home Assistant plays the slideshow on the living-room TV.

The screenshot problem

Here's the thing nobody warns you about: my camera roll is mostly garbage. Screenshots of recipes. A photo of a parking sign so I'd remember where I left the car. Memes. A blurry picture of a router's MAC address sticker. If I pointed Jellyfin at my whole phone backup, "memories night" would be a slideshow of administrative trivia.

So the key decision was simple: don't show the camera roll. Show a curated album.

My partner and I already share a "Delade Foton" ("Shared Photos") album in Nextcloud — the stuff we both actually want to keep. Jellyfin reads only that folder. The screenshots never leave the phone. The memories library is, by construction, only the good stuff.

The best filter isn't an AI that guesses what matters. It's a folder you both chose to put things in.

Letting Jellyfin read Nextcloud's files

Nextcloud owns its data on disk. Jellyfin runs in its own unprivileged container. The trick is a read-only bind mount: the shared-album folder is mounted into Jellyfin's container as read-only, so Jellyfin can see the photos but physically cannot change them.

mp4: /…/nextcloud/data/<user>/files/📸 Delade Foton → /media/memories (ro=1)

One small gotcha: because the container is unprivileged, the user IDs don't line up — the files show up owned by "nobody". That's fine, as long as they're world-readable, which they were. Jellyfin happily indexed them into a new library called Minnen ("Memories"), and just like that, the photos were on every screen in the house.

The one-tap part

Browsing to the library and hitting play is fine. But the dream was a single button. The problem: a Chromecast can't render a custom slideshow card, so I couldn't just "cast a webpage" of photos.

The answer was Jellyfin's own remote-control API. The Jellyfin app on the Android TV already has an open session, and that session advertises that it supports media control. So the flow became:

  1. A button in Home Assistant launches the Jellyfin app on the chosen TV.
  2. A small script waits for the app's session to register, then sends a PlayNow command with the album's items.
  3. The TV starts the slideshow. No remote, no navigating menus.

Pick a TV from a dropdown, tap "Minnen på TV", and the living room fills with photos.

Why bother?

Because it's mine. The photos sit on drives I can hold. The "algorithm" is a folder my partner and I curate together. Nothing phones home. And on a quiet evening, one tap turns the TV into a window onto a few years of good moments — rendered by the same little box that runs the rest of the apartment.

That's the whole pitch for self-hosting, really. Not that it's cheaper or easier (it is neither). It's that the thing you build is yours, and it does exactly what you wanted — screenshots of parking signs firmly excluded.

Comments

◂ all writeups michaelz.dev ▸