From 8c4b29d1ada6987533a964adb1d1ea4a414a94fb Mon Sep 17 00:00:00 2001 From: Eli Mallon Date: Tue, 2 Jun 2026 11:08:44 -0700 Subject: [PATCH] likes: key the like subject on the canonical DID-based video URI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a VOD page is reached via a handle URL (//video/), the video store's aturi authority is the handle, so liking created a place.stream.like whose subject was at:///... — which never matches the DID-keyed video record (and so never counts toward likeCount). Feed LikeButton video.uri instead: getVideo runs the requested URI through normalizeURI (handle->DID) and returns the stored DID-based row URI, so video.uri is canonical. Both the like read (getLikes) and write (createLike) now use it. Co-Authored-By: Claude Opus 4.8 --- .../src/components/vod/vod-mobile-metadata.tsx | 6 +++++- .../media/place-stream-media-getvideo.md | 8 +++++++- .../src/content/docs/lex-reference/openapi.json | 14 +++++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/js/components/src/components/vod/vod-mobile-metadata.tsx b/js/components/src/components/vod/vod-mobile-metadata.tsx index 5a851f044..51c1a63f6 100644 --- a/js/components/src/components/vod/vod-mobile-metadata.tsx +++ b/js/components/src/components/vod/vod-mobile-metadata.tsx @@ -103,7 +103,11 @@ export function VodMobileMetadata() { {/* Right: like + views + share */} - + {/* Use the server-canonical (DID-based) video.uri, not the store's + aturi — when the page is reached via a handle URL the aturi's + authority is the handle, and a like keyed on a handle subject + won't match the DID-keyed video record. */} + {wide && } diff --git a/js/docs/src/content/docs/lex-reference/media/place-stream-media-getvideo.md b/js/docs/src/content/docs/lex-reference/media/place-stream-media-getvideo.md index ecbd9f611..6a91f0497 100644 --- a/js/docs/src/content/docs/lex-reference/media/place-stream-media-getvideo.md +++ b/js/docs/src/content/docs/lex-reference/media/place-stream-media-getvideo.md @@ -48,6 +48,7 @@ Get a hydrated view of a place.stream.video record — the record itself plus au | `cid` | `string` | ✅ | | Format: `cid` | | `author` | [`app.bsky.actor.defs#profileViewBasic`](https://github.com/bluesky-social/atproto/tree/main/lexicons/app/bsky/actor/defs.json#profileViewBasic) | ✅ | | | | `record` | `unknown` | ✅ | | | +| `likeCount` | `integer` | ✅ | Total number of place.stream.like records whose subject is this video. Always present; zero when none, so consumers can render a count unconditionally. | Min: 0 | | `viewCounts` | [`#viewCountSummary`](#viewcountsummary) | ✅ | Aggregated view counts across every indexed reporter. Always present; zero-valued (count=0, reporters=0) when no place.stream.media.viewCount records have been observed yet, so consumers can render a count unconditionally. | | | `tracks` | Array of [`place.stream.media.track#trackView`](/lex-reference/place-stream-media-track#trackview) | ❌ | | | @@ -109,7 +110,7 @@ Sums across every place.stream.media.viewCount record indexed for this video, re }, "videoView": { "type": "object", - "required": ["uri", "cid", "author", "record", "viewCounts"], + "required": ["uri", "cid", "author", "record", "viewCounts", "likeCount"], "properties": { "uri": { "type": "string", @@ -126,6 +127,11 @@ Sums across every place.stream.media.viewCount record indexed for this video, re "record": { "type": "unknown" }, + "likeCount": { + "type": "integer", + "minimum": 0, + "description": "Total number of place.stream.like records whose subject is this video. Always present; zero when none, so consumers can render a count unconditionally." + }, "viewCounts": { "type": "ref", "ref": "#viewCountSummary", diff --git a/js/docs/src/content/docs/lex-reference/openapi.json b/js/docs/src/content/docs/lex-reference/openapi.json index 7401f0456..dd385ba8c 100644 --- a/js/docs/src/content/docs/lex-reference/openapi.json +++ b/js/docs/src/content/docs/lex-reference/openapi.json @@ -5533,6 +5533,11 @@ "$ref": "#/components/schemas/app.bsky.actor.defs_profileViewBasic" }, "record": {}, + "likeCount": { + "type": "integer", + "description": "Total number of place.stream.like records whose subject is this video. Always present; zero when none, so consumers can render a count unconditionally.", + "minimum": 0 + }, "viewCounts": { "$ref": "#/components/schemas/place.stream.media.getVideo_viewCountSummary", "description": "Aggregated view counts across every indexed reporter. Always present; zero-valued (count=0, reporters=0) when no place.stream.media.viewCount records have been observed yet, so consumers can render a count unconditionally." @@ -5544,7 +5549,14 @@ } } }, - "required": ["uri", "cid", "author", "record", "viewCounts"] + "required": [ + "uri", + "cid", + "author", + "record", + "viewCounts", + "likeCount" + ] }, "place.stream.media.getVideo_viewCountSummary": { "type": "object", -- 2.51.2