feat(immich): draw a server as a folder in the library

A saved Immich server is a node on the column beside the drives: no handle,
no picker — the key lives on the backend and the page only ever calls
`/api/immich/*` on its own origin. The dialog takes the address, the name and
the key, checks the key before storing anything, and offers the albums the key
can see; a blank tick list and a blank id field both mean every album. A share
key is one album and so has no picker.

`syncImmich` turns a server's albums into the shapes the tree already draws —
rows in `photos`, names in `walked` — so the column, the wall and the strip
need nothing new. The node's menu is the disk's menu minus what a server has
no disk for.

Also fixes `saveWalkedDirs` filling its noughts in before folding the keys:
a reading that spelled its keys the way it found them (a server's album
labels) had the lower-case spelling of a counted key written in as nought,
and the fold that settles the two spellings kept the nought.
This commit is contained in:
2026-10-10 16:16:37 +07:00
parent d2e2ebe108
commit e27998d820
9 changed files with 1529 additions and 60 deletions
+32
View File
@@ -336,6 +336,38 @@ export const en: Dict = {
'lib.repairRun': 'Repairing the library ({n} folders)…',
'lib.repairDone': 'Library repaired: {n} folders read back.',
// Immich (src/engine/immich.ts, src/ui/ImmichDialog.tsx, Library.tsx): one more
// source beside the folders on disk — a server the account keeps, read through
// the backend's own routes. The key never reaches this page.
'lib.immich.add': 'ADD IMMICH',
'lib.immich.title': 'ADD AN IMMICH SERVER',
'lib.immich.albumsChoose': 'CHOOSE ALBUMS',
'lib.immich.name': 'Name shown',
'lib.immich.nameHint': 'Leave blank to use the hostname',
'lib.immich.url': 'Server address',
'lib.immich.key': 'API key',
'lib.immich.keyShare': 'This is a share link, not an API key',
'lib.immich.keyCheck': 'CHECK THE KEY',
'lib.immich.checking': 'CHECKING…',
'lib.immich.perms':
'The API key needs all six read permissions: album.read, album.statistics, asset.read, asset.view, asset.download and asset.statistics.',
'lib.immich.ok': 'The key works.',
'lib.immich.albumsPick': 'Tick the albums to keep in the library. Ticking none means all of them.',
'lib.immich.albumIds': 'Or paste album IDs',
'lib.immich.albumIdsHint': 'One ID per line, or a whole …/albums/<id> address',
'lib.immich.noDownload': 'This key cannot download originals — frames can be viewed and graded from their previews only.',
'lib.immich.sync': 'READ AGAIN',
'lib.immich.disconnect': 'DISCONNECT',
'lib.immich.keep': 'REMOVE FROM LIBRARY',
'lib.immich.failed': 'This server could not be read.',
'lib.immich.auth': 'The key is wrong or too narrow.',
'lib.immich.unreachable': 'That address could not be reached.',
'lib.immich.serverErr': 'The server answered with something unusable.',
'lib.immich.invalid': 'An address and a key are both needed.',
'lib.immich.empty': 'This key sees no album.',
'lib.immich.added': 'Read {n} frames from {folder}.',
'lib.immich.hint': 'Right-click to read again, choose albums, disconnect or remove it from the library.',
'nav.admin': 'Admin',
'nav.photos': 'My photos',
'nav.profile': 'Profile',