Sports match share links now show the full VS composition (fighters,
flags, event, weight class, referee/court/match chips) in WhatsApp /
Telegram / Facebook / Twitter previews instead of the raw video frame.
- Browsershot + puppeteer-bundled Chromium screenshots a dedicated
1200x675 (true 16:9) render of the vs-mini composition. Chrome runs
through a small wrapper (bin/browsershot-node.sh) that raises the fd
limit and reads its full env, since PHP-FPM's stripped env otherwise
makes Chromium fail to launch.
- Render is JPEG @ q85 (~100 KB) instead of PNG (~700 KB) — WhatsApp
silently drops OG images above roughly 300 KB, which is why music
thumbnails always showed and match cards didn't.
- SportsMatchController@store/update renders synchronously so the
picture is guaranteed to exist before the user copies the share URL;
edits regenerate and old stamped variants are cleaned. The og:image
URL carries a ?v={updated_at} stamp so scrapers recache on edit.
- accessShare() (/s/{token}) now detects scraper user agents and serves
the video page HTML inline instead of a 302 — some crawlers don't
follow redirects when building link previews.
- og:description / twitter:description built from headerData(): flag
emoji + fighter names (blue vs red), event, weight, match#, court,
referee, view count, upload date.
- Fixed 3-dot menu on video cards being hidden behind the next card
(:has(.dropdown-menu.show) promotes the active card above siblings
and lifts the overflow:hidden clip on .yt-video-info).
- vs-mini: skip the entrance animation on touch devices and expose a
.vs-mini-static class so the OG render always captures the final
frame instead of a random mid-animation moment.
Also adds an admin gallery at /admin/og-previews for spot-checking the
generated preview JPEGs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- SportsMatchController syncs Video.title with SportsMatch.title on
store/update so the "Match title" field drives the video's display
title everywhere.
- headerData(): "championship" now prefers event_name (event title)
and adds a dedicated "stage" key sourced from SportsMatch.title
(shown between the yellow lines above the weight class in both the
in-player VS overlay and the vs-mini gallery card).
- Video cards render match titles with flags + corner colours
("FINALS – 🇧🇭 Blue vs 🇧🇭 Red (-61 kg)"), matching the video
page header, and clip long titles to one line.
- Video gallery grid uses repeat(N, minmax(0, 1fr)) + grid-auto-rows:1fr
so every card thumbnail renders at exactly the same size; hover-preview
videos use object-fit:cover to stop portrait sources looking smaller.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Match player + preview
- Rebuild VS intro as a 1920×1080 scaled canvas (arena design from drafts/):
angled RED/BLUE panels with clip-paths, slam-in VS with pulse+shine,
event/stage/weight header, Match/Court/Referee chips, per-fighter
Record/Rank/Stats chip row. Every placeholder from the artifact is
always in the DOM; empty ones are hidden by `.vs-nullable:empty`
and `.vs-nullable-hide` so the layout adapts without losing the
design's HTML shape. Country codes always render as full country
names (via new App\Data\Countries::name()).
- Real-time 6s countdown Skip button; video pinned at t=0 while
the intro runs, released to play at zero or on Skip.
- Standalone preview page at /videos/{video}/vs-preview.
Video cards (home + everywhere)
- Match cards get a `vs-mini` overlay of the same arena design
(fixed canvas, per-card ResizeObserver, animations replay every
time the mouse leaves the thumb). On hover the mini explodes
outward (panels fly out, VS scales+blurs+fades) and the hover
video plays over the cleared thumb.
- Match cards also render a `scorebar-mini` overlay (verbatim of
the full-player msb-scale scorebar + msb-feed) that shows
during hover playback. Live-scoring is wired per-card via a
data-sbm-state payload of rounds+points; RED/BLUE score, round
label, per-round clock, and the top-right Live Scoring ticker
(4 entries, sport-aware Yuko/Waza-ari/Ippon or Punch/Body
kick/… labels) all update from the mini video's timeupdate.
Bug fixes
- Hover video wasn't playing sound: dropped the `muted` attribute
I'd added while debugging match previews.
- White flash strobing on the left of match cards: removed the
`.vs-mini-flash` element (intro-only flourish that fired on
every mouseleave replay).
- Sports-match modal was showing "Please complete the required
fields" when saving basic info for match videos that had no
SportsMatch row yet: the submit gate only checked matchId, not
the attached videoId; now it correctly skips uploadVideoFirst()
in both edit and attach-existing-video modes.
Country names project-wide
- New helper App\Data\Countries::name($iso2) → full country name.
- Swapped `?? country` fallbacks to `?? Countries::name(country)`
in admin dashboard, video-analytics, video-insights payloads
(VideoController + SuperAdminController), and the VS partials.
Now user-visible country labels always show "Bahrain" instead
of "BH", including chart tooltips and modal titles.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>