Inhaltsverzeichnis
keine Gliederung/* YOUTUBE LAZY LOAD - Ersetzt iframes durch Thumbnails */
.yt-lazy {
position: relative;
display: block;
cursor: pointer;
background: #000000;
overflow: hidden;
max-width: 100%;
}
.yt-lazy img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0.85;
transition: opacity 0.2s ease;
}
.yt-lazy:hover img {
opacity: 1.0;
}
.yt-lazy .yt-play {
position: absolute;
top: 50%;
left: 50%;
width: 72px;
height: 50px;
margin-left: -36px;
margin-top: -25px;
background: rgba(204, 0, 0, 0.9);
border-radius: 12px;
z-index: 10;
cursor: pointer;
transition: background 0.2s ease, transform 0.2s ease;
}
.yt-lazy:hover .yt-play {
background: rgba(255, 0, 0, 1);
transform: scale(1.1);
}
.yt-lazy .yt-play:after {
content: "";
position: absolute;
top: 50%;
left: 50%;
margin-left: -6px;
margin-top: -12px;
border-style: solid;
border-width: 12px 0 12px 22px;
border-color: transparent transparent transparent #FFFFFF;
}
.yt-lazy .yt-title {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 8px 12px;
background: rgba(0, 0, 0, 0.7);
color: #FFFFFF;
font-size: 13px;
font-family: Arial, Helvetica, sans-serif;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.yt-lazy.yt-loading .yt-play {
background: rgba(100, 100, 100, 0.8);
animation: yt-pulse 1s ease-in-out infinite;
}
@keyframes yt-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
(function () {
/* ============================================================
* YOUTUBE LAZY LOADER v2
* FIX 24.02.2026: Ersetzt YouTube iframes durch Thumbnails
* FIX 24.02.2026 v2: MutationObserver Loop gefixt
* - Geladene iframes werden mit data-yt-lazy="loaded" markiert
* - Observer ignoriert markierte iframes
* - Observer pausiert waehrend Replacement
* ============================================================ */
var PREFIX = '[YT-Lazy] ';
var ATTR = 'data-yt-lazy';
var initialized = false;
var isReplacing = false;
function log(msg) {
if (window.console && console.log) {
console.log(PREFIX + msg);
}
}
function extractVideoId(src) {
if (!src) return null;
var patterns = [
/\/embed\/([a-zA-Z0-9_-]{11})/,
/\/v\/([a-zA-Z0-9_-]{11})/,
/[?&]v=([a-zA-Z0-9_-]{11})/
];
for (var i = 0; i < patterns.length; i++) {
var match = src.match(patterns[i]);
if (match) return match[1];
}
return null;
}
function isYouTube(iframe) {
/* Bereits von uns geladen? Finger weg! */
if (iframe.getAttribute(ATTR)) return false;
var src = iframe.getAttribute('src') || '';
return src.indexOf('youtube.com') !== -1 ||
src.indexOf('youtube-nocookie.com') !== -1 ||
src.indexOf('youtu.be') !== -1;
}
function getEmbedParams(src) {
var params = '';
var qIndex = src.indexOf('?');
if (qIndex !== -1) {
params = src.substring(qIndex);
}
if (params.indexOf('autoplay') === -1) {
params += (params.indexOf('?') !== -1 ? '&' : '?') + 'autoplay=1';
}
return params;
}
function createPlaceholder(iframe, videoId) {
var src = iframe.getAttribute('src') || '';
var w = iframe.getAttribute('width') || iframe.style.width || '560';
var h = iframe.getAttribute('height') || iframe.style.height || '315';
var wStr = (w + '').indexOf('%') !== -1 ? w : w + 'px';
var hStr = (h + '').indexOf('%') !== -1 ? h : h + 'px';
var container = document.createElement('div');
container.className = 'yt-lazy';
container.setAttribute('data-video-id', videoId);
container.setAttribute('data-embed-params', getEmbedParams(src));
container.setAttribute('data-width', w);
container.setAttribute('data-height', h);
container.style.width = wStr;
container.style.height = hStr;
if (iframe.style.maxWidth) container.style.maxWidth = iframe.style.maxWidth;
if (iframe.style.margin) container.style.margin = iframe.style.margin;
var thumb = document.createElement('img');
thumb.src = 'https://img.youtube.com/vi/' + videoId + '/hqdefault.jpg';
thumb.alt = 'YouTube Video';
thumb.style.width = '100%';
thumb.style.height = '100%';
var playBtn = document.createElement('div');
playBtn.className = 'yt-play';
container.appendChild(thumb);
container.appendChild(playBtn);
function onClick(e) {
if (e && e.preventDefault) e.preventDefault();
if (e && e.stopPropagation) e.stopPropagation();
container.className += ' yt-loading';
log('Lade Video: ' + videoId);
var vid = container.getAttribute('data-video-id');
var params = container.getAttribute('data-embed-params');
var cw = container.getAttribute('data-width');
var ch = container.getAttribute('data-height');
var cwStr = (cw + '').indexOf('%') !== -1 ? cw : cw + 'px';
var chStr = (ch + '').indexOf('%') !== -1 ? ch : ch + 'px';
var newIframe = document.createElement('iframe');
newIframe.setAttribute('width', cw);
newIframe.setAttribute('height', ch);
newIframe.style.width = cwStr;
newIframe.style.height = chStr;
newIframe.setAttribute('frameborder', '0');
newIframe.setAttribute('allowfullscreen', '');
newIframe.setAttribute('allow', 'autoplay; encrypted-media');
/* KRITISCH: Markieren damit Observer diesen iframe ignoriert */
newIframe.setAttribute(ATTR, 'loaded');
newIframe.src = 'https://www.youtube-nocookie.com/embed/' + vid + params;
/* Observer pausieren waehrend Replacement */
isReplacing = true;
if (container.parentNode) {
container.parentNode.replaceChild(newIframe, container);
log('Video geladen: ' + vid);
}
/* Observer nach kurzer Pause wieder aktivieren */
setTimeout(function () {
isReplacing = false;
}, 500);
return false;
}
if (container.addEventListener) {
container.addEventListener('click', onClick, false);
} else if (container.attachEvent) {
container.attachEvent('onclick', onClick);
}
return container;
}
function processIframes() {
/* Wenn gerade ein Video geladen wird, nicht eingreifen */
if (isReplacing) return 0;
var iframes = document.getElementsByTagName('iframe');
var count = 0;
var toReplace = [];
for (var i = 0; i < iframes.length; i++) {
var iframe = iframes[i];
if (iframe.getAttribute(ATTR)) continue;
if (isYouTube(iframe)) {
var videoId = extractVideoId(iframe.getAttribute('src'));
if (videoId) {
toReplace.push({ iframe: iframe, videoId: videoId });
}
}
}
/* Pausiere Observer waehrend Batch-Replacement */
if (toReplace.length > 0) {
isReplacing = true;
}
for (var j = 0; j < toReplace.length; j++) {
var item = toReplace[j];
var placeholder = createPlaceholder(item.iframe, item.videoId);
if (item.iframe.parentNode) {
item.iframe.parentNode.replaceChild(placeholder, item.iframe);
count++;
}
}
if (toReplace.length > 0) {
setTimeout(function () {
isReplacing = false;
}, 500);
}
if (count > 0) {
log(count + ' YouTube iframe(s) durch Thumbnails ersetzt');
}
return count;
}
function init() {
if (initialized) {
log('SKIP: Bereits initialisiert (Singleton)');
return;
}
initialized = true;
log('Init v2 gestartet...');
var count = processIframes();
if (count === 0) {
log('Keine YouTube iframes gefunden');
}
if (window.MutationObserver) {
var observer = new MutationObserver(function (mutations) {
/* Waehrend Replacement nichts tun */
if (isReplacing) return;
var hasNew = false;
for (var i = 0; i < mutations.length; i++) {
var nodes = mutations[i].addedNodes;
if (!nodes) continue;
for (var j = 0; j < nodes.length; j++) {
var node = nodes[j];
/* Nur reagieren wenn ein unmarkierter iframe hinzugefuegt wurde */
if (node.tagName === 'IFRAME' && !node.getAttribute(ATTR)) {
hasNew = true;
break;
}
/* Oder ein Container der iframes enthaelt */
if (node.getElementsByTagName) {
var inner = node.getElementsByTagName('iframe');
for (var k = 0; k < inner.length; k++) {
if (!inner[k].getAttribute(ATTR)) {
hasNew = true;
break;
}
}
}
if (hasNew) break;
}
if (hasNew) break;
}
if (hasNew) {
processIframes();
}
});
observer.observe(document.body, { childList: true, subtree: true });
log('MutationObserver aktiv (dynamische iframes)');
}
log('Fertig!');
}
if (document.readyState === 'complete') {
init();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', init, false);
} else {
window.onload = init;
}
})();
NoElements {}