use JS IntersectionObserver to lazy load youtube videos

This commit is contained in:
rimu 2024-09-07 12:36:21 +12:00
parent dba016e05e
commit 760477f00c
5 changed files with 97 additions and 4 deletions

View file

@ -1072,14 +1072,15 @@ class Post(db.Model):
file = File.query.get(self.image_id)
file.delete_from_disk()
def youtube_embed(self) -> str:
def youtube_embed(self, rel=True) -> str:
if self.url:
parsed_url = urlparse(self.url)
query_params = parse_qs(parsed_url.query)
if 'v' in query_params:
video_id = query_params.pop('v')[0]
query_params['rel'] = '0'
if rel:
query_params['rel'] = '0'
new_query = urlencode(query_params, doseq=True)
return f'{video_id}?{new_query}'
@ -1087,7 +1088,8 @@ class Post(db.Model):
video_id = parsed_url.path.split('/shorts/')[1].split('/')[0]
if 't' in query_params:
query_params['start'] = query_params.pop('t')[0]
query_params['rel'] = '0'
if rel:
query_params['rel'] = '0'
new_query = urlencode(query_params, doseq=True)
return f'{video_id}?{new_query}'

View file

@ -10,6 +10,7 @@ if(!setTheme) {
// fires after DOM is ready for manipulation
document.addEventListener("DOMContentLoaded", function () {
setupYouTubeLazyLoad();
setupCommunityNameInput();
setupShowMoreLinks();
setupConfirmFirst();
@ -27,6 +28,42 @@ document.addEventListener("DOMContentLoaded", function () {
setupLightboxPostBody();
});
function setupYouTubeLazyLoad() {
const lazyVideos = document.querySelectorAll(".video-wrapper");
if ("IntersectionObserver" in window) {
let videoObserver = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let videoWrapper = entry.target;
let iframe = document.createElement("iframe");
iframe.src = videoWrapper.getAttribute("data-src");
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen";
videoWrapper.innerHTML = "";
videoWrapper.appendChild(iframe);
videoObserver.unobserve(videoWrapper);
}
});
});
lazyVideos.forEach((video) => {
videoObserver.observe(video);
});
} else {
// Fallback for older browsers
lazyVideos.forEach((video) => {
let iframe = document.createElement("iframe");
iframe.src = video.getAttribute("data-src");
iframe.allow = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen";
video.innerHTML = "";
video.appendChild(iframe);
});
}
}
// All elements with the class "showElement" will show the DOM element referenced by the data-id attribute
function setupShowElementLinks() {
var elements = document.querySelectorAll('.showElement');

View file

@ -911,6 +911,31 @@ div.navbar {
background-color: white;
opacity: 0.5;
}
.post_teaser_video_preview .video-wrapper {
position: relative;
padding-bottom: 56.25%;
/* 16:9 aspect ratio */
height: 0;
overflow: hidden;
background-color: #000;
}
.post_teaser_video_preview .video-wrapper img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
}
.post_teaser_video_preview .video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
.max_width_512 {
max-width: 512px;

View file

@ -503,6 +503,33 @@ div.navbar {
background-color: white;
opacity: 0.5;
}
.video-wrapper {
position: relative;
padding-bottom: 56.25%; /* 16:9 aspect ratio */
height: 0;
overflow: hidden;
background-color: #000;
}
.video-wrapper img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
cursor: pointer;
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
}
.max_width_512 {

View file

@ -43,7 +43,9 @@
<div style="padding-bottom: 56.25%; position: relative;"><iframe style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%;" src="{{ post.url.replace('redgifs.com/watch/', 'redgifs.com/ifr/') }}" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; fullscreen" width="100%" height="100%" frameborder="0"></iframe></div>
{% endif -%}
{% if 'youtube.com' in post.url -%}
<div style="padding-bottom: 56.25%; position: relative;"><iframe style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%;" src="https://www.youtube.com/embed/{{ post.youtube_embed() }}" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; fullscreen" width="100%" height="100%" frameborder="0"></iframe></div>
<div class="video-wrapper" data-src="https://www.youtube.com/embed/{{ post.youtube_embed() }}">
<img src="https://img.youtube.com/vi/{{ post.youtube_embed(rel=False) }}/hqdefault.jpg" alt="Video Thumbnail">
</div>
{% endif -%}
{% if 'videos/watch' in post.url -%}
<div style="padding-bottom: 56.25%; position: relative;"><iframe style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%;" src="{{ post.peertube_embed() }}" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture; fullscreen" width="100%" height="100%" frameborder="0"></iframe></div>