Some checks failed
Veza CI / Rust (Stream Server) (push) Successful in 5m26s
Security Scan / Secret Scanning (gitleaks) (push) Failing after 56s
Veza CI / Backend (Go) (push) Failing after 8m39s
Veza CI / Frontend (Web) (push) Failing after 16m22s
Veza CI / Notify on failure (push) Successful in 11s
E2E Playwright / e2e (full) (push) Successful in 20m30s
End-to-end embed pipeline. Standalone HTML widget for iframes, oEmbed JSON for unfurlers (Twitter/Discord/Slack), runtime per-track OG + Twitter player card on the SPA. Share-token storage + handlers were already in place from earlier — Day 15 only adds the embed surface. Backend (root router, no /api/v1 prefix — matches what scrapers expect) - internal/handlers/embed_handler.go : EmbedTrack renders inline HTML with OG tags + <audio controls>. DMCA-blocked tracks 451, private tracks 404 (don't leak existence). X-Frame-Options=ALLOWALL + CSP frame-ancestors=* so the page can be iframed by third parties. OEmbed handler accepts ?url=&format=json, validates the URL points at /tracks/:id, returns a type=rich envelope with an iframe HTML string. ?maxwidth clamped to [240, 1280]. - internal/api/routes_embed.go : registers the two endpoints. - internal/handlers/embed_handler_test.go : pure-function coverage for extractTrackIDFromURL (8 cases incl. trailing slash, query string, hash fragment, subpath) + parseSafeInt (overflow + non-digit rejection). Frontend - apps/web/src/features/tracks/hooks/useTrackOpenGraph.ts : runtime injection of og:* + twitter:player + <link rel=alternate> (oEmbed discovery) into document.head. Limitation noted inline — pure HTML scrapers don't see these ; the embed widget itself carries server-rendered OG tags so unfurlers always work. - TrackDetailPage : wires useTrackOpenGraph(track) on render. E2E (tests/e2e/30-embed-and-share.spec.ts) - 30. /embed/track/:id renders HTML with OG tags + audio src. - 31. /oembed returns valid JSON envelope (rich type, iframe HTML). - 32. /oembed rejects non-track URLs (400). - 33. share-token roundtrip — creator mints, anonymous resolves via /api/v1/tracks/shared/:token (re-uses existing share handler ; Day 15 didn't add new share infra, just covers it under the embed acceptance gate). Acceptance (Day 15) : embed widget Twitter card preview ✓ (OG tags present), oEmbed JSON valid ✓, share token roundtrip ✓. W3 verification gate : Redis Sentinel ✓ · MinIO distribué ✓ · CDN signed URLs ✓ · DMCA E2E ✓ · embed + share token ✓ · all 5 W3 days shipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
35 lines
1.1 KiB
Go
35 lines
1.1 KiB
Go
package api
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"veza-backend-api/internal/handlers"
|
|
)
|
|
|
|
// setupEmbedRoutes registers the public embed widget + oEmbed
|
|
// endpoints. Both live on the root router (no /api/v1 prefix) so
|
|
// the URLs match what blogs / Twitter / Discord scrapers expect :
|
|
//
|
|
// GET /embed/track/:id — standalone HTML widget
|
|
// GET /oembed?url=&format=json — oEmbed JSON envelope
|
|
//
|
|
// v1.0.9 W3 Day 15.
|
|
func (r *APIRouter) setupEmbedRoutes(router *gin.Engine) {
|
|
frontend := r.config.FrontendURL
|
|
if frontend == "" {
|
|
frontend = "https://veza.fr"
|
|
}
|
|
apiBase := frontend // best default — assume frontend reverse-proxies API
|
|
if r.config.StreamServerURL != "" {
|
|
// Not actually the API base, but if we ever introduce an
|
|
// explicit API_BASE_URL config it should land here. For now
|
|
// the embed page uses relative-looking URLs which the
|
|
// browser resolves against the embed page's own origin.
|
|
_ = r.config.StreamServerURL
|
|
}
|
|
|
|
embedHandler := handlers.NewEmbedHandler(r.db.GormDB, frontend, apiBase, r.logger)
|
|
|
|
router.GET("/embed/track/:id", embedHandler.EmbedTrack)
|
|
router.GET("/oembed", embedHandler.OEmbed)
|
|
}
|