diff --git a/_config/oembed.yml b/_config/oembed.yml
index 75f4bc774..31a1b742b 100644
--- a/_config/oembed.yml
+++ b/_config/oembed.yml
@@ -3,4 +3,7 @@ Name: coreoembed
---
SilverStripe\Core\Injector\Injector:
SilverStripe\View\Embed\Embeddable:
- class: SilverStripe\View\Embed\EmbedResource
+ class: SilverStripe\View\Embed\EmbedContainer
+ Embed\Embed:
+ constructor:
+ - '%$Embed\Http\Crawler'
diff --git a/composer.json b/composer.json
index 286c2d720..08806cc7a 100644
--- a/composer.json
+++ b/composer.json
@@ -25,8 +25,8 @@
"bramus/monolog-colored-line-formatter": "^2",
"composer/installers": "^1 || ^2",
"composer/semver": "^1 || ^3",
- "embed/embed": "^3",
"guzzlehttp/psr7": "^2",
+ "embed/embed": "^4",
"league/csv": "^8 || ^9",
"m1/env": "^2.1",
"monolog/monolog": "^1.16",
diff --git a/src/View/Embed/EmbedContainer.php b/src/View/Embed/EmbedContainer.php
new file mode 100644
index 000000000..5374842ff
--- /dev/null
+++ b/src/View/Embed/EmbedContainer.php
@@ -0,0 +1,138 @@
+ '%$' . Embed::class,
+ ];
+
+ public Embed $embed;
+
+ private ?Extractor $extractor = null;
+
+ private string $url;
+
+ private array $options = [];
+
+ public function __construct(string $url)
+ {
+ $this->url = $url;
+ }
+
+ /**
+ * @return int
+ */
+ public function getWidth()
+ {
+ $code = $this->getExtractor()->code;
+ return $code ? ($code->width ?: 100) : 100;
+ }
+
+ /**
+ * @return int
+ */
+ public function getHeight()
+ {
+ $code = $this->getExtractor()->code;
+ return $code ? ($code->height ?: 100) : 100;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPreviewURL()
+ {
+ $extractor = $this->getExtractor();
+
+ // Use thumbnail url
+ if ($extractor->image) {
+ return (string) $extractor->image;
+ }
+
+ // Default media
+ return ModuleResourceLoader::resourceURL(
+ 'silverstripe/asset-admin:client/dist/images/icon_file.png'
+ );
+ }
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ $extractor = $this->getExtractor();
+ if ($extractor->title) {
+ return $extractor->title;
+ }
+ if ($extractor->url instanceof UriInterface) {
+ return basename($extractor->url->getPath());
+ }
+ return '';
+ }
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ $html = $this->getExtractor()->code->html ?? '';
+ if (strpos($html, '
+ EOT
+ );
+ $this->assertSame('video', $container->getType());
+ $container = $this->getEmbedContainer(
+ <<
+