diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-09 18:23:52 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-09 18:23:56 +0200 |
| commit | 25152ddb61a89ea3ea29d3aef5de13343429d32a (patch) | |
| tree | ebf8f11f66146caaa3c01270cd6cfcb0ee51723c /docs | |
| parent | c85c7f48e8f29923038d4c90cc1a6f9b8bcd7673 (diff) | |
| download | meshbay-25152ddb61a89ea3ea29d3aef5de13343429d32a.tar.gz | |
feat: back up the phone's photos to a group, once a day on Wi-Fi
The Android application sends the photos taken on the phone to one folder of
one group chosen by the member (docs/MESHBAY_DESIGN.md §9.12). The phone lists
MediaStore, keeps a ledger of what was sent and hands each photo's bytes to the
page by an opaque token on the packaged origin; the page decides when a run is
due and uploads through the existing path, one photo at a time under a slot.
- Once a day from the last finished run, on an unmetered network only;
"Back up now" asks first on mobile data. Leaving Wi-Fi stops after the file
in flight.
- Photos already on the phone are sent by default, newest first, under
<folder>/YYYY/MM; edits are sent beside the original as -edited-<date>.
- Additive by construction: nothing is ever deleted, renamed or replaced on
the node, and a photo deleted on the node is not sent again.
- A confirmation names the group, owner, members, folder and size when the
destination or starting point changes; a lasting refusal (disk full, folder
read-only or gone, no longer a member) is said once and retried a day later.
- No ACCESS_MEDIA_LOCATION, so the platform redacts photo locations.
- A dataSync foreground service keeps a run going with the screen off.
HEIC/HEIF photos are sent but not shown in Photos yet (§15.2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/MESHBAY_DESIGN.md | 88 | ||||
| -rw-r--r-- | docs/USERGUIDE.md | 37 |
2 files changed, 124 insertions, 1 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index 47fe62a..06ccaca 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -3323,6 +3323,88 @@ are two albums. --- +### 9.12 Photo backup (Android) + +The Android application sends the photos taken on the phone to **one folder of +one group**, chosen by the member, once a day. It is a client feature over the +upload path that exists: a backed-up photo is a `file_upload` into a writable +root under a slot the node granted, with every rule of §6.4, and its owner is +recorded as for any upload. **No message, no node state and no hub state was +added for it**; the node cannot tell a backed-up photo from one sent by hand, +and does not need to. + +**Split.** The phone (`photos/` in the Android package, reached as +`platform.photoSync`) lists the photos through MediaStore, keeps the ledger and +hands the bytes over. The page (`photo-sync.js`) decides when a run is due and +does the sending, because the transport and the group key are there. Bytes +cross by an opaque token the page fetches from its own origin, +`/photosync/<token>`, served by the shell's request interception: valid for the +run that issued it and for the one photo it names. The page never receives a +`content://` URI. A browser and the desktop have no camera roll and no such +object — absent, not refusing (§11.3). + +**When.** A run is due 24 hours after the last run that *finished*; an +interrupted one is retried at the next chance, at most every fifteen minutes. +Due-ness is checked at start, on return to the foreground, when the network +turns unmetered, and by one timer at the due time — nothing polls. A scheduled +run needs an **unmetered** network (`NET_CAPABILITY_NOT_METERED`, not "Wi-Fi": +a phone on another phone's hotspot is on Wi-Fi and spending that phone's data). +"Back up now" runs whenever; on a metered network it first states the count and +size and asks — the one confirmation in this feature that is not about where +the photos go. Turning metered mid-run stops after the file in flight; the +node's partial upload resumes it (§8.5). + +**One photo at a time, under a slot.** Each upload asks for a transfer slot +like a member sending by hand and gives it back, so a family's daily backups +never occupy the node's upload pool ahead of a person. + +**Where.** The member chooses the group (one per phone) and a folder among +those that are writable, available and shown by the group's Photos tab — a +folder outside those would take the photos and show them nowhere. Inside it, +each photo goes under `YYYY/MM` from when it was taken, because an album is a +directory (§9.9) and one folder of twenty thousand is a slow album. Albums on +the phone are chosen too; the camera alone is the default, because screenshots +and saved images are where photos nobody meant to share live. **By default the +photos already on the phone are sent, newest first**, then each new one; "from +now on" is an option. A confirmation is drawn **when the destination or the +starting point changes, never per run and never for a change of albums alone**: +it names the group, its owner, its member count, the folder, the count and size +about to go, and says that members can download them and that what they +downloaded cannot be taken back. + +**Additive by construction.** The backup never deletes, renames or replaces +anything on the node: `photo-sync.js` reaches no such operation +(`test_photo_sync.py` reads it for them). **The ledger is the memory of what was +sent, never a mirror of the phone**: per (account, group, folder), each photo's +MediaStore id, modification date, size, the SHA-256 of the bytes sent and the +name the node's ack gave. A run sends what the ledger lacks and never compares +the other way, so a photo deleted on the phone stays in the group, and one +deleted on the node is not sent again. An empty ledger (a reinstall) is +reconciled against the folder by name and size before anything is sent. + +**Edits.** A photo edited in place keeps its id and changes its modification +date; when the size also changed, or the bytes no longer hash to what was sent, +the edit is sent **beside the original**, as `<stem>-edited-<YYYYMMDD-HHMMSS>.<ext>` +from the edit's date. A touch that left the bytes alone sends nothing. "Save as +copy" makes a new photo and needs no rule. + +**Location.** The manifest does not ask for `ACCESS_MEDIA_LOCATION`, so a +photo read through MediaStore has its EXIF location **redacted by the +platform**: a camera roll going to a group does not say where its owner lives, +and nobody had to do anything for it. + +**Refusals.** A refusal that will hold tomorrow — `disk_full` (§6.4), a folder +no longer writable, gone or on a drive that is not plugged, the member removed +from the group, the photo permission withdrawn — stops the run, is said once in +a notification and in Settings, and is retried a day later rather than at every +opening. Anything else (the node offline, the network gone) is an interruption +and is retried. + +**Screen off.** The sending lives in the page, so a run holds a `dataSync` +foreground service (`BackupService`) and the WebView reported visible, like a +cast (§11.3). Android 15 limits that type to six hours a day; the service stops +when told and the run carries on at the next opening. + ## 10. Filesystem portability **exFAT and NTFS on Windows are the common case, not an edge case.** Most users are @@ -3457,7 +3539,8 @@ narrow bridge — and Android has all three: locks and the renderer's priority policy do not prevent it. A cast's pipeline lives in the page (WebRTC → decrypt → relay), so while one runs the shell keeps the WebView reported visible and holds a media-playback foreground - service; nowhere else, because a page never hidden is never throttled. + service. A photo backup does the same with a `dataSync` service of its own + (§9.12); nowhere else, because a page never hidden is never throttled. - **Notifications reach a closed application with nothing to install, and never through a vendor push service.** Android lets nothing hold a connection for an application that is not running, so there are three ways to wake a @@ -4048,6 +4131,7 @@ seeking, audio-language and subtitle selection, transfer leases with queueing, pause and resume, the group-application framework with Chat, Files, Videos, Music and Photos, cross-group search with source merging, per-account playlists, casting to a Chromecast with subtitles rebased onto the relay's clock, the +phone's photo backup (§9.12), the operator CLI and loopback control API, the desktop client through its identity and download stages, account recovery, the Windows port through packaging, and the Android client — the shell, native keys, downloads and uploads, casting, @@ -4079,6 +4163,8 @@ process runs it — `systemctl --user` on Linux, Task Scheduler on Windows. | — | **Bitmap subtitles** (PGS, VOBSUB — about a fifth of the embedded streams). No WebVTT without OCR; they are not listed rather than listed and blank. Burn-in covers them and costs `-c:v copy`, which is what the eight-slot sizing assumes never happens | | — | Delegation (§3.4) | | — | Tier 3 roster attestation (§3.3) | +| — | **HEIC/HEIF in Photos.** The indexer does not classify `.heic`/`.heif` as images and no browser but Safari draws them, so a phone that shoots HEIC has its backed-up photos stored and listed in Files but absent from Photos. Needs `pillow-heif` in every package and a JPEG rendition for the viewer (§9.12) | +| — | **Photo backup with the application closed**, and **"remove what this phone sent"** (§9.12). A closed application has no page and so no transport; it runs at the next opening | | — | **Android: phone behaviour and release** — the back button driving the page, recovery from a network handover, keeping a download alive with the screen off, lock-screen media controls, and an update channel (§11.3) | | — | **Federation between two hubs.** The protocol is written and switched off in the code (§7.6); what is not built is one run between two machines | diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md index 7afb77b..74dae15 100644 --- a/docs/USERGUIDE.md +++ b/docs/USERGUIDE.md @@ -378,6 +378,37 @@ coordinates are still inside the photo itself, as your phone wrote them, so anyone who downloads the original file has them. Strip them before sharing if that matters to you. +### Backing up your phone's photos + +On the Android application, **Settings → Photo backup** sends the photos taken +on your phone to a folder of one of your groups, once a day. + +- **Set up** asks for access to your photos, then for a group, a folder and the + albums to send. Only folders you may add to and that the group's Photos tab + shows are offered. The camera is ticked; screenshots and other albums are + yours to add. +- By default **the photos already on the phone are sent too**, newest first, + then each new one. Choose "Only photos taken from now on" to skip the ones + already there. +- Before anything is sent you are told where the photos go, how many members + the group has and how much will be sent. **Everyone in that group will be + able to see and download them.** You can delete what you sent afterwards, + but not the copies others have already downloaded — so pick the group with + care. Changing the group or the folder later asks again. +- It runs **on Wi-Fi only** (more exactly, on a connection that is not charged + by the amount), once a day, while the application is open — with the screen + off too. If the application was not opened all day, it runs the next time it + is. **Back up now** runs at once; on mobile data it tells you how much it is + about to send and asks first. +- Photos go into folders by year and month (`2026/10`). **A photo you delete + from the phone stays in the group**, and one deleted from the group is not + sent again. A photo you edit on the phone is sent again beside the original, + with `-edited-` and the date in its name. +- **Where a photo was taken is removed** from the copy that is sent. +- If the backup cannot go on — the node's disk is full, the folder no longer + accepts files, you left the group — it stops, says why once in a + notification and in Settings, and tries again the next day. + ### Search The magnifying glass in the sidebar searches **across every group you are in** @@ -1030,6 +1061,12 @@ Better to know now than to go looking for it: with the screen off, from one track to the next, with a notification shown while it plays. A phone browser works too. - **A node cannot be hosted on Android**, and is not planned to be. +- **Photo backup only runs while the application is open** (the screen may be + off). There is no button yet to remove everything the phone sent to a group + in one go — delete those files from the group instead. +- **Photos in the HEIC format are backed up but do not show in Photos** yet: + they are in the folder (Files lists them) and can be downloaded. Most Android + phones take JPEG unless set otherwise. - **Hubs do not talk to each other yet.** Everyone in a group needs an account on the same hub. - **Casting reaches Chromecast devices** from the desktop and Android |