AutoGineer Workflow Scraper & Downloader

Automatically scrape and download all automation workflows from AutoGineer

Size

12.1 KB

Version

1.1.2

Created

Dec 9, 2025

Updated

4 days ago

1// ==UserScript==
2// @name		AutoGineer Workflow Scraper & Downloader
3// @description		Automatically scrape and download all automation workflows from AutoGineer
4// @version		1.1.2
5// @match		https://*.autogineer.com/*
6// @icon		https://www.autogineer.com/favicon.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('AutoGineer Workflow Scraper initialized');
12
13    // State management
14    let isScrapingActive = false;
15    let scrapedWorkflows = [];
16    let totalDownloaded = 0;
17    let statusElement = null;
18
19    // Utility function to wait
20    function wait(ms) {
21        return new Promise(resolve => setTimeout(resolve, ms));
22    }
23
24    // Utility function to download JSON
25    function downloadJSON(data, filename) {
26        const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
27        const url = URL.createObjectURL(blob);
28        const a = document.createElement('a');
29        a.href = url;
30        a.download = filename;
31        document.body.appendChild(a);
32        a.click();
33        document.body.removeChild(a);
34        URL.revokeObjectURL(url);
35        console.log(`Downloaded: ${filename}`);
36    }
37
38    // Update status display
39    function updateStatus(message, isError = false) {
40        console.log(message);
41        if (statusElement) {
42            statusElement.textContent = message;
43            statusElement.style.color = isError ? '#ef4444' : '#10b981';
44        }
45    }
46
47    // Check if we're on the main vault page
48    function isVaultPage() {
49        return window.location.pathname === '/' || window.location.pathname.includes('/vault');
50    }
51
52    // Check if we're on a template detail page
53    function isTemplatePage() {
54        return window.location.pathname.includes('/template/');
55    }
56
57    // Get all workflow cards on the current page
58    function getWorkflowCards() {
59        const cards = document.querySelectorAll('[role="button"][aria-label*="View details for"]');
60        console.log(`Found ${cards.length} workflow cards on page`);
61        return Array.from(cards);
62    }
63
64    // Click the "Load More" button if it exists
65    async function clickLoadMore() {
66        const loadMoreBtn = document.querySelector('button:not([disabled])');
67        const btnText = loadMoreBtn?.textContent || '';
68        
69        if (loadMoreBtn && btnText.includes('Load More')) {
70            console.log('Clicking Load More button...');
71            loadMoreBtn.click();
72            await wait(3000); // Wait for new workflows to load
73            return true;
74        }
75        return false;
76    }
77
78    // Download workflow from detail page
79    async function downloadWorkflowFromDetailPage() {
80        try {
81            updateStatus('Waiting for page to load...');
82            await wait(5000); // Increased wait time for data to load
83
84            // Find the download button by text content
85            const buttons = Array.from(document.querySelectorAll('button'));
86            const downloadBtn = buttons.find(btn => btn.textContent.includes('Download JSON'));
87            
88            if (!downloadBtn) {
89                throw new Error('Download button not found');
90            }
91
92            // Get workflow name from the page
93            const workflowTitle = document.querySelector('h1.text-3xl')?.textContent?.trim() || 'workflow';
94            
95            updateStatus(`Downloading: ${workflowTitle}`);
96            
97            // Click download button
98            downloadBtn.click();
99            await wait(2000); // Wait for download to initiate
100
101            totalDownloaded++;
102            updateStatus(`Downloaded ${totalDownloaded} workflows: ${workflowTitle}`);
103            
104            return { success: true, name: workflowTitle };
105        } catch (error) {
106            console.error('Error downloading workflow:', error);
107            updateStatus(`Error downloading workflow: ${error.message}`, true);
108            return { success: false, error: error.message };
109        }
110    }
111
112    // Navigate back to vault
113    async function navigateBackToVault() {
114        const backBtn = document.querySelector('button');
115        const btnText = backBtn?.textContent || '';
116        
117        if (backBtn && btnText.includes('Back to Vault')) {
118            console.log('Navigating back to vault...');
119            backBtn.click();
120            await wait(2000); // Wait for navigation
121            return true;
122        } else {
123            // Fallback: navigate directly
124            console.log('Using fallback navigation...');
125            window.history.back();
126            await wait(2000);
127            return true;
128        }
129    }
130
131    // Main scraping function
132    async function startScraping() {
133        if (isScrapingActive) {
134            updateStatus('Scraping already in progress!', true);
135            return;
136        }
137
138        isScrapingActive = true;
139        totalDownloaded = 0;
140        scrapedWorkflows = [];
141
142        try {
143            updateStatus('Starting workflow scraping...');
144
145            // Make sure we're on the vault page
146            if (!isVaultPage()) {
147                updateStatus('Please navigate to the main vault page first', true);
148                isScrapingActive = false;
149                return;
150            }
151
152            let hasMoreWorkflows = true;
153            let pageCount = 0;
154
155            while (hasMoreWorkflows && isScrapingActive) {
156                pageCount++;
157                updateStatus(`Processing page ${pageCount}...`);
158
159                // Get all workflow cards on current page
160                const workflowCards = getWorkflowCards();
161                
162                if (workflowCards.length === 0) {
163                    updateStatus('No more workflows found', false);
164                    break;
165                }
166
167                // Process each workflow card
168                for (let i = 0; i < workflowCards.length; i++) {
169                    if (!isScrapingActive) break;
170
171                    updateStatus(`Processing workflow ${i + 1}/${workflowCards.length} on page ${pageCount}...`);
172
173                    // Click the workflow card
174                    const cards = getWorkflowCards(); // Re-query to avoid stale references
175                    if (cards[i]) {
176                        cards[i].click();
177                        await wait(2000); // Wait for navigation
178
179                        // Download the workflow
180                        const result = await downloadWorkflowFromDetailPage();
181                        
182                        if (result.success) {
183                            scrapedWorkflows.push(result.name);
184                        }
185
186                        // Navigate back to vault
187                        await navigateBackToVault();
188                        await wait(1500); // Wait for page to stabilize
189                    }
190                }
191
192                // Try to load more workflows
193                updateStatus('Checking for more workflows...');
194                hasMoreWorkflows = await clickLoadMore();
195                
196                if (!hasMoreWorkflows) {
197                    updateStatus(`Scraping complete! Downloaded ${totalDownloaded} workflows`, false);
198                    break;
199                }
200            }
201
202            // Final summary
203            updateStatus(`✓ Scraping finished! Total downloaded: ${totalDownloaded} workflows`, false);
204            console.log('All scraped workflows:', scrapedWorkflows);
205
206        } catch (error) {
207            console.error('Scraping error:', error);
208            updateStatus(`Error during scraping: ${error.message}`, true);
209        } finally {
210            isScrapingActive = false;
211        }
212    }
213
214    // Stop scraping
215    function stopScraping() {
216        isScrapingActive = false;
217        updateStatus('Scraping stopped by user', false);
218    }
219
220    // Create control panel UI
221    function createControlPanel() {
222        // Check if panel already exists
223        if (document.getElementById('workflow-scraper-panel')) {
224            return;
225        }
226
227        const panel = document.createElement('div');
228        panel.id = 'workflow-scraper-panel';
229        panel.style.cssText = `
230            position: fixed;
231            top: 20px;
232            right: 20px;
233            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
234            border: 2px solid rgba(255, 255, 255, 0.2);
235            border-radius: 16px;
236            padding: 20px;
237            z-index: 999999;
238            box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
239            min-width: 320px;
240            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
241        `;
242
243        const title = document.createElement('div');
244        title.textContent = '🤖 Workflow Scraper';
245        title.style.cssText = `
246            font-size: 18px;
247            font-weight: bold;
248            color: white;
249            margin-bottom: 15px;
250            text-align: center;
251        `;
252
253        const status = document.createElement('div');
254        status.id = 'scraper-status';
255        status.textContent = 'Ready to scrape workflows';
256        status.style.cssText = `
257            background: rgba(255, 255, 255, 0.15);
258            color: white;
259            padding: 12px;
260            border-radius: 8px;
261            margin-bottom: 15px;
262            font-size: 13px;
263            min-height: 40px;
264            word-wrap: break-word;
265        `;
266        statusElement = status;
267
268        const buttonContainer = document.createElement('div');
269        buttonContainer.style.cssText = `
270            display: flex;
271            gap: 10px;
272        `;
273
274        const startBtn = document.createElement('button');
275        startBtn.textContent = 'Start Scraping';
276        startBtn.style.cssText = `
277            flex: 1;
278            background: white;
279            color: #667eea;
280            border: none;
281            padding: 12px 20px;
282            border-radius: 8px;
283            font-weight: bold;
284            cursor: pointer;
285            font-size: 14px;
286            transition: all 0.3s;
287        `;
288        startBtn.onmouseover = () => startBtn.style.transform = 'scale(1.05)';
289        startBtn.onmouseout = () => startBtn.style.transform = 'scale(1)';
290        startBtn.onclick = startScraping;
291
292        const stopBtn = document.createElement('button');
293        stopBtn.textContent = 'Stop';
294        stopBtn.style.cssText = `
295            background: rgba(239, 68, 68, 0.9);
296            color: white;
297            border: none;
298            padding: 12px 20px;
299            border-radius: 8px;
300            font-weight: bold;
301            cursor: pointer;
302            font-size: 14px;
303            transition: all 0.3s;
304        `;
305        stopBtn.onmouseover = () => stopBtn.style.transform = 'scale(1.05)';
306        stopBtn.onmouseout = () => stopBtn.style.transform = 'scale(1)';
307        stopBtn.onclick = stopScraping;
308
309        const closeBtn = document.createElement('button');
310        closeBtn.textContent = '×';
311        closeBtn.style.cssText = `
312            position: absolute;
313            top: 10px;
314            right: 10px;
315            background: rgba(255, 255, 255, 0.2);
316            color: white;
317            border: none;
318            width: 28px;
319            height: 28px;
320            border-radius: 50%;
321            cursor: pointer;
322            font-size: 20px;
323            line-height: 1;
324            transition: all 0.3s;
325        `;
326        closeBtn.onmouseover = () => closeBtn.style.background = 'rgba(255, 255, 255, 0.3)';
327        closeBtn.onmouseout = () => closeBtn.style.background = 'rgba(255, 255, 255, 0.2)';
328        closeBtn.onclick = () => panel.remove();
329
330        buttonContainer.appendChild(startBtn);
331        buttonContainer.appendChild(stopBtn);
332
333        panel.appendChild(closeBtn);
334        panel.appendChild(title);
335        panel.appendChild(status);
336        panel.appendChild(buttonContainer);
337
338        document.body.appendChild(panel);
339        console.log('Control panel created');
340    }
341
342    // Initialize the extension
343    function init() {
344        console.log('Initializing AutoGineer Workflow Scraper...');
345        
346        // Wait for page to be ready
347        if (document.readyState === 'loading') {
348            document.addEventListener('DOMContentLoaded', () => {
349                setTimeout(createControlPanel, 1000);
350            });
351        } else {
352            setTimeout(createControlPanel, 1000);
353        }
354    }
355
356    // Start the extension
357    init();
358})();
AutoGineer Workflow Scraper & Downloader | Robomonkey