Freepik Bulk Image Downloader

Scarica tutte le immagini gratuite dalla pagina, organizzate per tag in un file ZIP

Size

11.2 KB

Version

1.0.1

Created

Nov 25, 2025

Updated

18 days ago

1// ==UserScript==
2// @name		Freepik Bulk Image Downloader
3// @description		Scarica tutte le immagini gratuite dalla pagina, organizzate per tag in un file ZIP
4// @version		1.0.1
5// @match		https://*.freepik.com/*
6// @icon		https://cdn-front.freepik.com/favicons/favicon.ico?v=2
7// @require		https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
8// @grant		GM.xmlhttpRequest
9// ==/UserScript==
10(function() {
11    'use strict';
12
13    console.log('Freepik Bulk Image Downloader inizializzato');
14
15    // Stili per il pulsante di download
16    const styles = `
17        #freepik-bulk-download-btn {
18            position: fixed;
19            bottom: 30px;
20            right: 30px;
21            z-index: 10000;
22            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
23            color: white;
24            border: none;
25            padding: 16px 24px;
26            border-radius: 50px;
27            font-size: 16px;
28            font-weight: bold;
29            cursor: pointer;
30            box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
31            transition: all 0.3s ease;
32            display: flex;
33            align-items: center;
34            gap: 10px;
35        }
36        
37        #freepik-bulk-download-btn:hover {
38            transform: translateY(-2px);
39            box-shadow: 0 12px 28px rgba(102, 126, 234, 0.6);
40        }
41        
42        #freepik-bulk-download-btn:disabled {
43            background: #ccc;
44            cursor: not-allowed;
45            transform: none;
46        }
47        
48        #freepik-download-progress {
49            position: fixed;
50            bottom: 100px;
51            right: 30px;
52            z-index: 10000;
53            background: white;
54            padding: 20px;
55            border-radius: 12px;
56            box-shadow: 0 4px 20px rgba(0,0,0,0.15);
57            min-width: 300px;
58            display: none;
59        }
60        
61        #freepik-download-progress.active {
62            display: block;
63        }
64        
65        .progress-bar {
66            width: 100%;
67            height: 8px;
68            background: #e0e0e0;
69            border-radius: 4px;
70            overflow: hidden;
71            margin-top: 10px;
72        }
73        
74        .progress-bar-fill {
75            height: 100%;
76            background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
77            transition: width 0.3s ease;
78            width: 0%;
79        }
80        
81        .progress-text {
82            font-size: 14px;
83            color: #333;
84            margin-bottom: 5px;
85        }
86        
87        .progress-detail {
88            font-size: 12px;
89            color: #666;
90            margin-top: 8px;
91        }
92    `;
93
94    // Aggiungi gli stili
95    const styleSheet = document.createElement('style');
96    styleSheet.textContent = styles;
97    document.head.appendChild(styleSheet);
98
99    // Funzione per estrarre i tag dall'URL o dal titolo
100    function extractTags(url, title) {
101        const tags = [];
102        
103        // Estrai dalla query string
104        const urlObj = new URL(url);
105        const query = urlObj.searchParams.get('query');
106        if (query) {
107            tags.push(query.replace(/\+/g, '_'));
108        }
109        
110        // Estrai dal titolo (es: "Free Vector gradient product card template")
111        if (title) {
112            const match = title.match(/Free\s+(Vector|PSD|Photo|AI)\s+(.+)/i);
113            if (match) {
114                const type = match[1].toLowerCase();
115                tags.push(type);
116                
117                // Prendi le prime 2-3 parole del titolo come tag
118                const words = match[2].split(' ').slice(0, 3).join('_').toLowerCase();
119                tags.push(words);
120            }
121        }
122        
123        return tags.length > 0 ? tags : ['uncategorized'];
124    }
125
126    // Funzione per scaricare un'immagine
127    async function downloadImage(url) {
128        return new Promise((resolve, reject) => {
129            GM.xmlhttpRequest({
130                method: 'GET',
131                url: url,
132                responseType: 'blob',
133                onload: function(response) {
134                    if (response.status === 200) {
135                        resolve(response.response);
136                    } else {
137                        reject(new Error(`Failed to download: ${response.status}`));
138                    }
139                },
140                onerror: function(error) {
141                    reject(error);
142                },
143                ontimeout: function() {
144                    reject(new Error('Timeout'));
145                }
146            });
147        });
148    }
149
150    // Funzione per aggiornare la barra di progresso
151    function updateProgress(current, total, message) {
152        const progressDiv = document.getElementById('freepik-download-progress');
153        const progressText = progressDiv.querySelector('.progress-text');
154        const progressDetail = progressDiv.querySelector('.progress-detail');
155        const progressFill = progressDiv.querySelector('.progress-bar-fill');
156        
157        const percentage = Math.round((current / total) * 100);
158        progressText.textContent = `Download in corso: ${percentage}%`;
159        progressDetail.textContent = message || `${current} di ${total} immagini`;
160        progressFill.style.width = `${percentage}%`;
161    }
162
163    // Funzione principale per scaricare tutte le immagini
164    async function downloadAllFreeImages() {
165        const button = document.getElementById('freepik-bulk-download-btn');
166        const progressDiv = document.getElementById('freepik-download-progress');
167        
168        button.disabled = true;
169        button.textContent = '⏳ Raccolta immagini...';
170        progressDiv.classList.add('active');
171        
172        try {
173            // Trova tutte le figure con immagini
174            const figures = document.querySelectorAll('figure[data-cy="resource-thumbnail"]');
175            console.log(`Trovate ${figures.length} immagini totali`);
176            
177            const freeImages = [];
178            
179            // Filtra solo le immagini gratuite
180            figures.forEach(fig => {
181                const premiumBadge = fig.querySelector('[class*="Premium"]');
182                if (!premiumBadge) {
183                    const link = fig.querySelector('a');
184                    const img = fig.querySelector('img');
185                    const title = img?.alt || '';
186                    
187                    if (img && img.src && link) {
188                        freeImages.push({
189                            url: img.src,
190                            title: title,
191                            pageUrl: link.href,
192                            tags: extractTags(link.href, title)
193                        });
194                    }
195                }
196            });
197            
198            console.log(`Trovate ${freeImages.length} immagini gratuite`);
199            
200            if (freeImages.length === 0) {
201                alert('Nessuna immagine gratuita trovata su questa pagina!');
202                return;
203            }
204            
205            // Crea il file ZIP
206            const zip = new JSZip();
207            
208            // Scarica tutte le immagini
209            for (let i = 0; i < freeImages.length; i++) {
210                const imageData = freeImages[i];
211                updateProgress(i + 1, freeImages.length, `Scaricamento: ${imageData.title.substring(0, 40)}...`);
212                
213                try {
214                    console.log(`Scaricamento immagine ${i + 1}/${freeImages.length}: ${imageData.url}`);
215                    const blob = await downloadImage(imageData.url);
216                    
217                    // Estrai l'estensione del file
218                    const extension = imageData.url.split('.').pop().split('?')[0] || 'jpg';
219                    
220                    // Crea il nome del file
221                    const fileName = `image_${i + 1}.${extension}`;
222                    
223                    // Organizza per tag (usa il primo tag come cartella principale)
224                    const folderName = imageData.tags[0].replace(/[^a-z0-9_-]/gi, '_');
225                    
226                    // Aggiungi al ZIP nella cartella appropriata
227                    zip.folder(folderName).file(fileName, blob);
228                    
229                    console.log(`Aggiunta immagine a cartella: ${folderName}/${fileName}`);
230                } catch (error) {
231                    console.error(`Errore nel download dell'immagine ${i + 1}:`, error);
232                }
233            }
234            
235            // Genera il file ZIP
236            updateProgress(freeImages.length, freeImages.length, 'Creazione file ZIP...');
237            console.log('Generazione file ZIP...');
238            
239            const zipBlob = await zip.generateAsync({
240                type: 'blob',
241                compression: 'DEFLATE',
242                compressionOptions: { level: 6 }
243            });
244            
245            // Scarica il file ZIP
246            const downloadLink = document.createElement('a');
247            downloadLink.href = URL.createObjectURL(zipBlob);
248            downloadLink.download = `freepik_images_${Date.now()}.zip`;
249            document.body.appendChild(downloadLink);
250            downloadLink.click();
251            document.body.removeChild(downloadLink);
252            
253            console.log('Download completato!');
254            updateProgress(freeImages.length, freeImages.length, `✅ Completato! ${freeImages.length} immagini scaricate`);
255            
256            setTimeout(() => {
257                progressDiv.classList.remove('active');
258                button.disabled = false;
259                button.innerHTML = '📥 Scarica Immagini Free';
260            }, 3000);
261            
262        } catch (error) {
263            console.error('Errore durante il download:', error);
264            alert('Errore durante il download delle immagini. Controlla la console per i dettagli.');
265            progressDiv.classList.remove('active');
266            button.disabled = false;
267            button.innerHTML = '📥 Scarica Immagini Free';
268        }
269    }
270
271    // Crea il pulsante di download
272    function createDownloadButton() {
273        // Verifica se siamo su una pagina di ricerca
274        if (!window.location.pathname.includes('/search') && !window.location.pathname.includes('/free-')) {
275            console.log('Non siamo su una pagina di ricerca, pulsante non aggiunto');
276            return;
277        }
278        
279        const button = document.createElement('button');
280        button.id = 'freepik-bulk-download-btn';
281        button.innerHTML = '📥 Scarica Immagini Free';
282        button.addEventListener('click', downloadAllFreeImages);
283        
284        const progressDiv = document.createElement('div');
285        progressDiv.id = 'freepik-download-progress';
286        progressDiv.innerHTML = `
287            <div class="progress-text">Preparazione...</div>
288            <div class="progress-bar">
289                <div class="progress-bar-fill"></div>
290            </div>
291            <div class="progress-detail">Inizializzazione...</div>
292        `;
293        
294        document.body.appendChild(button);
295        document.body.appendChild(progressDiv);
296        
297        console.log('Pulsante di download aggiunto alla pagina');
298    }
299
300    // Inizializza quando il DOM è pronto
301    function init() {
302        if (document.readyState === 'loading') {
303            document.addEventListener('DOMContentLoaded', createDownloadButton);
304        } else {
305            createDownloadButton();
306        }
307    }
308
309    init();
310})();
Freepik Bulk Image Downloader | Robomonkey