Match videos: composed VS-card OG preview + richer share metadata

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) <[email protected]>
This commit is contained in:
ghassanandClaude Opus 4.7 committed 2026-08-11 12:34:40 +03:00
1 parent 665bad76bf
commit 3e18bd2150
14 files changed
+3562 -21

No files matched your search

Generated
+340 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "40fa327b55e9b6fafab4b2da3f763724",
"content-hash": "bdb64417cd2491642a0712fe40bade22",
"packages": [
{
"name": "bacon/bacon-qr-code",
@@ -1457,6 +1457,90 @@
],
"time": "2025-08-22T14:27:06+00:00"
},
{
"name": "intervention/image",
"version": "2.7.2",
"source": {
"type": "git",
"url": "https://github.com/Intervention/image.git",
"reference": "04be355f8d6734c826045d02a1079ad658322dad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Intervention/image/zipball/04be355f8d6734c826045d02a1079ad658322dad",
"reference": "04be355f8d6734c826045d02a1079ad658322dad",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"guzzlehttp/psr7": "~1.1 || ^2.0",
"php": ">=5.4.0"
},
"require-dev": {
"mockery/mockery": "~0.9.2",
"phpunit/phpunit": "^4.8 || ^5.7 || ^7.5.15"
},
"suggest": {
"ext-gd": "to use GD library based image processing.",
"ext-imagick": "to use Imagick based image processing.",
"intervention/imagecache": "Caching extension for the Intervention Image library"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Image": "Intervention\\Image\\Facades\\Image"
},
"providers": [
"Intervention\\Image\\ImageServiceProvider"
]
},
"branch-alias": {
"dev-master": "2.4-dev"
}
},
"autoload": {
"psr-4": {
"Intervention\\Image\\": "src/Intervention/Image"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Oliver Vogel",
"email": "[email protected]",
"homepage": "https://intervention.io/"
}
],
"description": "Image handling and manipulation library with support for Laravel integration",
"homepage": "http://image.intervention.io/",
"keywords": [
"gd",
"image",
"imagick",
"laravel",
"thumbnail",
"watermark"
],
"support": {
"issues": "https://github.com/Intervention/image/issues",
"source": "https://github.com/Intervention/image/tree/2.7.2"
},
"funding": [
{
"url": "https://paypal.me/interventionio",
"type": "custom"
},
{
"url": "https://github.com/Intervention",
"type": "github"
}
],
"time": "2022-05-21T17:30:32+00:00"
},
{
"name": "laravel/framework",
"version": "10.50.2",
@@ -2237,6 +2321,71 @@
},
"time": "2026-01-23T15:30:45+00:00"
},
{
"name": "league/glide",
"version": "2.3.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/glide.git",
"reference": "b8e946dd87c79a9dce3290707ab90b5b52602813"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/glide/zipball/b8e946dd87c79a9dce3290707ab90b5b52602813",
"reference": "b8e946dd87c79a9dce3290707ab90b5b52602813",
"shasum": ""
},
"require": {
"intervention/image": "^2.7",
"league/flysystem": "^2.0|^3.0",
"php": "^7.2|^8.0",
"psr/http-message": "^1.0|^2.0"
},
"require-dev": {
"mockery/mockery": "^1.3.3",
"phpunit/php-token-stream": "^3.1|^4.0",
"phpunit/phpunit": "^8.5|^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\Glide\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Reinink",
"email": "[email protected]",
"homepage": "http://reinink.ca"
},
{
"name": "Titouan Galopin",
"email": "[email protected]",
"homepage": "https://titouangalopin.com"
}
],
"description": "Wonderfully easy on-demand image manipulation library with an HTTP based API.",
"homepage": "http://glide.thephpleague.com",
"keywords": [
"ImageMagick",
"editing",
"gd",
"image",
"imagick",
"league",
"manipulation",
"processing"
],
"support": {
"issues": "https://github.com/thephpleague/glide/issues",
"source": "https://github.com/thephpleague/glide/tree/2.3.2"
},
"time": "2025-03-21T13:48:39+00:00"
},
{
"name": "league/mime-type-detection",
"version": "1.16.0",
@@ -4021,6 +4170,196 @@
},
"time": "2025-12-14T04:43:48+00:00"
},
{
"name": "spatie/browsershot",
"version": "3.61.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/browsershot.git",
"reference": "14d75679390b8b84a71b3a17dc5905928deeb887"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/browsershot/zipball/14d75679390b8b84a71b3a17dc5905928deeb887",
"reference": "14d75679390b8b84a71b3a17dc5905928deeb887",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": "^8.0",
"spatie/image": "^1.5.3|^2.0",
"spatie/temporary-directory": "^1.1|^2.0",
"symfony/process": "^4.2|^5.0|^6.0|^7.0"
},
"require-dev": {
"pestphp/pest": "^1.20",
"spatie/phpunit-snapshot-assertions": "^4.2.3"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Browsershot\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "[email protected]",
"homepage": "https://github.com/freekmurze",
"role": "Developer"
}
],
"description": "Convert a webpage to an image or pdf using headless Chrome",
"homepage": "https://github.com/spatie/browsershot",
"keywords": [
"chrome",
"convert",
"headless",
"image",
"pdf",
"puppeteer",
"screenshot",
"webpage"
],
"support": {
"source": "https://github.com/spatie/browsershot/tree/3.61.0"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2023-12-21T10:00:28+00:00"
},
{
"name": "spatie/image",
"version": "2.2.7",
"source": {
"type": "git",
"url": "https://github.com/spatie/image.git",
"reference": "2f802853aab017aa615224daae1588054b5ab20e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/image/zipball/2f802853aab017aa615224daae1588054b5ab20e",
"reference": "2f802853aab017aa615224daae1588054b5ab20e",
"shasum": ""
},
"require": {
"ext-exif": "*",
"ext-json": "*",
"ext-mbstring": "*",
"league/glide": "^2.2.2",
"php": "^8.0",
"spatie/image-optimizer": "^1.7",
"spatie/temporary-directory": "^1.0|^2.0",
"symfony/process": "^3.0|^4.0|^5.0|^6.0"
},
"require-dev": {
"pestphp/pest": "^1.22",
"phpunit/phpunit": "^9.5",
"symfony/var-dumper": "^4.0|^5.0|^6.0",
"vimeo/psalm": "^4.6"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Image\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "[email protected]",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Manipulate images with an expressive API",
"homepage": "https://github.com/spatie/image",
"keywords": [
"image",
"spatie"
],
"support": {
"source": "https://github.com/spatie/image/tree/2.2.7"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2023-07-24T13:54:13+00:00"
},
{
"name": "spatie/image-optimizer",
"version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/image-optimizer.git",
"reference": "333c03952289dc2df0a91874636a0dffeb5b6aec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/image-optimizer/zipball/333c03952289dc2df0a91874636a0dffeb5b6aec",
"reference": "333c03952289dc2df0a91874636a0dffeb5b6aec",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"php": "^7.4|^8.0",
"psr/log": "^1.0 | ^2.0 | ^3.0",
"symfony/process": "^4.2|^5.0|^6.0|^7.0|^8.0"
},
"require-dev": {
"pestphp/pest": "^1.21|^2.0|^3.0|^4.0",
"phpunit/phpunit": "^8.5.21|^9.4.4|^10.0|^11.0|^12.0",
"symfony/var-dumper": "^4.2|^5.0|^6.0|^7.0|^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\ImageOptimizer\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "[email protected]",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Easily optimize images using PHP",
"homepage": "https://github.com/spatie/image-optimizer",
"keywords": [
"image-optimizer",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/image-optimizer/issues",
"source": "https://github.com/spatie/image-optimizer/tree/1.10.0"
},
"time": "2026-06-29T08:28:30+00:00"
},
{
"name": "spatie/temporary-directory",
"version": "2.3.1",