Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name /bag/ filter
- // @namespace http://tampermonkey.net/
- // @version 1.7.8-fx
- // @description Hides non whitelisted images. Images are whitelisted after 15 minutes of the post not being deleted. Excludes GIF, MP4, and WEBM files.
- // @author Anonymous
- // @match https://boards.4chan.org/vg*
- // @grant none
- // ==/UserScript==
- (function () {
- 'use strict';
- // Check for a thread.
- if (!/^bag\/|\/bag\/|Blue Archive|BIue Archive/.test(document?.querySelector('.postInfo.desktop .subject')?.textContent?.trim() ?? '')) return;
- const ADD_TO_WHITELIST_TIMEOUT_MS = 15 * 60 * 1000;
- const MD5_WHITELIST_KEY = 'bagFilter';
- const IS_DISABLED_KEY = 'bagFilterDisabled';
- const FILTERED_CSS_CLASS = 'bag-filter-filtered';
- const FILTER_STYLES = `
- .fileThumb img:not(.full-image).${FILTERED_CSS_CLASS} {
- width: 50px !important;
- height: 50px !important;
- opacity: 0 !important;
- }
- .fileThumb:hover img:not(.full-image).${FILTERED_CSS_CLASS} {
- width: auto !important;
- height: auto !important;
- opacity: 1 !important;
- z-index: 100;
- }`;
- const fileTypeRegex = /\.(gif|mp4|webm)$/i;
- function isExcludedFileType(post) {
- const fileText = post.querySelector('.fileText-original, .fileText');
- if (fileText) {
- const fileLink = fileText.querySelector('a');
- if (fileLink && fileLink.href) {
- return fileTypeRegex.test(fileLink.href);
- }
- }
- return false;
- }
- const styleSheet = document.createElement('style');
- document.head.appendChild(styleSheet);
- const opLinks = document.querySelector('.opContainer .fileText');
- const toggleLink = document.createElement('a');
- toggleLink.href = '#';
- opLinks.appendChild(document.createTextNode(' '));
- opLinks.appendChild(toggleLink);
- toggleLink.onclick = () => {
- window.localStorage.setItem(IS_DISABLED_KEY, String(!isDisabled()));
- updateToggle();
- };
- function isDisabled() {
- return window.localStorage.getItem(IS_DISABLED_KEY) === 'true';
- }
- function updateToggle() {
- if (isDisabled()) {
- toggleLink.textContent = 'enable bag filter';
- styleSheet.textContent = '';
- } else {
- toggleLink.textContent = 'disable bag filter';
- styleSheet.textContent = FILTER_STYLES;
- }
- }
- const md5Whitelist = new Set(JSON.parse(window.localStorage.getItem(MD5_WHITELIST_KEY) || '[]'));
- function update() {
- if (isDisabled()) {
- return;
- }
- const addToWhitelistPostTime = Date.now() - ADD_TO_WHITELIST_TIMEOUT_MS;
- const posts = document.querySelectorAll('.replyContainer:has(.fileThumb)');
- let md5WhitelistChanged = false;
- for (const post of posts) {
- if (isExcludedFileType(post)) {
- continue;
- }
- const postTime = Number(post.querySelector('.dateTime').dataset.utc) * 1000;
- const thumbnail = post.querySelector('img:not(.full-image)');
- if (!thumbnail) continue;
- const md5 = thumbnail.dataset.md5;
- const otherFiltersMatch = imageSizeMatch(post);
- if (post.hasAttribute('hidden')) {
- if (md5Whitelist.has(md5)) {
- md5Whitelist.delete(md5);
- md5WhitelistChanged = true;
- }
- } else if (postTime < addToWhitelistPostTime && !post.classList.contains('deleted-post')) {
- if (!md5Whitelist.has(md5) && otherFiltersMatch) {
- md5Whitelist.add(md5);
- md5WhitelistChanged = true;
- }
- }
- if (md5Whitelist.has(md5) || !otherFiltersMatch) {
- thumbnail.classList.remove(FILTERED_CSS_CLASS);
- } else {
- thumbnail.classList.add(FILTERED_CSS_CLASS);
- }
- }
- if (md5WhitelistChanged) {
- window.localStorage.setItem(MD5_WHITELIST_KEY, JSON.stringify([...md5Whitelist]));
- }
- }
- function imageSizeMatch(post) {
- const fileText = post.querySelector('.fileText-original, .fileText')?.textContent;
- if (fileText) {
- const matchInKB = fileText.match(/\((\d+(?:\.\d+)?)\s*KB/i);
- if (matchInKB) {
- const sizeInKB = parseFloat(matchInKB[1]);
- return sizeInKB >= 20;
- }
- const matchInMB = fileText.match(/\((\d+(?:\.\d+)?)\s*MB/i);
- if (matchInMB) {
- const sizeInMB = parseFloat(matchInMB[1]);
- return sizeInMB >= 1;
- }
- }
- return false;
- }
- // Handle the shift + right-click event.
- function handleRightClick(event) {
- // Check if Shift key is pressed.
- if (!event.shiftKey) return;
- // Prevent the default context menu.
- event.preventDefault();
- const thumbnail = event.currentTarget; // Use currentTarget to get the bound image
- const md5 = thumbnail.dataset.md5;
- if (md5 && !md5Whitelist.has(md5)) {
- md5Whitelist.add(md5);
- window.localStorage.setItem(MD5_WHITELIST_KEY, JSON.stringify([...md5Whitelist]));
- thumbnail.classList.remove(FILTERED_CSS_CLASS); // Immediately show the image
- }
- }
- // Additional mousedown handler for Firefox.
- function mousedownHandler(event) {
- if (event.button === 2 && event.shiftKey) {
- // Prevent default and handle the event as a right-click.
- event.preventDefault();
- handleRightClick(event);
- }
- }
- // Attach right-click and mousedown listeners to all image thumbnails.
- function addRightClickListeners() {
- const images = document.querySelectorAll('.replyContainer .fileThumb img:not(.full-image)');
- images.forEach(image => {
- // Skip if parent post has excluded file type
- const post = image.closest('.replyContainer');
- if (post && isExcludedFileType(post)) {
- return;
- }
- // Remove any existing listeners to avoid duplication.
- image.removeEventListener('contextmenu', handleRightClick);
- image.removeEventListener('mousedown', mousedownHandler);
- // Add listeners for both contextmenu and mousedown events.
- image.addEventListener('contextmenu', handleRightClick);
- image.addEventListener('mousedown', mousedownHandler);
- });
- }
- // Observe for dynamic content loading (e.g., infinite scrolling).
- const observer = new MutationObserver(() => {
- update();
- addRightClickListeners();
- });
- observer.observe(document.body, {childList: true, subtree: true});
- // Initial run.
- updateToggle();
- update();
- addRightClickListeners();
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement