Fix Facebook in-app browser playback and document www SSL setup.

Mute autoplay and add faster loader fallback for FB/Instagram WebViews; document adding www.slavic-pulse.com in Dokploy to avoid self-signed cert errors on mobile.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-27 16:40:38 +02:00
parent d87ad674ee
commit e22c26798b
2 changed files with 49 additions and 11 deletions
+27 -3
View File
@@ -24,9 +24,12 @@ site-slavic-pulse-com/
**Kroki w Dokploy UI:**
1. Nowa aplikacja (Compose) → wklej `docker-compose-example/docker-compose.yml`
2. Wklej `.env` (na podstawie `.env.example`) — ustaw `VIDEO_ID_*`, opisy SEO
3. **Domains** → dodaj FQDN (np. `slavic-pulse.com`), **Container Port = `80`**
4. Traefik routuje ruch HTTPS → port 80 kontenera (bez mapowania portu na hosta)
5. Deploy
3. **Domains** → dodaj **oba** hosty (Container Port = `80`, HTTPS = Let's Encrypt):
- `slavic-pulse.com`
- `www.slavic-pulse.com`**wymagane** — bez tego www dostaje domyślny cert Traefika (CN=*, self-signed) i telefony pokazują „serwer nie potrafi udowodnić tożsamości”
4. (Opcjonalnie) **Advanced → Redirects** → preset **www → non-www**, żeby `www` przekierowywało na apex
5. Traefik routuje ruch HTTPS → port 80 kontenera (bez mapowania portu na hosta)
6. Deploy
**Porty:** nie używaj `ports:` w compose — Traefik/Dokploy łączy się z wewnętrznym `:80`.
W `docker ps` kolumna PORTS może być pusta — to normalne przy routingu przez Traefik.
@@ -84,3 +87,24 @@ Sprawdź w Dokploy UI: domena → Container Port = **80**, kontener `Up (healthy
1. Edytuj `.env` w Dokploy
2. Redeploy / restart kontenera (przy starcie ponownie klonuje repo i generuje HTML)
### Błąd certyfikatu SSL na telefonie („serwer nie potrafi udowodnić…”)
**Diagnoza (stan typowy):**
- `https://slavic-pulse.com` — certyfikat Let's Encrypt OK
- `https://www.slavic-pulse.com`**self-signed** (Traefik default, CN=`*`) → błąd na Androidzie / iPhone / WebView Facebooka
Strona wysyła `Strict-Transport-Security: includeSubDomains`, więc po wizycie na działającym apexie przeglądarka **wymusza HTTPS także na www** — a tam cert jest zły → twardy błąd.
**Naprawa w Dokploy (zalecane):**
1. **Domains****Add Domain**
2. Host: `www.slavic-pulse.com`, Port: `80`, HTTPS: włączone, Certificate: **letsencrypt**
3. Deploy / poczekaj ~30 s na wystawienie certyfikatu
4. Sprawdź: `curl -I https://www.slavic-pulse.com` (powinno być HTTP 200 lub 301, bez błędu SSL)
5. (Opcjonalnie) **Advanced → Redirects****www to non-www**
**Alternatywa w DNS (OVH):** zamiast rekordu A dla `www` ustaw przekierowanie HTTP na `https://slavic-pulse.com` w panelu domeny — wtedy ruch www nie trafia na serwer bez certyfikatu.
**Facebook / in-app browser:** linki w postach powinny wskazywać `https://slavic-pulse.com` (bez www). Po naprawie www problem znika także dla użytkowników, którzy wpiszą www ręcznie.
**Odnowienie certyfikatu:** Let's Encrypt odnawia cert automatycznie przez Traefik. Jeśli cert wygasa, w Dokploy sprawdź logi Traefik i czy port 80 jest dostępny z internetu (HTTP-01 challenge).
+22 -8
View File
@@ -168,6 +168,7 @@
redirectEnabled: ${POST_VIDEO_REDIRECT_ENABLED_VERTICAL_JS}
}
};
const SITE_ORIGIN = '${SITE_BASE_URL}';
let player;
let activeFormat;
let activeConfig;
@@ -176,6 +177,15 @@
const stageVideo = document.getElementById('stage-video');
const stage = document.getElementById('stage');
function isInAppBrowser() {
const ua = navigator.userAgent || '';
return /FBAN|FBAV|Instagram|Line\/|Twitter|LinkedInApp|wv\)/i.test(ua);
}
function hideLoader() {
loader.classList.add('hidden');
}
function youtubeThumbnailUrl(videoId, quality) {
return 'https://img.youtube.com/vi/' + videoId + '/' + (quality || 'maxresdefault') + '.jpg';
}
@@ -240,15 +250,21 @@
const stageBg = document.getElementById('stage-bg');
const bgPreload = new Image();
bgPreload.onload = () => loader.classList.add('hidden');
bgPreload.onload = hideLoader;
bgPreload.onerror = hideLoader;
if (stageBg && stageBg.src) {
bgPreload.src = stageBg.src;
} else {
hideLoader();
}
const tag = document.createElement('script');
tag.src = 'https://www.youtube.com/iframe_api';
tag.onerror = hideLoader;
document.head.appendChild(tag);
setTimeout(hideLoader, isInAppBrowser() ? 4000 : 15000);
function enableVideoSound() {
if (!player || typeof player.unMute !== 'function') return;
player.unMute();
@@ -264,7 +280,7 @@
videoId: activeConfig.id,
playerVars: {
autoplay: 1,
mute: 0,
mute: 1,
controls: 0,
showinfo: 0,
modestbranding: 1,
@@ -274,7 +290,7 @@
disablekb: 1,
iv_load_policy: 3,
cc_load_policy: 0,
origin: window.location.origin
origin: SITE_ORIGIN.replace(/\/$/, '')
},
events: {
onReady: onPlayerReady,
@@ -285,9 +301,11 @@
function onPlayerReady(event) {
sizeVideoCover();
enableVideoSound();
stageVideo.classList.add('active');
event.target.playVideo();
if (!isInAppBrowser()) {
enableVideoSound();
}
}
function onPlayerStateChange(event) {
@@ -315,10 +333,6 @@
window.addEventListener('resize', handleResize);
document.getElementById('stage-root').addEventListener('pointerdown', enableVideoSound, { once: true });
setTimeout(() => {
loader.classList.add('hidden');
}, 15000);
</script>
</body>
</html>