feat: motion photo support - #2819
Merged
Merged
Conversation
dschmidt
force-pushed
the
feat/motion-photos
branch
4 times, most recently
from
July 7, 2026 13:10
2d81b74 to
a37ca7d
Compare
dschmidt
changed the base branch from
main
to
chore/regenerate-libre-graph-client
July 7, 2026 13:11
dschmidt
force-pushed
the
chore/regenerate-libre-graph-client
branch
from
July 7, 2026 13:18
4d882ab to
cae8685
Compare
dschmidt
force-pushed
the
feat/motion-photos
branch
from
July 7, 2026 13:18
a37ca7d to
f013edc
Compare
dschmidt
force-pushed
the
feat/motion-photos
branch
2 times, most recently
from
July 7, 2026 14:01
7a98785 to
ecff135
Compare
dschmidt
force-pushed
the
feat/motion-photos
branch
from
August 15, 2026 20:25
ecff135 to
161f9c5
Compare
dschmidt
force-pushed
the
feat/motion-photos
branch
3 times, most recently
from
September 7, 2026 11:43
bf54e80 to
ba234f1
Compare
dschmidt
marked this pull request as ready for review
September 7, 2026 11:45
dschmidt
force-pushed
the
feat/motion-photos
branch
2 times, most recently
from
September 7, 2026 14:41
f550137 to
5170436
Compare
Map the oc:motionPhoto WebDAV property (version, presentationTimestampUs, videoSize) onto Resource in buildResource, using the generated MotionPhoto type from the libre-graph client.
MotionPhotoBadge renders the MDI motion-play/pause icon; MotionPhotoOverlay pairs the badge with the hover-to-play clip so every surface reuses the same markup and behaviour. useMotionPhoto range-fetches the embedded MP4; useMotionPhotoPlayback owns the shared hover/play state, buffering and abort.
dschmidt
force-pushed
the
feat/motion-photos
branch
from
September 7, 2026 15:13
5170436 to
21d3e20
Compare
dschmidt
force-pushed
the
feat/motion-photos
branch
from
September 8, 2026 07:04
21d3e20 to
52ee6b2
Compare
Show the badge and hover-to-play the clip on grid tiles, table rows, the sidebar preview and the media viewer photo roll. The media viewer auto-plays once on open and offers a loop play/pause control in the bottom bar.
Cover the badge in tiles/table, the media viewer preview strip, the viewer playback control and inline sidebar playback.
The motion photo facet landed in opencloud main on 2026-09-03, the e2e scenarios need a server that emits it.
The motion photo facet needs the Camera: XMP keys (Tika 4) and the video emitted as an embedded document (apache/tika#3115, merged on 2026-09-02 and not released yet). Without it the search service never writes libre.graph.motionPhoto and oc:motion-photo stays empty. The snapshot tag moves, so the image is pinned by digest to the build that was verified against the e2e fixture. Replace it with the release tag once Tika 4.1.0 ships.
…xpected to fail A quota-exhausted upload is rejected at the tus POST by the bumped opencloud, so no 201/204 ever arrives. The dangling waitForResponse then rejected when the page closed and failed an otherwise passing scenario.
A play() cancelled while its fetch was in flight still ran its finally block and reset the state of the next run: it dropped the in-flight guard, cleared the newer spinner timer and hid its loading state, so a later run could become uncancelable and start after the pointer left. Every run now carries a generation and only cleans up its own. Hover-to-play waits for a short hover intent (150 ms) so sweeping the pointer across a list does not fire and abort one range request per item, and a consumer that switches resources (the sidebar) revokes the previous clip instead of keeping one blob per resource it ever showed.
…clip The overlay used to instantiate the playback composable (with its media query listener) for every list row. It is now a plain positioned wrapper and defers to a MotionPhotoPlayer that is only mounted for motion photos. The player is pointer-transparent apart from its badge. The badge is a real button now and sits next to the resource link instead of inside it, in the list and in the tile. A file whose facet is unusable still shows the badge, greyed out with an explaining label, because knowing that a file is a motion photo matters even when the clip cannot be played here.
dschmidt
force-pushed
the
feat/motion-photos
branch
from
September 8, 2026 08:42
f7c3810 to
5ccb6bb
Compare
The viewer rendered motion photos through their own component and lost the image controls. The still is a regular MediaImage again, which gained an overlay slot whose wrapper is the panzoom target, so zoom, pan and rotation carry over to the clip laid on top.
A digest of a snapshot build can be pruned upstream, which would break CI and dev stacks at a random point in time. The tag moves, but it moves forward, and it is replaced by the release tag as soon as Tika 4.1.0 ships.
No template comments, no prop docs (web-pkg components do not document props, unlike the design system), and only the facts that are not readable from the code: the motion photo file layout and range math, the stale-run generation, the hover intent, the touch gating, the 206 content type, and why the viewer wrapper has to fill the stage.
JammingBen
reviewed
Sep 8, 2026
As a positioned sibling after the media link it already paints above the thumbnail; z-20 lifted the badge above the selection checkbox and, since the card has no stacking context of its own, above sticky chrome.
The play and pause glyphs are design-system icons now (motion-play-line, motion-pause-line, the dot in its own group so it can orbit while loading), and the badge takes a Tailwind sizeClass like OcIcon instead of the deprecated SizeType, which drops the copied size map.
The preview shrinks while hovered or selected, the clip did not: it played at full tile size on top. The preview inset is now driven by the media area's hover state (badge included, so hovering the badge does not pop the still back out), the clip follows that inset with the same rounding, and the badge keeps the checkbox's fixed edge distance. The clip sits in a wrapper because insets alone do not size a replaced element, and the media link is a flex item again so the wrapper is not a line taller than the link.
openclouders
pushed a commit
that referenced
this pull request
Sep 8, 2026
feat: motion photo support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Surfaces Google Motion Photos (a still JPEG with a short MP4 appended) in the UI: a play badge everywhere plus inline playback.
Note
The backend side has landed: opencloud-eu/reva#790 emits the
oc:motion-photoPROPFIND property, opencloud-eu/opencloud#3478 bumped reva to that commit on 2026-09-07. This PR bumpsOPENCLOUD_COMMITIDin.woodpecker.envto a main commit that includes it, so the e2e scenarios run against a backend that emits the property.The facet also needs Tika 4.1.0-SNAPSHOT: the search service only writes
libre.graph.motionPhotowhen Tika flattens the motion photo XMP intoCamera:keys (Tika 4) and emits the appended clip as an embeddedvideo/*document (apache/tika#3115, merged 2026-09-02, unreleased). Verified locally: Tika 3.3.1 yields no keys, 4.0.0 yields keys but no property, 4.1.0-SNAPSHOT yieldsoc:motion-photowithvideo-size. The CI Tika image (.woodpecker.star) and the dev stack (docker-compose.yml) follow the4.1.0-SNAPSHOTtag on purpose (a digest of a snapshot can be pruned upstream) and switch to the release tag as soon as Tika 4.1.0 ships.oc:motion-photoWebDAV property (version,presentationTimestampUs,videoSize) throughbuildResourceontoResource, using the generatedMotionPhototype from the libre-graph client.MotionPhotoBadge(MDI motion-play/pause icon) on grid tiles, table rows, the sidebar preview and the media viewer photo roll.useMotionPhotorange-fetches just the embedded MP4 (Range: bytes=-videoSize) and wraps it as a blob;useMotionPhotoPlaybackowns the shared hover/play state, buffering indicator and abort.MotionPhotoOverlayreuses both across the files list, sidebar and photo roll.MediaImage, so zoom, pan, rotation and reset keep working and carry over to the clip.videoSize) still shows the badge, greyed out with an explaining tooltip: knowing that a file is a motion photo matters (e.g. before sharing it) even when it cannot be played here.<button>and lives next to the resource link, never inside it. Only actual motion photos mount the playback state; plain rows and tiles stay untouched.blob:URL (same as every video in the media viewer), somedia-srcneedsblob:. The dev stack and CI CSP files are updated; the server default (services/proxy/pkg/config/csp.yaml) needs the same change.Related Issue
How Has This Been Tested?
pnpm check:alluseMotionPhoto,useMotionPhotoPlayback,MotionPhotoOverlay,MediaMotionPhoto,ResourceTile,ResourceListItem,PhotoRollItemandbuildResourceMotion photo indicator: badge in tiles and table view, badge in the media viewer preview strip, playback control in the media viewer, inline playback from the sidebarTypes of changes