diff --git a/package-lock.json b/package-lock.json
index 4d91e3d..8447f1e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,8 @@
"@fortawesome/fontawesome-free": "^6.1.1",
"bulma": "^0.9.4",
"darkreader": "^4.9.51",
- "elevator.js": "^1.0.1"
+ "elevator.js": "^1.0.1",
+ "lite-youtube-embed": "^0.2.0"
},
"devDependencies": {
"esbuild": "^0.14.43",
@@ -1070,6 +1071,11 @@
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
+ "node_modules/lite-youtube-embed": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/lite-youtube-embed/-/lite-youtube-embed-0.2.0.tgz",
+ "integrity": "sha512-XXXAk5sbvtjjwbie3XG+6HppgTm1HTGL/Uk9z9NkJH53o7puZLur434heHzAjkS60hZB3vT4ls25zl5rMiX4EA=="
+ },
"node_modules/load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
@@ -2267,6 +2273,11 @@
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
"dev": true
},
+ "lite-youtube-embed": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/lite-youtube-embed/-/lite-youtube-embed-0.2.0.tgz",
+ "integrity": "sha512-XXXAk5sbvtjjwbie3XG+6HppgTm1HTGL/Uk9z9NkJH53o7puZLur434heHzAjkS60hZB3vT4ls25zl5rMiX4EA=="
+ },
"load-json-file": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
diff --git a/package.json b/package.json
index aaa0bf7..a022b23 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"@fortawesome/fontawesome-free": "^6.1.1",
"bulma": "^0.9.4",
"darkreader": "^4.9.51",
- "elevator.js": "^1.0.1"
+ "elevator.js": "^1.0.1",
+ "lite-youtube-embed": "^0.2.0"
}
}
diff --git a/static/src/js/lite-youtube-embed.js b/static/src/js/lite-youtube-embed.js
new file mode 100644
index 0000000..685f5c0
--- /dev/null
+++ b/static/src/js/lite-youtube-embed.js
@@ -0,0 +1 @@
+require("lite-youtube-embed");
diff --git a/static/src/scss/_blocks.scss b/static/src/scss/_blocks.scss
index 3f016c2..611737b 100644
--- a/static/src/scss/_blocks.scss
+++ b/static/src/scss/_blocks.scss
@@ -7,3 +7,11 @@ div.block-image {
.content > div:not(:last-child) {
margin-bottom: $content-block-margin-bottom;
}
+
+div.block-embed {
+ lite-youtube {
+ max-width: $embed_width;
+ min-width: $embed_width;
+ margin: 0 auto;
+ }
+}
diff --git a/static/src/scss/_variables.scss b/static/src/scss/_variables.scss
index e69de29..667c787 100644
--- a/static/src/scss/_variables.scss
+++ b/static/src/scss/_variables.scss
@@ -0,0 +1 @@
+$embed_width: 85%;
diff --git a/static/src/scss/lite-youtube-embed.scss b/static/src/scss/lite-youtube-embed.scss
new file mode 100644
index 0000000..62c1ebc
--- /dev/null
+++ b/static/src/scss/lite-youtube-embed.scss
@@ -0,0 +1 @@
+@import "lite-youtube-embed/src/lite-yt-embed";
diff --git a/templates/base.html b/templates/base.html
index c0a4763..a8c96bd 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -16,6 +16,7 @@
+
{% block extra_css %}{% endblock %}
@@ -40,6 +41,7 @@
+
{% block darkmode %}
diff --git a/website/common/embed.py b/website/common/embed.py
new file mode 100644
index 0000000..a2c0863
--- /dev/null
+++ b/website/common/embed.py
@@ -0,0 +1,38 @@
+import re
+
+from django.utils.html import format_html
+from wagtail.embeds.finders.oembed import OEmbedFinder
+from wagtail.embeds.oembed_providers import youtube
+
+
+class YouTubeLiteEmbedFinder(OEmbedFinder):
+ """
+ A modified OEmbed finder uses lite-youtube-embed instead
+
+ https://github.com/paulirish/lite-youtube-embed
+ """
+
+ EMBED_ID_RE = re.compile(r"\/embed\/(.*?)\?")
+
+ def __init__(
+ self, providers: list[dict] | None = None, options: dict | None = None
+ ):
+ super().__init__(providers=[youtube], options=options)
+
+ @classmethod
+ def _get_video_id(cls, html: str) -> str:
+ matched = cls.EMBED_ID_RE.search(html)
+ if matched is None:
+ raise ValueError(f"Unable to find video id in {html}")
+ return matched.group(1)
+
+ def find_embed(self, *args: list, **kwargs: dict) -> dict:
+ result = super().find_embed(*args, **kwargs)
+ video_id = self._get_video_id(result["html"])
+ result["html"] = format_html(
+ "",
+ video_id,
+ result["title"],
+ result["thumbnail_url"],
+ )
+ return result
diff --git a/website/common/tests.py b/website/common/tests.py
index 8bbfa72..660a769 100644
--- a/website/common/tests.py
+++ b/website/common/tests.py
@@ -1,5 +1,6 @@
from django.test import SimpleTestCase
+from .embed import YouTubeLiteEmbedFinder
from .models import BasePage
from .utils import get_page_models
@@ -15,3 +16,15 @@ class BasePageTestCase(SimpleTestCase):
issubclass(page_model, BasePage),
f"{page_model} does not inherit from {BasePage}.",
)
+
+
+class YouTubeLiteEmbedFinderTestCase(SimpleTestCase):
+ def test_finds_video_id(self) -> None:
+ self.assertEqual(
+ YouTubeLiteEmbedFinder._get_video_id(
+ ''
+ ),
+ "dQw4w9WgXcQ",
+ )
+ with self.assertRaises(ValueError):
+ YouTubeLiteEmbedFinder._get_video_id("something-else")
diff --git a/website/settings.py b/website/settings.py
index 819cf90..55ee0a1 100644
--- a/website/settings.py
+++ b/website/settings.py
@@ -144,6 +144,16 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
WAGTAILIMAGES_IMAGE_MODEL = "images.CustomImage"
+WAGTAILEMBEDS_FINDERS = [
+ {
+ "class": "website.common.embed.YouTubeLiteEmbedFinder",
+ },
+ {
+ "class": "wagtail.embeds.finders.oembed",
+ },
+]
+
+
if DEBUG:
# Add django-browser-reload
INSTALLED_APPS.append("django_browser_reload")