diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-10 10:28:12 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-10 10:28:12 +0200 |
| commit | 734b922370a56c7e3577c1f6bbdad69f75301334 (patch) | |
| tree | 3d016fe675672f07ebc6920912738004d4572038 | |
| parent | c100de578a49915dfc7ca5c30534ccccfd23d46c (diff) | |
| download | meshbay-734b922370a56c7e3577c1f6bbdad69f75301334.tar.gz | |
fix(android): back photos up under YYYY/YYYY-MM, not YYYY/MM
A month folder named 08 alone read like an album number.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 files changed, 14 insertions, 14 deletions
diff --git a/docs/MESHBAY_DESIGN.md b/docs/MESHBAY_DESIGN.md index 06ccaca..8a75f5a 100644 --- a/docs/MESHBAY_DESIGN.md +++ b/docs/MESHBAY_DESIGN.md @@ -3361,7 +3361,7 @@ 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 +each photo goes under `YYYY/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 diff --git a/docs/USERGUIDE.md b/docs/USERGUIDE.md index 83dc05e..1541e07 100644 --- a/docs/USERGUIDE.md +++ b/docs/USERGUIDE.md @@ -400,7 +400,7 @@ on your phone to a folder of one of your groups, once a day. 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 +- Photos go into folders by year, then year and month (`2026/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. diff --git a/packages/meshbay-android/app/src/main/kotlin/org/meshbay/client/photos/PhotoPlan.kt b/packages/meshbay-android/app/src/main/kotlin/org/meshbay/client/photos/PhotoPlan.kt index de39669..7e7801d 100644 --- a/packages/meshbay-android/app/src/main/kotlin/org/meshbay/client/photos/PhotoPlan.kt +++ b/packages/meshbay-android/app/src/main/kotlin/org/meshbay/client/photos/PhotoPlan.kt @@ -128,9 +128,9 @@ object PhotoPlan { fun whenTaken(p: Photo): Long = if (p.taken > 0) p.taken else p.added * 1000 - /** `<folder>/YYYY/MM`, from when it was taken: an album is a directory (§9.9). */ + /** `<folder>/YYYY/YYYY-MM`, from when it was taken: an album is a directory (§9.9). */ fun dirFor(folder: String, p: Photo, zone: TimeZone): String { - val fmt = SimpleDateFormat("yyyy/MM", Locale.ROOT).apply { timeZone = zone } + val fmt = SimpleDateFormat("yyyy/yyyy-MM", Locale.ROOT).apply { timeZone = zone } return "$folder/${fmt.format(Date(whenTaken(p)))}" } diff --git a/packages/meshbay-android/app/src/test/kotlin/org/meshbay/client/PhotoSyncTest.kt b/packages/meshbay-android/app/src/test/kotlin/org/meshbay/client/PhotoSyncTest.kt index 24e1841..0e2e924 100644 --- a/packages/meshbay-android/app/src/test/kotlin/org/meshbay/client/PhotoSyncTest.kt +++ b/packages/meshbay-android/app/src/test/kotlin/org/meshbay/client/PhotoSyncTest.kt @@ -43,8 +43,8 @@ class PhotoSyncTest { @Test fun `everything already on the phone is sent, newest first, under its year and month`() { val out = plan(listOf(photo(1, taken = oct9 - 40L * 86400000), photo(2), photo(3, taken = oct9 - 86400000))) assertEquals(listOf(2L, 3L, 1L), out.map { it.photo.mediaId }) - assertEquals("Media/Photos/Bob/2026/10", out[0].dir) - assertEquals("Media/Photos/Bob/2026/08", out[2].dir) + assertEquals("Media/Photos/Bob/2026/2026-10", out[0].dir) + assertEquals("Media/Photos/Bob/2026/2026-08", out[2].dir) assertEquals("IMG_2.jpg", out[0].name) } @@ -79,7 +79,7 @@ class PhotoSyncTest { assertEquals(1, out.size) assertTrue(out[0].edited) assertEquals("IMG_1-edited-20261009-130000.jpg", out[0].name) - assertEquals("Media/Photos/Bob/2026/10", out[0].dir) + assertEquals("Media/Photos/Bob/2026/2026-10", out[0].dir) } @Test fun `a touch that left the bytes alone sends nothing`() { diff --git a/packages/meshbay-hub/src/meshbay_hub/static/photo-sync.js b/packages/meshbay-hub/src/meshbay_hub/static/photo-sync.js index 154a009..74084b8 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/photo-sync.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/photo-sync.js @@ -249,7 +249,7 @@ async function upload(transport, item) { } } -/** `<folder>/YYYY/MM`, one level at a time; a level that exists is fine. */ +/** `<folder>/YYYY/YYYY-MM`, one level at a time; a level that exists is fine. */ async function makeDirs(transport, folder, dir, dirs) { let at = folder; for (const name of dir.slice(folder.length + 1).split('/').filter(Boolean)) { diff --git a/packages/meshbay-hub/tests/test_photo_sync.py b/packages/meshbay-hub/tests/test_photo_sync.py index f7852f4..cbc5f5d 100644 --- a/packages/meshbay-hub/tests/test_photo_sync.py +++ b/packages/meshbay-hub/tests/test_photo_sync.py @@ -63,7 +63,7 @@ fake.status = { lastCompleted: null, failure: null, failureAt: null, }; fake.items = [ - { token: 't1', name: 'IMG_3.jpg', dir: 'Media/Photos/Bob/2026/10', size: 30, edited: false, + { token: 't1', name: 'IMG_3.jpg', dir: 'Media/Photos/Bob/2026/2026-10', size: 30, edited: false, alsoKnownAs: 'IMG_3-edited-x.jpg' }, { token: 't2', name: 'IMG_2.jpg', dir: 'Media/Photos/Bob/2026/09', size: 20, edited: false, alsoKnownAs: 'IMG_2-edited-x.jpg' }, @@ -143,11 +143,11 @@ def test_a_due_run_sends_newest_first_and_records_each(tmp_path): # IMG_1 is already in the folder (a reinstall's empty ledger): recorded, # not sent again. assert _of(log, "upload") == [ - ["Media/Photos/Bob/2026/10", "IMG_3.jpg", "tr-30"], + ["Media/Photos/Bob/2026/2026-10", "IMG_3.jpg", "tr-30"], ["Media/Photos/Bob/2026/09", "IMG_2.jpg", "tr-20"], ] assert _of(log, "sent") == [ - ["t1", "Media/Photos/Bob/2026/10", "IMG_3.jpg"], + ["t1", "Media/Photos/Bob/2026/2026-10", "IMG_3.jpg"], ["t2", "Media/Photos/Bob/2026/09", "IMG_2.jpg"], ["t3", "Media/Photos/Bob/2026/09", "IMG_1.jpg"], ] @@ -158,7 +158,7 @@ def test_a_due_run_sends_newest_first_and_records_each(tmp_path): def test_only_missing_folders_are_made_and_parents_first(tmp_path): log = _run(_start(), tmp_path) - assert _of(log, "mkdir") == [["Media/Photos/Bob/2026/10"]] + assert _of(log, "mkdir") == [["Media/Photos/Bob/2026/2026-10"]] def test_every_upload_holds_a_slot_and_gives_it_back(tmp_path): @@ -170,9 +170,9 @@ def test_every_upload_holds_a_slot_and_gives_it_back(tmp_path): def test_an_edit_under_its_own_name_counts_as_already_there(tmp_path): log = _run(_start(""" -fake.index.entries.push({ path: 'Media/Photos/Bob/2026/10', name: 'IMG_3-edited-x.jpg', size: 30 }); +fake.index.entries.push({ path: 'Media/Photos/Bob/2026/2026-10', name: 'IMG_3-edited-x.jpg', size: 30 }); """), tmp_path) - assert ["t1", "Media/Photos/Bob/2026/10", "IMG_3-edited-x.jpg"] in _of(log, "sent") + assert ["t1", "Media/Photos/Bob/2026/2026-10", "IMG_3-edited-x.jpg"] in _of(log, "sent") assert all(u[1] != "IMG_3.jpg" for u in _of(log, "upload")) |