PageSourceSearch

https://www.freistaedter-motorshow.at/lib/Sonstjs/videoplayer.js?20260101

js freistaedter-motorshow.at collected 2026-10-08 03:28:36 UTC 8,738 bytes, 137 lines download raw bytes

1// VIDEO, SOUNDCLOUD - Universal Lazy Embed Script - Final Version - 25.10.2025
2document.addEventListener("DOMContentLoaded", function() {
3    const lazyPlaceholders = document.querySelectorAll(".lazy-embed-placeholder");
4
5    if (lazyPlaceholders.length === 0) return;
6
7    const translations = {
8        de: { withSound: "Mit Ton", noSound: "Ohne Ton" },
9        en: { withSound: "With Sound", noSound: "No Sound" }
10    };
11
12    const getLanguage = () => {
13        const lang = document.documentElement.lang.split('-')[0];
14        return translations[lang] ? lang : 'de';
15    };
16
17    const currentTranslations = translations[getLanguage()];
18
19    const loadMedia = (placeholder, isMuted) => {
20        const provider = placeholder.dataset.provider;
21        const videoId = placeholder.dataset.videoId;
22        let iframeHtml = '';
23        const mutedParam = isMuted ? 1 : 0;
24
25        if (provider === "youtube") {
26            iframeHtml = `<iframe src="https://www.youtube.com/embed/${videoId}?rel=0&autoplay=1&mute=${mutedParam}&playsinline=1" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`;
27        } else if (provider === "vimeo") {
28            iframeHtml = `<iframe src="https://player.vimeo.com/video/${videoId}?autoplay=1&muted=${mutedParam}&title=0&byline=0&portrait=0" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>`;
29        } else if (provider === "soundcloud") {
30            const trackUrl = placeholder.dataset.trackUrl;
31            // KORREKTUR: Der Iframe wird jetzt ebenfalls absolut positioniert, um den Container korrekt auszufüllen.
32            iframeHtml = `<iframe style="position:absolute;top:0;left:0;width:100%;height:100%;" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=${encodeURIComponent(trackUrl)}&color=%23ff5500&auto_play=true&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true"></iframe>`;
33        }
34        
35        if (iframeHtml) {
36            placeholder.innerHTML = iframeHtml;
37            placeholder.classList.add('media-loaded');
38        }
39    };
40
41    const handleInteraction = (event) => {
42        const placeholder = event.currentTarget;
43        const provider = placeholder.dataset.provider;
44        const isMobile = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
45
46        if (isMobile && provider !== 'soundcloud') {
47            loadMedia(placeholder, true); 
48        } else {
49            if (provider === 'soundcloud') {
50                loadMedia(placeholder, false);
51                return;
52            }
53            const overlay = document.createElement('div');
54            overlay.className = 'sound-choice-overlay';
55            const soundOnIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"></path></svg>';
56            const soundOffIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"></path></svg>';
57            
58            const withSoundButton = document.createElement('button');
59            withSoundButton.className = 'sound-choice-button';
60            withSoundButton.innerHTML = `${soundOnIcon} <span>${currentTranslations.withSound}</span>`;
61            withSoundButton.onclick = (e) => { e.stopPropagation(); loadMedia(placeholder, false); };
62
63            const withoutSoundButton = document.createElement('button');
64            withoutSoundButton.className = 'sound-choice-button';
65            withoutSoundButton.innerHTML = `${soundOffIcon} <span>${currentTranslations.noSound}</span>`;
66            withoutSoundButton.onclick = (e) => { e.stopPropagation(); loadMedia(placeholder, true); };
67            
68            const playButton = placeholder.querySelector('.play-button');
69            if (playButton) { playButton.remove(); }
70            
71            overlay.appendChild(withSoundButton);
72            overlay.appendChild(withoutSoundButton);
73            placeholder.appendChild(overlay);
74        }
75    };
76
77    const initializePlaceholder = async (placeholder) => {
78        const provider = placeholder.dataset.provider;
79        const videoId = placeholder.dataset.videoId;
80        
81        if (placeholder.querySelector('.lazy-embed-thumbnail')) { return; }
82
83        const thumbnailElement = document.createElement('img');
84        thumbnailElement.className = 'lazy-embed-thumbnail';
85        thumbnailElement.alt = 'Vorschaubild';
86        Object.assign(thumbnailElement.style, { position: 'absolute', top: '0', left: '0', width: '100%', height: '100%', objectFit: 'cover', zIndex: '1' });
87        
88        const playButton = placeholder.querySelector('.play-button');
89        if (playButton) { Object.assign(playButton.style, { zIndex: '2' }); }
90        
91        placeholder.prepend(thumbnailElement);
92
93        thumbnailElement.onerror = function() {
94            thumbnailElement.style.display = 'none';
95            if (placeholder.querySelector('.thumbnail-error-message')) return;
96            const errorMessage = document.createElement('div');
97            errorMessage.className = 'thumbnail-error-message';
98            errorMessage.innerHTML = 'Vorschaubild konnte nicht geladen werden.<br>Möglicherweise blockiert durch Browser- oder Virenschutz.';
99            Object.assign(errorMessage.style, { position: 'absolute', top: '0', left: '0', width: '100%', height: '100%', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', backgroundColor: '#EAEAEA', color: '#333', textAlign: 'center', padding: '20px 10px', boxSizing: 'border-box', zIndex: '1' });
100            placeholder.prepend(errorMessage);
101        };
102
103        try {
104            if (provider === "youtube") {
105                const urlsToTry = [`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`, `https://i.ytimg.com/vi/${videoId}/sddefault.jpg`, `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`];
106                let thumbnailUrl = urlsToTry[urlsToTry.length - 1];
107                for (const url of urlsToTry) { try { const response = await fetch(url, { method: 'HEAD' }); if (response.ok) { thumbnailUrl = url; break; } } catch (e) {} }
108                thumbnailElement.src = thumbnailUrl;
109            } else if (provider === "vimeo") {
110                const response = await fetch(`https://vimeo.com/api/oembed.json?url=https://vimeo.com/${videoId}`);
111                if (response.ok) {
112                    const data = await response.json();
113                    if (data.thumbnail_url) { thumbnailElement.src = data.thumbnail_url.replace(/_\d+x?\d*/, ''); } 
114                    else { thumbnailElement.onerror(); }
115                } else { thumbnailElement.onerror(); }
116            } else if (provider === "soundcloud") {
117                const trackUrl = placeholder.dataset.trackUrl;
118                if (trackUrl) {
119                    const oembedUrl = `https://soundcloud.com/oembed?url=${encodeURIComponent(trackUrl)}&format=json`;
120                    const oembedResponse = await fetch(oembedUrl);
121                    if (oembedResponse.ok) {
122                        const oembedData = await oembedResponse.json();
123                        if (oembedData.thumbnail_url) { thumbnailElement.src = oembedData.thumbnail_url; } 
124                        else { thumbnailElement.onerror(); }
125                    }
126                }
127            }
128        } catch (error) { thumbnailElement.onerror(); }
129    };
130
131    if ("IntersectionObserver" in window) {
132        const observer = new IntersectionObserver((entries, obs) => { entries.forEach(entry => { if (entry.isIntersecting) { const placeholder = entry.target; initializePlaceholder(placeholder); obs.unobserve(placeholder); } }); });
133        lazyPlaceholders.forEach(placeholder => { observer.observe(placeholder); placeholder.addEventListener('click', handleInteraction, { once: true }); });
134    } else {
135        lazyPlaceholders.forEach(placeholder => { initializePlaceholder(placeholder); placeholder.addEventListener('click', handleInteraction, { once: true }); });
136    }
137});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.