232 lines
10 KiB
Markdown
232 lines
10 KiB
Markdown
# PhotoSync
|
||
|
||
> [!NOTIFY]
|
||
> This mod is mostly generated by Claude. Bug feedbacks are welcomed and they will get
|
||
> fixed and replied by human.
|
||
|
||
A Fabric client mod that sends your Minecraft screenshots to [Immich](https://immich.app)
|
||
and lets you browse the album back inside the game. This mod also supports periodic screenshooting.
|
||
|
||
Take a screenshot with F2 and it uploads in the background. Press F6 to see what
|
||
is uploading, scroll through the album's timeline, or change how any of it
|
||
behaves. Nothing about the vanilla screenshot flow changes — F2 still saves a PNG
|
||
to `screenshots/` and still works with the mod misconfigured or offline.
|
||
|
||
Supports **Minecraft 1.20 through 26.2**, client side only. Requires
|
||
[Fabric API](https://modrinth.com/mod/fabric-api). Sinytra connector should work.
|
||
|
||
| Photo Browser | Settings |
|
||
| - | - |
|
||
|  |  |
|
||
|
||
---
|
||
|
||
## Install
|
||
|
||
1. Install Fabric Loader 0.19.3 or newer and Fabric API for your Minecraft
|
||
version.
|
||
2. Drop the jar matching your version into `mods/`:
|
||
|
||
| Your Minecraft version | Jar |
|
||
| --- | --- |
|
||
| 1.20 – 1.20.1 | `photosync-1.20.1-1.0.0.jar` |
|
||
| 1.20.2 – 1.20.4 | `photosync-1.20.4-1.0.0.jar` |
|
||
| 1.20.5 – 1.20.6 | `photosync-1.20.6-1.0.0.jar` |
|
||
| 1.21 – 1.21.1 | `photosync-1.21.1-1.0.0.jar` |
|
||
| 1.21.2 – 1.21.4 | `photosync-1.21.4-1.0.0.jar` |
|
||
| 1.21.5 | `photosync-1.21.5-1.0.0.jar` |
|
||
| 1.21.6 – 1.21.10 | `photosync-1.21.8-1.0.0.jar` |
|
||
| 1.21.11 – 1.21.x | `photosync-1.21.11-1.0.0.jar` |
|
||
| 26.1 – 26.2 | `photosync-26.2-1.0.0.jar` |
|
||
|
||
Each jar declares its own supported range, so Fabric will refuse to load the
|
||
wrong one rather than crashing later.
|
||
|
||
3. Launch the game. PhotoSync does nothing until you connect it to a server.
|
||
|
||
The mod is client-side. Servers neither know nor care that you are running it,
|
||
and it works in single player.
|
||
|
||
## Connect it to Immich
|
||
|
||
Press **F6** (rebindable in Options → Controls → PhotoSync), open **Settings**,
|
||
and fill in two fields:
|
||
|
||
- **Server URL** — `https://photos.example.com`. Typing just `photos.example.com`
|
||
works too; so does pasting a URL that already ends in `/api`.
|
||
- **API key** — Immich's web UI, under Account Settings → API Keys. The field is
|
||
masked, and the key is never written to the log or copied to the clipboard.
|
||
|
||
Press **Test**. It reports the account name and server version on success, and
|
||
the actual failure on the way there — a wrong key and an unreachable host say
|
||
different things.
|
||
|
||
Then pick an **Album**. "Whole library" uploads without adding to any album; the
|
||
picker also creates one if you type a name and press Create. The chosen album is
|
||
both where uploads go and what the Browse tab shows.
|
||
|
||
Every upload carries a one-line description: the window title (which a modpack
|
||
replaces with its own name) and the server you were on, or "Singleplayer". It is
|
||
captured the moment the screenshot is taken, so an album mixed from several
|
||
clients or worlds stays tellable apart.
|
||
|
||
Settings save when you close the screen. **Revert** undoes everything since you
|
||
opened it.
|
||
|
||
## The screens
|
||
|
||
**Uploads** is the queue: everything still in flight plus the last hundred that
|
||
finished, newest first, each with its state — queued, uploading, retrying, done,
|
||
failed — and a preview of the selected one. Failed uploads get a **Retry**;
|
||
anything at all gets **Show in folder**, which opens `screenshots/` in your file
|
||
manager. **Remove** takes an entry out of the list without touching the file, and
|
||
**Clear finished** empties the completed ones in one go.
|
||
|
||
Uploads that fail retry on their own — five attempts by default, with the wait
|
||
doubling each time, so the last one comes 80 seconds after the fourth. Only the
|
||
final failure raises a corner message; the retries in between are visible here
|
||
for anyone who wants to watch them.
|
||
|
||
**Browse** is the album, newest first, with a heading per day. It loads the way a
|
||
photo website does: the per-day counts arrive before any image does, so the
|
||
scrollbar is honest about the album's real size from the first frame, and the
|
||
thumbnails for a day are fetched only when you scroll near them. Click a photo to
|
||
open it, Escape to go back. It is read-only — PhotoSync will not delete, move or
|
||
favourite anything on your server.
|
||
|
||
An opened photo is fetched at the largest size your server will serve — the
|
||
original if it has full-size renditions enabled, its 1440px preview otherwise.
|
||
The blur you see for the moment before it arrives is the thumbhash the timeline
|
||
already carried, and it says so while it is standing in, so a blur is never
|
||
mistaken for the photo.
|
||
|
||
Videos in the album show their preview frame with a video badge in the corner.
|
||
There is no playback; this is a screenshot mod.
|
||
|
||
**Settings** covers everything below.
|
||
|
||
## Automatic screenshots
|
||
|
||
Off by default, and it stays off until you turn it on. Once enabled, PhotoSync
|
||
takes a screenshot every five minutes (adjustable from 5 seconds to an hour) and
|
||
puts it through the same queue as a manual one.
|
||
|
||
- **Name suffix** — appended before `.png`, `_auto` by default, so an automatic
|
||
capture lands as `2026-08-07_14.31.02_auto.png` and is easy to spot or filter.
|
||
Leave it blank for none.
|
||
- **Only while in a world** — on by default. No point photographing the main menu.
|
||
- **Skip while a screen is open** — on by default. Your inventory is not a
|
||
landscape.
|
||
- **Skip if you have not moved** — on by default. A cycle is skipped when the
|
||
camera has been in the same place, looking the same way, for a whole interval:
|
||
that shot would be the previous one again. It resumes on its own the moment you
|
||
move or look somewhere else, so an afk stretch costs you one photo rather than
|
||
a hundred identical ones. The view is judged from the camera, so following
|
||
someone in spectator mode counts as moving.
|
||
|
||
Automatic captures are recorded separately from manual ones, so the two are
|
||
distinguishable everywhere they appear.
|
||
|
||
## Messages in the corner
|
||
|
||
One line, bottom left, gone in three seconds. Separately switchable for
|
||
screenshot taken, upload finished, and upload failed, with an adjustable
|
||
duration — the setting that suits an automatic capture every thirty seconds is
|
||
not the one that suits two screenshots an hour.
|
||
|
||
These draw on the in-world HUD, so they do not appear on the title screen or on
|
||
top of an open screen. An upload that finishes while you are looking at the
|
||
Uploads tab updates the list instead, which is better feedback than a toast.
|
||
|
||
## Quitting with uploads still running
|
||
|
||
If you quit while something is uploading, PhotoSync stops the shutdown and shows
|
||
a progress dialog: how many are left, and two buttons. **Keep playing** returns
|
||
you to the game. **Quit anyway** quits immediately.
|
||
|
||
Either way nothing is lost. The queue is on disk and is written through on every
|
||
state change, so unfinished uploads resume the next time you play — the dialog
|
||
exists to save you the wait, not to prevent a loss. An upload that was mid-flight
|
||
when the game died is simply tried again, and Immich recognises the retry as a
|
||
duplicate rather than storing a second copy.
|
||
|
||
You can turn the dialog off under Settings → Uploads → *Ask before quitting
|
||
mid-upload*, in which case the game gets a three-second grace period to finish
|
||
whatever is nearly done and then quits regardless.
|
||
|
||
## Everything else in Settings
|
||
|
||
| Setting | Default | |
|
||
| --- | --- | --- |
|
||
| Upload screenshots automatically | on | Off makes the mod a browser and a manual queue |
|
||
| Uploads at once | 2 | Up to 4 |
|
||
| Attempts before giving up | 5 | Up to 20 |
|
||
| Wait between attempts | 5s | Doubles each attempt: 5s, 10s, 20s, 40s |
|
||
| Delete the local file after upload | off | Only ever after the server confirms it |
|
||
| Thumbnail size | 96px | 48–192 |
|
||
| Thumbnails kept in memory | 256 | The mod's largest memory knob |
|
||
| Mark videos in the grid | on | |
|
||
|
||
## Files it writes
|
||
|
||
Everything lives in `config/photosync/` in your game directory:
|
||
|
||
- `photosync.json` — settings, including your API key. Back it up accordingly.
|
||
- `uploads.json` — the upload queue, so it survives a crash or a quit.
|
||
|
||
Screenshots themselves go where they always did, in `screenshots/`. PhotoSync
|
||
never moves them, and only deletes one if you asked it to and the upload was
|
||
confirmed.
|
||
|
||
## Troubleshooting
|
||
|
||
**"Not connected" on the Browse tab** — the server URL or API key is missing or
|
||
wrong. Settings → Test says which.
|
||
|
||
**Screenshots are taken but nothing queues** — either *Upload screenshots
|
||
automatically* is off, or there are no credentials yet. PhotoSync deliberately
|
||
does not queue against a server it cannot reach, because the result is a list of
|
||
failures you cannot act on.
|
||
|
||
**Thumbnails are blank in Browse** — Minecraft's image decoder reads PNG and JPEG
|
||
only, and Immich's default thumbnail format is WebP. PhotoSync notices on the
|
||
first tile and asks for JPEG previews instead for the rest of the session, so
|
||
this self-corrects on its own.
|
||
|
||
**An opened photo says it could not load** — close it and open it again, which
|
||
retries. If it fails every time, the log line says why; the usual cause is
|
||
Administration → Settings → Image → Preview format set to WebP on the server,
|
||
which nothing on this side can decode. Set it to JPEG.
|
||
|
||
**A jar refuses to load** — check the table above. Fabric enforces each jar's
|
||
declared version range, so this means the jar is for a different bucket.
|
||
|
||
## Building from source
|
||
|
||
```sh
|
||
./gradlew buildAllPlatforms
|
||
```
|
||
|
||
Jars land in `platform/<version>/build/libs/`. Nothing is shaded or bundled —
|
||
each jar is around 270 KB and contains only this mod's classes. To run one
|
||
version in a dev client:
|
||
|
||
```sh
|
||
./gradlew :platform:1.21.11:runClient
|
||
```
|
||
|
||
The source tree is one shared implementation plus nine thin per-version
|
||
adapters. If you are adding a Minecraft version or wondering why the layout is
|
||
the way it is, [`docs/PORTING.md`](docs/PORTING.md) is the document for that: it
|
||
covers the bucket scheme, the measured API breakpoints between every supported
|
||
version, and the procedure for a new release.
|
||
|
||
Adding a photo service other than Immich means implementing `PhotoProvider` and
|
||
`ProviderFactory` in `shared/core` and registering it with `ProviderCatalog`. No
|
||
UI or platform code needs to change — the settings screen builds its connection
|
||
fields from what the provider declares.
|
||
|
||
## Licence
|
||
|
||
MIT.
|