cleanup webpost
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
appbsky "github.com/bluesky-social/indigo/api/bsky"
|
||||
)
|
||||
|
||||
// Helpers for extracting Open Graph / Twitter Card metadata from post
|
||||
// embeds. These produce data for og:* and twitter:* meta tags only — they
|
||||
// are not used by the schema.org JSON-LD output (which lives in jsonld.go).
|
||||
//
|
||||
// The og:video tags exist as a separate code path because JSON-LD does not
|
||||
// currently emit a VideoObject (deferred — requires `duration` from the
|
||||
// appview that is not exposed today).
|
||||
|
||||
// videoMeta is the metadata needed for og:video meta tags.
|
||||
type videoMeta struct {
|
||||
URL string
|
||||
Type string
|
||||
Width int64
|
||||
Height int64
|
||||
HasSize bool
|
||||
}
|
||||
|
||||
// extractVideoMeta returns og:video metadata for the post if it has a video
|
||||
// embed, otherwise the zero value. Respects the same embedHidden gate as
|
||||
// extractPostMedia (in jsonld.go) so og:video and og:image suppression stay
|
||||
// in sync.
|
||||
func extractVideoMeta(pv *appbsky.FeedDefs_PostView, embedHidden bool) videoMeta {
|
||||
if pv == nil || pv.Embed == nil || embedHidden {
|
||||
return videoMeta{}
|
||||
}
|
||||
var v *appbsky.EmbedVideo_View
|
||||
if pv.Embed.EmbedVideo_View != nil {
|
||||
v = pv.Embed.EmbedVideo_View
|
||||
} else if pv.Embed.EmbedRecordWithMedia_View != nil &&
|
||||
pv.Embed.EmbedRecordWithMedia_View.Media != nil &&
|
||||
pv.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View != nil {
|
||||
v = pv.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View
|
||||
}
|
||||
if v == nil || v.Playlist == "" {
|
||||
return videoMeta{}
|
||||
}
|
||||
out := videoMeta{
|
||||
URL: v.Playlist,
|
||||
Type: "application/vnd.apple.mpegurl",
|
||||
}
|
||||
if v.AspectRatio != nil {
|
||||
out.Width = v.AspectRatio.Width
|
||||
out.Height = v.AspectRatio.Height
|
||||
out.HasSize = true
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
appbsky "github.com/bluesky-social/indigo/api/bsky"
|
||||
)
|
||||
|
||||
func TestExtractVideoMeta(t *testing.T) {
|
||||
// Plain post — no video.
|
||||
pv := makePostView("alice.bsky.social", "did:plc:alice", "abc", "hi")
|
||||
if vm := extractVideoMeta(pv, false); vm.URL != "" {
|
||||
t.Errorf("non-video post produced video meta: %+v", vm)
|
||||
}
|
||||
|
||||
// Video embed with playlist + aspect ratio.
|
||||
playlist := "https://video.bsky.app/playlist.m3u8"
|
||||
pv = makePostView("alice.bsky.social", "did:plc:alice", "abc", "watch")
|
||||
pv.Embed = &appbsky.FeedDefs_PostView_Embed{
|
||||
EmbedVideo_View: &appbsky.EmbedVideo_View{
|
||||
Thumbnail: strPtr("https://cdn.bsky.app/thumb@jpg"),
|
||||
Playlist: playlist,
|
||||
AspectRatio: &appbsky.EmbedDefs_AspectRatio{Width: 16, Height: 9},
|
||||
},
|
||||
}
|
||||
vm := extractVideoMeta(pv, false)
|
||||
if vm.URL != playlist {
|
||||
t.Errorf("URL wrong: %v", vm.URL)
|
||||
}
|
||||
if vm.Type != "application/vnd.apple.mpegurl" {
|
||||
t.Errorf("Type wrong: %v", vm.Type)
|
||||
}
|
||||
if !vm.HasSize || vm.Width != 16 || vm.Height != 9 {
|
||||
t.Errorf("aspect ratio not propagated: %+v", vm)
|
||||
}
|
||||
|
||||
// Hidden embed gate suppresses video too.
|
||||
if vm := extractVideoMeta(pv, true); vm.URL != "" {
|
||||
t.Errorf("hidden embed should suppress video meta")
|
||||
}
|
||||
|
||||
// Video inside record-with-media.
|
||||
pv2 := makePostView("alice.bsky.social", "did:plc:alice", "abc", "quote w/ video")
|
||||
pv2.Embed = &appbsky.FeedDefs_PostView_Embed{
|
||||
EmbedRecordWithMedia_View: &appbsky.EmbedRecordWithMedia_View{
|
||||
Media: &appbsky.EmbedRecordWithMedia_View_Media{
|
||||
EmbedVideo_View: &appbsky.EmbedVideo_View{Playlist: playlist},
|
||||
},
|
||||
},
|
||||
}
|
||||
vm2 := extractVideoMeta(pv2, false)
|
||||
if vm2.URL != playlist {
|
||||
t.Errorf("record-with-media video URL not extracted: %+v", vm2)
|
||||
}
|
||||
if vm2.HasSize {
|
||||
t.Errorf("expected HasSize=false when no aspect ratio")
|
||||
}
|
||||
|
||||
// Video without playlist — skip entirely.
|
||||
pv3 := makePostView("alice.bsky.social", "did:plc:alice", "abc", "no playlist")
|
||||
pv3.Embed = &appbsky.FeedDefs_PostView_Embed{
|
||||
EmbedVideo_View: &appbsky.EmbedVideo_View{
|
||||
Thumbnail: strPtr("https://cdn.bsky.app/thumb@jpg"),
|
||||
},
|
||||
}
|
||||
if vm := extractVideoMeta(pv3, false); vm.URL != "" {
|
||||
t.Errorf("video without playlist should produce empty meta, got %+v", vm)
|
||||
}
|
||||
}
|
||||
@@ -576,76 +576,22 @@ func (srv *Server) WebPost(c echo.Context) error {
|
||||
data["canonicalURL"] = canonicalURL
|
||||
}
|
||||
|
||||
// If any undesirable labels are set, the embed will not be included in
|
||||
// metadata
|
||||
isEmbedHidden := false
|
||||
for _, label := range postView.Labels {
|
||||
isNeg := label.Neg != nil && *label.Neg
|
||||
if hideEmbedLabels[label.Val] && !isNeg {
|
||||
isEmbedHidden = true
|
||||
break
|
||||
}
|
||||
// Embed-hidden gate, post text, image thumbs, and video metadata are all
|
||||
// derived from helpers in jsonld.go so the og:* / twitter:* meta tags
|
||||
// and the JSON-LD payload stay in lockstep — Google's Rich Results
|
||||
// validator requires og:image and JSON-LD image[] to be byte-identical.
|
||||
isEmbedHidden := postEmbedHidden(postView, hideEmbedLabels)
|
||||
data["postText"] = postRecordText(postView)
|
||||
|
||||
if thumbs := extractPostMedia(postView, isEmbedHidden); len(thumbs) > 0 {
|
||||
data["imgThumbUrls"] = thumbs
|
||||
}
|
||||
|
||||
if postView.Record != nil {
|
||||
postRecord, ok := postView.Record.Val.(*appbsky.FeedPost)
|
||||
if ok {
|
||||
data["postText"] = ExpandPostText(postRecord)
|
||||
|
||||
if !isEmbedHidden && postRecord.Labels != nil && postRecord.Labels.LabelDefs_SelfLabels != nil {
|
||||
for _, label := range postRecord.Labels.LabelDefs_SelfLabels.Values {
|
||||
if hideEmbedLabels[label.Val] {
|
||||
isEmbedHidden = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if postView.Embed != nil && !isEmbedHidden {
|
||||
hasImages := postView.Embed.EmbedImages_View != nil
|
||||
hasVideo := postView.Embed.EmbedVideo_View != nil
|
||||
hasMedia := postView.Embed.EmbedRecordWithMedia_View != nil && postView.Embed.EmbedRecordWithMedia_View.Media != nil
|
||||
hasMediaImages := hasMedia && postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View != nil
|
||||
hasMediaVideo := hasMedia && postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View != nil
|
||||
|
||||
if hasImages {
|
||||
var thumbUrls []string
|
||||
for i := range postView.Embed.EmbedImages_View.Images {
|
||||
thumbUrls = append(thumbUrls, postView.Embed.EmbedImages_View.Images[i].Thumb)
|
||||
}
|
||||
data["imgThumbUrls"] = thumbUrls
|
||||
} else if hasVideo {
|
||||
if postView.Embed.EmbedVideo_View.Thumbnail != nil {
|
||||
data["imgThumbUrls"] = []string{*postView.Embed.EmbedVideo_View.Thumbnail}
|
||||
}
|
||||
if postView.Embed.EmbedVideo_View.Playlist != "" {
|
||||
data["videoUrl"] = postView.Embed.EmbedVideo_View.Playlist
|
||||
data["videoType"] = "application/vnd.apple.mpegurl"
|
||||
if postView.Embed.EmbedVideo_View.AspectRatio != nil {
|
||||
data["videoWidth"] = postView.Embed.EmbedVideo_View.AspectRatio.Width
|
||||
data["videoHeight"] = postView.Embed.EmbedVideo_View.AspectRatio.Height
|
||||
}
|
||||
}
|
||||
} else if hasMediaImages {
|
||||
var thumbUrls []string
|
||||
for i := range postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View.Images {
|
||||
thumbUrls = append(thumbUrls, postView.Embed.EmbedRecordWithMedia_View.Media.EmbedImages_View.Images[i].Thumb)
|
||||
}
|
||||
data["imgThumbUrls"] = thumbUrls
|
||||
} else if hasMediaVideo {
|
||||
if postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.Thumbnail != nil {
|
||||
data["imgThumbUrls"] = []string{*postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.Thumbnail}
|
||||
}
|
||||
if postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.Playlist != "" {
|
||||
data["videoUrl"] = postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.Playlist
|
||||
data["videoType"] = "application/vnd.apple.mpegurl"
|
||||
if postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.AspectRatio != nil {
|
||||
data["videoWidth"] = postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.AspectRatio.Width
|
||||
data["videoHeight"] = postView.Embed.EmbedRecordWithMedia_View.Media.EmbedVideo_View.AspectRatio.Height
|
||||
}
|
||||
}
|
||||
if vm := extractVideoMeta(postView, isEmbedHidden); vm.URL != "" {
|
||||
data["videoUrl"] = vm.URL
|
||||
data["videoType"] = vm.Type
|
||||
if vm.HasSize {
|
||||
data["videoWidth"] = vm.Width
|
||||
data["videoHeight"] = vm.Height
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user