Baraag Unspoiler NSFW Images

Remove sensitive content spoilers from images and videos on baraag

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         Baraag Unspoiler NSFW Images
// @version      1.4
// @description  Remove sensitive content spoilers from images and videos on baraag
// @match        https://baraag.net/*
// @license      public domain
// @namespace    https://sleazyfork.org/users/1468364
// ==/UserScript==

(function() {
	'use strict';

	function hideHideButton() {
		const observer = new MutationObserver((mutations) => {
			document.querySelectorAll('.media-gallery__actions').forEach((el) => {
				if (el.style.display !== 'none') {
					el.style.display = 'none';
				}
			});
		});

		observer.observe(document.body, {
			childList: true,
			subtree: true,
		});
	}

	function isUserProfilePage() {
		return /^\/@[^\/]+(\/with_replies)?$/.test(window.location.pathname);
	}

	// Helper to verify poster image validity
	function verifyAndFixVideoPoster(video) {
		// Prevent double checking the specific video element
		if (video.dataset.posterChecked) return;

		const posterUrl = video.getAttribute('poster');

		if (posterUrl) {
			const img = new Image();

			img.onload = function() {
				// Check dimensions. 0x0 means a 0-byte or broken image
				if (this.naturalWidth === 0 || this.naturalHeight === 0) {
					video.removeAttribute('poster');
					video.setAttribute('preload', 'metadata');
				}
				video.dataset.posterChecked = 'true';
			};

			img.onerror = function() {
				video.removeAttribute('poster');
				video.setAttribute('preload', 'metadata');
				video.dataset.posterChecked = 'true';
			};

			img.src = posterUrl;
		} else {
			// No poster: Ensure we load metadata
			video.setAttribute('preload', 'metadata');
			video.dataset.posterChecked = 'true';
		}
	}

	// Process videos
	function processVideoPlayer(videoPlayer) {
		// Only stop if we have successfully found AND processed the video tag before.
		// If the video tag was missing on previous runs, we want to check again.
		if (videoPlayer.dataset.unspoilerComplete === 'fixed') {
			return;
		}

		// 1. Handle Spoiler Button
		const spoilerButtonDiv = videoPlayer.querySelector('.spoiler-button');
		if (spoilerButtonDiv && !spoilerButtonDiv.classList.contains('spoiler-button--hidden')) {
			const spoilerButton = videoPlayer.querySelector('.spoiler-button button');
			if (spoilerButton && !spoilerButton.dataset.unspoilerClicked) {
				spoilerButton.dataset.unspoilerClicked = 'true';
				spoilerButton.click();
			}
			// Hide canvas manually just in case
			const canvas = videoPlayer.querySelector('.media-gallery__preview');
			if (canvas) canvas.classList.add('media-gallery__preview--hidden');
		}

		// 2. Handle Video Tag (This might not exist yet due to lazy loading)
		const video = videoPlayer.querySelector('video');
		if (video) {
			verifyAndFixVideoPoster(video);
			// Only mark complete if we actually found and processed the video element
			videoPlayer.dataset.unspoilerComplete = 'fixed';
		} else {
			// Video tag is missing (lazy loaded).
			// Do NOT mark as complete. The MutationObserver will trigger again when
			// the site injects the video tag, allowing us to process it then.
		}
	}

	function processStatusCards() {
		document.querySelectorAll('.status-card__image-image').forEach(img => {
			if (img.style.visibility !== 'visible') {
				img.style.visibility = 'visible';
				const parentDiv = img.closest('.status-card__image');
				if (parentDiv) {
					parentDiv.parentNode.insertBefore(img, parentDiv);
				}
			}
		});
	}

	function processAllContent() {
		document.querySelectorAll('.video-player').forEach(videoPlayer => {
			processVideoPlayer(videoPlayer);
		});

		if (!window.location.pathname.includes('/media')) {
			document.querySelectorAll('.spoiler-button:not(.unspoiler-processed)').forEach(spoiler => {
				if (spoiler.closest('.video-player')) return;
				spoiler.classList.add('unspoiler-processed');
				const button = spoiler.querySelector('button');
				if (button && !button.dataset.unspoilerClicked) {
					button.dataset.unspoilerClicked = 'true';
					button.click();
				}
			});
		}

		if (window.location.pathname.includes('/media')) {
			document.querySelectorAll('.media-gallery__item').forEach(item => {
				const hasSpoilerOverlay = item.querySelector('.media-gallery__item__overlay .icon-eye-slash');
				if (!item.querySelector('img') && hasSpoilerOverlay) {
					const thumbnail = item.querySelector('.media-gallery__item-thumbnail');
					if (thumbnail && !thumbnail.dataset.unspoilerProcessed) {
						thumbnail.dataset.unspoilerProcessed = 'true';
						thumbnail.click();
					}
				}
			});
		}

		processStatusCards();
	}

	function initObserver() {
		const observer = new MutationObserver(mutations => {
			let needsProcessing = false;
			let hasNewVideos = false;

			mutations.forEach(mutation => {
				mutation.addedNodes.forEach(node => {
					if (node.nodeType === 1) {
						if (node.matches('.video-player')) hasNewVideos = true;
						else if (node.querySelector('.video-player')) hasNewVideos = true;
					}
				});
				if (mutation.addedNodes.length) needsProcessing = true;
			});

			if (needsProcessing) {
				if (hasNewVideos && isUserProfilePage()) {
					setTimeout(processAllContent, 100);
				} else {
					debouncedProcess();
				}
			}
		});

		observer.observe(document.body, { childList: true, subtree: true });
	}

	const debouncedProcess = debounce(processAllContent, 1);

	function debounce(func, wait) {
		let timeout;
		return function() {
			clearTimeout(timeout);
			timeout = setTimeout(func, wait);
		};
	}

	function init() {
		hideHideButton();
		processAllContent();
		initObserver();

		window.addEventListener('scroll', debounce(function() {
			const scrollThreshold = window.innerHeight * 2;
			if (document.documentElement.scrollHeight - window.scrollY - window.innerHeight < scrollThreshold) {
				var loadMoreButton = document.querySelector('.load-more');
				if (loadMoreButton) {
					loadMoreButton.click();
				}
			}
		}, 100));
	}

	if (document.readyState !== 'loading') {
		init();
	} else {
		document.addEventListener('DOMContentLoaded', init);
	}
})();