From e22c26798b7dc07191a579a24db817336e9a1a77 Mon Sep 17 00:00:00 2001 From: tomasz-syn-grzegorza Date: Sat, 27 Jun 2026 16:40:38 +0200 Subject: [PATCH] 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 --- docker-compose-example/README.md | 30 +++++++++++++++++++++++++++--- index.html.template | 30 ++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/docker-compose-example/README.md b/docker-compose-example/README.md index d00153a..dfba16d 100644 --- a/docker-compose-example/README.md +++ b/docker-compose-example/README.md @@ -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). diff --git a/index.html.template b/index.html.template index d311678..58653fb 100644 --- a/index.html.template +++ b/index.html.template @@ -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);