- Inside an album, SELECT cycles newest / oldest / file name A-Z / Z-A (natural, case-insensitive; name orders drop the month headers and L/R jump by initial letter). Asset originalFileName is now parsed. - Full-screen viewer: Triangle or the "Save to Vita" button downloads the original (falling back to Immich's full-size / preview JPEG) and exports it to the Photos app via ScePhotoExport (new src/export.c). The video downloader is now a generic download_to_file(). - R / L turn the whole viewer 90 degrees clockwise / counter-clockwise so the Vita can be held upright (new src/viewrot.c): it renders into a portrait render target drawn rotated, and maps d-pad, sticks and touch into the turned screen. Zoom moves to the right stick only. SCREEN_W/H are now variables for that logical screen. - Server & Backup page: album cover shape setting (vertical 3:4, square, panoramic 16:9), saved as covershape= in config.txt. - Test builds: "rup" holds the right stick up in test_input.txt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.7 KiB
📷 vitaImmich
Your self-hosted photo library, in your hands.
A native Immich client for the PlayStation Vita — browse, search and map your whole photo & video library over Wi‑Fi, play videos on the Vita's hardware decoder, and back up the camera roll, all on a 12‑year‑old handheld.
![]() |
![]() |
![]() |
| Timeline & search | Places map | Server & backup |
✨ Features
- 🗓️ Timeline — your entire library as a justified, date‑grouped grid (newest first), styled after the Immich web app.
- 🔍 Smart search — free‑text CLIP search straight from the Vita's keyboard.
- 🗺️ Places map — geotagged photos clustered on a world map; pan/zoom with the sticks and open any cluster as its own gallery.
- 🖼️ Full‑screen viewer — pinch/stick zoom & pan, swipe between photos, hardware‑accelerated H.264 video playback.
- ☁️ Camera‑roll backup — scans the Vita's photos & videos, dedupes against the server, and uploads on request.
- 📊 Server overview — storage usage, server/app versions, and per‑device backup status.
- 👆 Touch + buttons — the whole UI is drivable with the front touchscreen or the d‑pad/sticks.
Status: proof‑of‑concept. App title id
VIMM00001. See limitations.
📦 Requirements
- A PS Vita running HENkaku/h‑encore with VitaShell.
- A reasonably recent Immich server reachable over the Vita's Wi‑Fi.
- An Immich API key (web UI → Account Settings → API Keys), or an email/password.
🚀 Install & configure
-
Grab
vitaImmich.vpkfrom the latest release (or build it — see below) and install it with VitaShell. -
Launch it once; it creates
ux0:data/vitaimmich/config.txt. -
Edit that file (VitaShell's FTP, SELECT, makes this easy):
server=http://192.168.1.100:2283 apikey=your-immich-api-keyBehind a reverse proxy without NAT loopback? Pin the domain to your LAN IP so the Host header / TLS SNI stay on the domain but the connection goes straight to the server:
server=https://immich.example.com apikey=your-immich-api-key serverip=192.168.1.100 -
Relaunch.
🎮 Controls
Timeline
| Button | Action |
|---|---|
| D‑pad / sticks | Move selection (hold to repeat) |
| L / R | Jump a month up / down |
| △ | Smart search |
| X | Open full screen |
| 🗺️ / ☁️ (touch) | Open the Places map / server page |
| SELECT | Sync overview |
| START | Exit |
Albums
| Button | Action |
|---|---|
| D‑pad / drag | Move selection / scroll |
| X | Open the album |
| □ (or tap the search bar) | Search albums by name |
| SELECT (or tap the chip) | Sort: modified newest → oldest → name A‑Z → Z‑A |
| △ | Reload the album list |
| O | Clear the search, then back |
Cover shape — Vertical (3:4), Square or Panoramic (16:9) — is
picked on the Server & Backup page (L / R or tap) and saved as
covershape= in config.txt.
Inside an album
| Button | Action |
|---|---|
| SELECT | Order: newest → oldest → file name A‑Z → Z‑A (name orders drop the month headers) |
| L / R | Jump a month (or, sorted by name, an initial letter) |
| O | Back to the album list |
Places map
| Button | Action |
|---|---|
| Left stick / d‑pad / drag | Pan |
| Right stick / L · R | Zoom out / in |
| X | Open the centred cluster as a gallery |
| △ | Toggle the lat/lon graticule |
| O | Back |
Full‑screen viewer
| Button | Action |
|---|---|
| ← / → | Previous / next |
| R / L | Turn the viewer 90° clockwise / counter‑clockwise — hold the Vita upright and portrait photos fill the screen (d‑pad, sticks and touch follow the turn) |
| Right stick | Zoom · left stick pans |
| X | Play video / retry a failed load |
| △ (or tap "Save to Vita") | Save the photo to the Vita's Photos app (JPEG/PNG original, else Immich's full-size JPEG) |
| O | Back |
Video playback — X pause/resume · ←/→ seek ±10 s · O stop.
🔧 Building
Needs VitaSDK with libvita2d, curl, openssl,
zstd, zlib, libpng, libjpeg-turbo and freetype (install via vdpm).
export VITASDK=$HOME/vitasdk
export PATH=$VITASDK/bin:$PATH
cmake -B build -S .
cmake --build build # -> build/vitaImmich.vpk
The sources in src/ are a unity build: main.c #includes the section
files (state.c, draw.c, … app.c) into one translation unit, so only
main.c is compiled. The geotag map's base tiles live in assets/maptiles.pak,
generated from a world‑map image by tools/png_to_tiles.py.
☁️ Camera‑roll backup
On startup the app mounts the Photos app's storage (photo0: /
ux0:picture) plus ux0:video/CAMERA, scans for .jpg/.jpeg/.png/.mp4, and
merges those files into the same date‑sorted timeline as your server library. A
badge in each cell's corner shows status:
- 🔵 blue‑grey dot — cloud only
- 🔶 orange up‑arrow — local only
- 🟠 blinking — queued / uploading
- 🟢 green check — backed up (on both; shown once, as the server asset)
- 🔴 red dot — failed
A background thread SHA‑1‑hashes each local file and asks the server which
already exist (bulk-upload-check). Uploads never start on their own — open the
sync overview (SELECT) and press X to queue every local‑only file.
Tunables in config.txt: syncdir=<folder> (repeatable) and syncmaxmb=<MB>
(size cap; files over 512 MB are skipped by default, 0 disables).
⚠️ Limitations
- TLS verification is disabled (no CA bundle ships) — prefer plain HTTP on a trusted LAN, or treat HTTPS as unverified.
- Videos download in full to the memory card before playing (deleted after).
Playback is the Vita's hardware decoder via SceAvPlayer, so only MP4
(H.264/AAC) plays — Immich's transcoded
video/playbackstream is used. - Backup is one‑way (Vita → server);
deviceIdis hard‑coded to "PS Vita" and uploads aren't added to an album. - Thumbnails stream in one at a time on a background thread (grey placeholder until loaded); hashing the camera roll fills statuses in gradually.


