From 6688db6145977ef317d7550e2cc4c1adf6bf2f9f Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Sat, 23 May 2026 23:23:31 +0200 Subject: [PATCH] require item revealing when user wants it --- public/s/css/f0ckm.css | 82 ++++++++++++++++++++++++++++++++++ public/s/js/f0ckm.js | 25 +++++++++++ public/s/js/settings.js | 14 ++++++ public/s/js/v0ck.js | 22 ++++++++- src/inc/locales/de.json | 2 + src/inc/locales/en.json | 2 + src/inc/locales/nl.json | 2 + views/item-partial-legacy.html | 2 +- views/item-partial-modern.html | 2 +- views/settings.html | 7 +++ views/snippets/item-media.html | 2 +- 11 files changed, 158 insertions(+), 4 deletions(-) diff --git a/public/s/css/f0ckm.css b/public/s/css/f0ckm.css index cdbb6f4..3972b6b 100644 --- a/public/s/css/f0ckm.css +++ b/public/s/css/f0ckm.css @@ -14733,4 +14733,86 @@ body.scroller-active #gchat-reopen-bubble { padding: 0 !important; font-size: 11px !important; line-height: 1 !important; +} + +/* Post detail page media-object blur overlay support (NSFW, NSFL, SFW, Untagged) */ +.blur-detail-active.blur-nsfw-active .media-object[data-mode="nsfw"]:not(.revealed), +.blur-detail-active.blur-nsfl-active .media-object[data-mode="nsfl"]:not(.revealed), +.blur-detail-active.blur-sfw-active .media-object[data-mode="sfw"]:not(.revealed), +.blur-detail-active.blur-untagged-active .media-object[data-mode="untagged"]:not(.revealed) { + position: relative !important; + cursor: pointer !important; +} + +.blur-detail-active.blur-nsfw-active .media-object[data-mode="nsfw"]:not(.revealed) > *, +.blur-detail-active.blur-nsfl-active .media-object[data-mode="nsfl"]:not(.revealed) > *, +.blur-detail-active.blur-sfw-active .media-object[data-mode="sfw"]:not(.revealed) > *, +.blur-detail-active.blur-untagged-active .media-object[data-mode="untagged"]:not(.revealed) > * { + filter: blur(40px) brightness(0.6) !important; + -webkit-filter: blur(40px) brightness(0.6) !important; + pointer-events: none !important; + user-select: none !important; + transition: filter 0.35s ease, -webkit-filter 0.35s ease !important; +} + +.media-object.revealed > * { + filter: none !important; + -webkit-filter: none !important; + pointer-events: auto !important; +} + +.blur-detail-active.blur-nsfw-active .media-object[data-mode="nsfw"]:not(.revealed)::after, +.blur-detail-active.blur-nsfl-active .media-object[data-mode="nsfl"]:not(.revealed)::after, +.blur-detail-active.blur-sfw-active .media-object[data-mode="sfw"]:not(.revealed)::after, +.blur-detail-active.blur-untagged-active .media-object[data-mode="untagged"]:not(.revealed)::after { + position: absolute !important; + inset: 0 !important; + display: flex !important; + flex-direction: column !important; + align-items: center !important; + justify-content: center !important; + z-index: 1000 !important; + color: #fff !important; + font-family: inherit !important; + font-weight: 800 !important; + letter-spacing: 2px !important; + text-transform: uppercase !important; + text-align: center !important; + white-space: pre-wrap !important; + cursor: pointer !important; + transition: opacity 0.35s cubic-bezier(0.25, 1, 0.5, 1) !important; + text-shadow: 0 2px 10px rgba(0, 0, 0, 0.9) !important; + pointer-events: none !important; + opacity: 1 !important; +} + +.blur-detail-active.blur-nsfw-active .media-object[data-mode="nsfw"]:not(.revealed)::after { + content: "NSFW\A \A Click to reveal" !important; + font-size: 18px !important; + color: #ffffff !important; + background: rgba(10, 10, 12, 0.45) !important; +} +.blur-detail-active.blur-nsfl-active .media-object[data-mode="nsfl"]:not(.revealed)::after { + content: "NSFL\A \A Click to reveal" !important; + font-size: 18px !important; + color: #ff3b30 !important; + background: rgba(10, 10, 12, 0.55) !important; +} +.blur-detail-active.blur-sfw-active .media-object[data-mode="sfw"]:not(.revealed)::after { + content: "SFW\A \A Click to reveal" !important; + font-size: 18px !important; + color: #30d158 !important; + background: rgba(10, 10, 12, 0.4) !important; +} +.blur-detail-active.blur-untagged-active .media-object[data-mode="untagged"]:not(.revealed)::after { + content: "UNTAGGED\A \A Click to reveal" !important; + font-size: 18px !important; + color: #ff9f0a !important; + background: rgba(10, 10, 12, 0.45) !important; +} + +/* Hide overlay when revealed */ +.media-object.revealed::after { + opacity: 0 !important; + pointer-events: none !important; } \ No newline at end of file diff --git a/public/s/js/f0ckm.js b/public/s/js/f0ckm.js index bd89c99..c625422 100644 --- a/public/s/js/f0ckm.js +++ b/public/s/js/f0ckm.js @@ -44,6 +44,7 @@ window.cancelAnimFrame = (function () { if (localStorage.getItem('blurNsfl') === 'true') htmlEl.classList.add('blur-nsfl-active'); if (localStorage.getItem('blurSfw') === 'true') htmlEl.classList.add('blur-sfw-active'); if (localStorage.getItem('blurUntagged') === 'true') htmlEl.classList.add('blur-untagged-active'); + if (localStorage.getItem('blurDetail') !== 'false') htmlEl.classList.add('blur-detail-active'); window.updateVisitIndicators = () => { try { @@ -8827,6 +8828,30 @@ if (navigator.vibrate) { const blurUntagged = localStorage.getItem('blurUntagged') === 'true'; if (!blurNsfw && !blurNsfl && !blurSfw && !blurUntagged) return; + // Check if they clicked a blurred media-object container on the detail page + const mediaObj = e.target.closest('.media-object'); + if (mediaObj && localStorage.getItem('blurDetail') !== 'false') { + const mode = mediaObj.getAttribute('data-mode'); + let shouldBlurThis = false; + if (mode === 'nsfw') shouldBlurThis = blurNsfw; + else if (mode === 'nsfl') shouldBlurThis = blurNsfl; + else if (mode === 'sfw') shouldBlurThis = blurSfw; + else if (mode === 'untagged') shouldBlurThis = blurUntagged; + + if (shouldBlurThis && !mediaObj.classList.contains('revealed')) { + e.preventDefault(); + e.stopPropagation(); + mediaObj.classList.add('revealed'); + + // Start audio/video playback cleanly on reveal + const videoElem = mediaObj.querySelector('video') || mediaObj.querySelector('audio'); + if (videoElem) { + videoElem.play().catch(() => {}); + } + return; + } + } + // Check if they clicked the elegant hide-again button in the corner const hideBtn = e.target.closest('.hide-thumb-btn'); if (hideBtn) { diff --git a/public/s/js/settings.js b/public/s/js/settings.js index 4654612..8d34184 100644 --- a/public/s/js/settings.js +++ b/public/s/js/settings.js @@ -779,6 +779,20 @@ showStatus(enabled ? 'Untagged blurring enabled!' : 'Untagged blurring disabled!', 'success'); }); } + const blurDetailToggle = document.getElementById('blur_detail_toggle'); + if (blurDetailToggle) { + blurDetailToggle.checked = localStorage.getItem('blurDetail') !== 'false'; + blurDetailToggle.addEventListener('change', () => { + const enabled = blurDetailToggle.checked; + localStorage.setItem('blurDetail', enabled ? 'true' : 'false'); + if (enabled) { + document.documentElement.classList.add('blur-detail-active'); + } else { + document.documentElement.classList.remove('blur-detail-active'); + } + showStatus(enabled ? 'Detail page blurring enabled!' : 'Detail page blurring disabled!', 'success'); + }); + } // Background Blur Toggle const backgroundToggle = document.getElementById('show_background_toggle'); diff --git a/public/s/js/v0ck.js b/public/s/js/v0ck.js index 84a1fcc..50d7560 100644 --- a/public/s/js/v0ck.js +++ b/public/s/js/v0ck.js @@ -421,8 +421,28 @@ class v0ck { video.volume = _volume = volumeSlider.value = +(localStorage.getItem('volume') ?? defaultVolume); handleVolumeButton(video.volume); + const mediaObj = player.closest('.media-object'); + let isBlurredDetail = false; + if (mediaObj && localStorage.getItem('blurDetail') !== 'false') { + const mode = mediaObj.getAttribute('data-mode'); + const blurNsfw = localStorage.getItem('blurNsfw') === 'true'; + const blurNsfl = localStorage.getItem('blurNsfl') === 'true'; + const blurSfw = localStorage.getItem('blurSfw') === 'true'; + const blurUntagged = localStorage.getItem('blurUntagged') === 'true'; + + let shouldBlurThis = false; + if (mode === 'nsfw') shouldBlurThis = blurNsfw; + else if (mode === 'nsfl') shouldBlurThis = blurNsfl; + else if (mode === 'sfw') shouldBlurThis = blurSfw; + else if (mode === 'untagged') shouldBlurThis = blurUntagged; + + if (shouldBlurThis && !mediaObj.classList.contains('revealed')) { + isBlurredDetail = true; + } + } + // Attempt autoplay and show overlay if blocked - const shouldAutoplay = window.f0ckSession?.disable_autoplay !== true; + const shouldAutoplay = !isBlurredDetail && window.f0ckSession?.disable_autoplay !== true; if (shouldAutoplay) { const playPromise = togglePlay(); if (playPromise !== undefined) { diff --git a/src/inc/locales/de.json b/src/inc/locales/de.json index 8906056..55e2c71 100644 --- a/src/inc/locales/de.json +++ b/src/inc/locales/de.json @@ -158,6 +158,8 @@ "blur_sfw_hint": "Zeichnet SFW-Vorschaubilder weich.", "blur_untagged": "Unmarkierte weichzeichnen", "blur_untagged_hint": "Zeichnet unmarkierte Vorschaubilder weich.", + "blur_detail": "Beiträge weichzeichnen", + "blur_detail_hint": "Erfordert das Anklicken zum Anzeigen von weichgezeichneten Medien auf der Beitragsseite.", "render_emojis": "Emojis in Zitatantworten anzeigen", "render_emojis_hint": ":emoji:-Bilder in >zitierten Zeilen anzeigen", "embed_yt": "YouTube-Videos in Kommentaren einbetten", diff --git a/src/inc/locales/en.json b/src/inc/locales/en.json index dec05fb..3ba85f6 100644 --- a/src/inc/locales/en.json +++ b/src/inc/locales/en.json @@ -158,6 +158,8 @@ "blur_sfw_hint": "Blur SFW-rated thumbnails.", "blur_untagged": "Blur Untagged", "blur_untagged_hint": "Blur thumbnails with no tags or rating.", + "blur_detail": "Click to reveal item on detail page", + "blur_detail_hint": "Require clicking to reveal blurred media on the post detail page.", "render_emojis": "Render emojis in quote replies", "render_emojis_hint": "Show :emoji: images inside >quoted lines", "embed_yt": "Embed YouTube links in comments", diff --git a/src/inc/locales/nl.json b/src/inc/locales/nl.json index e432747..a25eb2d 100644 --- a/src/inc/locales/nl.json +++ b/src/inc/locales/nl.json @@ -158,6 +158,8 @@ "blur_sfw_hint": "Vervaagt SFW-thumbnails.", "blur_untagged": "Ongetagde vervagen", "blur_untagged_hint": "Vervaagt ongetagde thumbnails.", + "blur_detail": "Details weigeren direct te tonen (vervagen)", + "blur_detail_hint": "Vereist klikken om vervaagde media op de detailpagina te onthullen.", "render_emojis": "Emoji's weergeven in antwoorden", "render_emojis_hint": "Toon :emoji: afbeeldingen binnen >geciteerde regels", "embed_yt": "YouTube-links insluiten in opmerkingen", diff --git a/views/item-partial-legacy.html b/views/item-partial-legacy.html index a7af923..64da84c 100644 --- a/views/item-partial-legacy.html +++ b/views/item-partial-legacy.html @@ -22,7 +22,7 @@ @endif -
+
@include(snippets/item-media)
@endif
-
+
@include(snippets/item-media)
+
+ + {{ t('settings.blur_detail_hint') || 'Require clicking to reveal blurred media on the post detail page instead of showing it immediately.' }} +
@elseif(item.mime.startsWith("audio"))
- +
@elseif(item.mime.startsWith("image"))