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})();