aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-common
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-common')
-rw-r--r--packages/meshbay-common/src/meshbay_common/__init__.py8
-rw-r--r--packages/meshbay-common/src/meshbay_common/adminop.py5
-rw-r--r--packages/meshbay-common/src/meshbay_common/protocol.py12
3 files changed, 22 insertions, 3 deletions
diff --git a/packages/meshbay-common/src/meshbay_common/__init__.py b/packages/meshbay-common/src/meshbay_common/__init__.py
index b37de8e..0ca0005 100644
--- a/packages/meshbay-common/src/meshbay_common/__init__.py
+++ b/packages/meshbay-common/src/meshbay_common/__init__.py
@@ -43,5 +43,11 @@ __version__ = "0.7.0"
# wrong, and Music now requires one before showing/enriching anything,
# exactly like Videos. Additive at the protocol level: an older client
# never sends the op and never expects the field.
-MNP_VERSION = "0.10"
+# 0.11: added `taken_at`/`camera` to `IndexEntry` (best-effort, from a photo's
+# own EXIF block) and `photo_roots`/`photo_roots_ack`, for the Photos group
+# app (docs/photos.md). Unlike `video_root`/`audio_root`, `photo_roots` is a
+# *set*, replaced whole in one signed op — a photo library is routinely
+# scattered across several folders, not one. Additive: an older client
+# never sends the op and never expects either field.
+MNP_VERSION = "0.11"
MHP_VERSION = "0.1"
diff --git a/packages/meshbay-common/src/meshbay_common/adminop.py b/packages/meshbay-common/src/meshbay_common/adminop.py
index d09b95e..19dfe8e 100644
--- a/packages/meshbay-common/src/meshbay_common/adminop.py
+++ b/packages/meshbay-common/src/meshbay_common/adminop.py
@@ -96,6 +96,11 @@ OP_MUSICBRAINZ_ENABLED = "musicbrainz_enabled"
# OP_VIDEO_ROOT above, added later once a real messy library showed the
# "no root, whole shared tree" simplification didn't hold up.
OP_AUDIO_ROOT = "audio_root"
+# Which folder(s) are the Photos app's entry points for this group — a
+# *set*, unlike OP_VIDEO_ROOT/OP_AUDIO_ROOT above: a photo library is
+# routinely scattered across several folders (docs/photos.md §2.1). The
+# whole set is signed and replaced in one op, same shape as OP_APPS_ENABLED.
+OP_PHOTO_ROOTS = "photo_roots"
OP_ROOT_ADD = "root_add"
OP_ROOT_REMOVE = "root_remove"
OP_GROUP_ATTACH = "group_attach"
diff --git a/packages/meshbay-common/src/meshbay_common/protocol.py b/packages/meshbay-common/src/meshbay_common/protocol.py
index 24fea8f..dd377e7 100644
--- a/packages/meshbay-common/src/meshbay_common/protocol.py
+++ b/packages/meshbay-common/src/meshbay_common/protocol.py
@@ -123,6 +123,11 @@ class MNP:
# shape as VIDEO_ROOT above.
AUDIO_ROOT = "audio_root" # operator → node: which folder is the Music entry point
AUDIO_ROOT_ACK = "audio_root_ack"
+ # Which folder(s) are the Photos app's entry points for this group — a
+ # *set*, unlike VIDEO_ROOT/AUDIO_ROOT above, since a photo library is
+ # routinely scattered across several unrelated folders (docs/photos.md §2.1).
+ PHOTO_ROOTS = "photo_roots" # operator → node: the whole root set, replaced
+ PHOTO_ROOTS_ACK = "photo_roots_ack"
# Device linking. A new device files a request bound to a code it displays;
# an already-pinned device of the same account approves it. Neither the hub
# nor the node can produce the countersignature.
@@ -174,14 +179,16 @@ class IndexEntry:
thumb_hash: str | None = None # blake3 of thumbnail
uploader_id: str | None = None # user_id of who uploaded (None = pre-existing on disk)
uploader_pk: str | None = None # Ed25519 public key of uploader (base64 raw 32 bytes)
- width: int | None = None # pixels, video only
- height: int | None = None # pixels, video only
+ width: int | None = None # pixels, video/image
+ height: int | None = None # pixels, video/image
display_title: str | None = None # parsed or cleaned-filename title, Videos app
season: int | None = None # parsed season number, Videos app
episode: int | None = None # parsed episode number, Videos app
artist: str | None = None # tag or parsed, Music app
album: str | None = None # tag or parsed, Music app
track_no: int | None = None # tag or parsed, Music app
+ taken_at: int | None = None # unix timestamp, EXIF DateTimeOriginal — Photos app
+ camera: str | None = None # "Make Model", when both present — Photos app
def index_entry_wire(e: IndexEntry) -> dict:
@@ -201,6 +208,7 @@ def index_entry_wire(e: IndexEntry) -> dict:
"display_title": e.display_title,
"season": e.season, "episode": e.episode,
"artist": e.artist, "album": e.album, "track_no": e.track_no,
+ "taken_at": e.taken_at, "camera": e.camera,
}