Google Images Bikini Filter

A new extension

Size

5.7 KB

Version

1.0.1

Created

Feb 15, 2026

Updated

22 days ago

1// ==UserScript==
2// @name		Google Images Bikini Filter
3// @description		A new extension
4// @version		1.0.1
5// @match		https://*.google.com/*
6// ==/UserScript==
7(function() {
8    'use strict';
9
10    console.log('Google Images Bikini Filter extension loaded');
11
12    // Debounce function to avoid excessive calls
13    function debounce(func, wait) {
14        let timeout;
15        return function executedFunction(...args) {
16            const later = () => {
17                clearTimeout(timeout);
18                func(...args);
19            };
20            clearTimeout(timeout);
21            timeout = setTimeout(later, wait);
22        };
23    }
24
25    // Check if we're on Google Images search
26    function isGoogleImagesPage() {
27        return window.location.href.includes('google.com') && 
28               (window.location.href.includes('udm=2') || 
29                window.location.href.includes('tbm=isch') ||
30                document.querySelector('div[data-ved]') !== null);
31    }
32
33    // Process images and filter for bikini content
34    async function filterImages() {
35        if (!isGoogleImagesPage()) {
36            console.log('Not on Google Images page, skipping filter');
37            return;
38        }
39
40        console.log('Starting bikini filter process...');
41
42        // Find all image containers
43        const imageContainers = document.querySelectorAll('div[data-ved][jsname]');
44        console.log(`Found ${imageContainers.length} image containers`);
45
46        if (imageContainers.length === 0) {
47            console.log('No image containers found, will retry...');
48            return;
49        }
50
51        for (const container of imageContainers) {
52            // Skip if already processed
53            if (container.dataset.bikiniProcessed === 'true') {
54                continue;
55            }
56
57            // Mark as processed
58            container.dataset.bikiniProcessed = 'true';
59
60            // Get the image element
61            const img = container.querySelector('img');
62            if (!img || !img.src || img.src.startsWith('data:')) {
63                continue;
64            }
65
66            // Get alt text and surrounding text for context
67            const altText = img.alt || '';
68            const containerText = container.textContent || '';
69            const context = `Image alt text: "${altText}". Container text: "${containerText.substring(0, 200)}"`;
70
71            try {
72                console.log('Analyzing image:', img.src.substring(0, 100));
73
74                // Use AI to determine if this is a bikini picture
75                const analysis = await RM.aiCall(
76                    `Analyze if this image is related to bikinis, swimwear, or beach attire based on the context: ${context}. Consider the image description and surrounding text.`,
77                    {
78                        type: "json_schema",
79                        json_schema: {
80                            name: "bikini_detection",
81                            schema: {
82                                type: "object",
83                                properties: {
84                                    isBikini: { 
85                                        type: "boolean",
86                                        description: "True if the image is related to bikinis, swimwear, or beach attire"
87                                    },
88                                    confidence: { 
89                                        type: "number",
90                                        minimum: 0,
91                                        maximum: 1,
92                                        description: "Confidence level of the detection"
93                                    },
94                                    reason: {
95                                        type: "string",
96                                        description: "Brief explanation of the decision"
97                                    }
98                                },
99                                required: ["isBikini", "confidence", "reason"]
100                            }
101                        }
102                    }
103                );
104
105                console.log('Analysis result:', analysis);
106
107                // Hide images that are NOT bikini-related
108                if (!analysis.isBikini || analysis.confidence < 0.5) {
109                    container.style.display = 'none';
110                    console.log('Hiding non-bikini image:', analysis.reason);
111                } else {
112                    container.style.display = '';
113                    console.log('Keeping bikini image:', analysis.reason);
114                }
115
116            } catch (error) {
117                console.error('Error analyzing image:', error);
118                // On error, keep the image visible to avoid hiding everything
119            }
120        }
121
122        console.log('Bikini filter process completed');
123    }
124
125    // Initialize the extension
126    async function init() {
127        console.log('Initializing Google Images Bikini Filter...');
128
129        if (!isGoogleImagesPage()) {
130            console.log('Not on Google Images page');
131            return;
132        }
133
134        // Wait for images to load
135        setTimeout(() => {
136            filterImages();
137        }, 2000);
138
139        // Watch for new images being loaded (infinite scroll)
140        const debouncedFilter = debounce(filterImages, 1000);
141        
142        const observer = new MutationObserver(debouncedFilter);
143        
144        observer.observe(document.body, {
145            childList: true,
146            subtree: true
147        });
148
149        console.log('Bikini filter initialized and watching for new images');
150    }
151
152    // Start when page is ready
153    if (document.readyState === 'loading') {
154        document.addEventListener('DOMContentLoaded', init);
155    } else {
156        init();
157    }
158
159})();