B
Blink.new Files Downloader
Copyโpaste script to export your Blink.new project files as a ZIP
-
Open your Blink.new project
Make sure the project is loaded in your browser.
-
Expand the file tree (open files/folders)
Click through files so the editor loads them (the script can capture opened Monaco models).
-
Open DevTools Console
Press F12 (or Ctrl+Shift+I on Windows, Cmd+Option+I on macOS) and switch to the Console tab.
-
Paste the script below and press Enter
The script loads JSZip, captures files from Monaco, then downloads a ZIP.
/**
* BLINK.NEW FIXED SCRAPER v3.0
*
* This version is specifically designed for Blink.new's actual structure
* Works with the file tree visible in your screenshot!
*
* HOW TO USE:
* 1. Keep Blink.new project open
* 2. Press F12 (Console)
* 3. Paste THIS script
* 4. Press Enter
* 5. Wait for download!
*/
(async function() {
console.log('๐ฅ Blink.new FIXED Scraper v3.0 Starting...');
console.log('โณ Please wait...');
// Load JSZip
if (typeof JSZip === 'undefined') {
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js';
document.head.appendChild(script);
await new Promise(resolve => {
script.onload = resolve;
setTimeout(resolve, 3000);
});
}
if (typeof JSZip === 'undefined') {
alert('โ Failed to load JSZip. Check internet and try again.');
return;
}
console.log('โ
JSZip loaded');
const fileContents = new Map();
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// ============================================
// STEP 1: Get Monaco Content (Primary Method)
// ============================================
console.log('๐ Step 1: Checking Monaco Editor...');
function getMonacoFiles() {
const files = [];
if (window.monaco && window.monaco.editor) {
const models = window.monaco.editor.getModels();
console.log(`โ
Found ${models.length} Monaco models`);
for (const model of models) {
try {
const uri = model.uri.toString();
const content = model.getValue();
// Extract path from URI
// URIs look like: file:///src/App.tsx or inmemory://model/1
let path = uri;
// Clean up the path
if (path.startsWith('file://')) {
path = path.replace(/^file:\/\/+/, '');
} else if (path.startsWith('inmemory://')) {
path = path.replace(/^inmemory:\/\/[^/]+\//, '');
}
// Remove leading slashes
path = path.replace(/^\/+/, '');
// If path is just a number or looks weird, use the content to guess
if (!path.includes('.') || path.match(/^[0-9]+$/)) {
// Try to detect file type from content
if (content.includes('import React') || content.includes('export default')) {
path = `file-${files.length + 1}.tsx`;
} else if (content.trim().startsWith('{')) {
path = `file-${files.length + 1}.json`;
} else if (content.includes('@apply') || content.includes('background:')) {
path = `file-${files.length + 1}.css`;
} else {
path = `file-${files.length + 1}.txt`;
}
}
if (content && content.trim().length > 0) {
files.push({ path, content });
fileContents.set(path, content);
}
} catch (e) {
console.warn('Failed to process model:', e);
}
}
}
return files;
}
const initialFiles = getMonacoFiles();
console.log(`๐ Initial extraction: ${initialFiles.length} files`);
for (const file of initialFiles) {
console.log(` โ
${file.path} (${file.content.length} chars)`);
}
// ============================================
// STEP 2: Find and Click Files
// ============================================
console.log('๐ฑ๏ธ Step 2: Looking for clickable files...');
// Find all elements that might be file entries
// Look for elements with file extensions in their text
const allElements = document.querySelectorAll('*');
const fileElements = [];
for (const el of allElements) {
const text = el.textContent;
// Must be short enough to be a filename
if (text && text.length < 100 && text.length > 3) {
// Check if it matches a filename pattern
const fileMatch = text.match(/^[\w-]+\.(tsx?|jsx?|css|s?css|html?|json|md|xml|ya?ml|ts|js)$/i);
if (fileMatch) {
const fileName = text.trim();
// Check if element or parent is clickable
const isClickable =
el.onclick ||
el.tagName === 'BUTTON' ||
el.role === 'button' ||
el.parentElement?.onclick ||
window.getComputedStyle(el).cursor === 'pointer';
if (isClickable) {
fileElements.push({ el, fileName });
}
}
}
}
console.log(`โ
Found ${fileElements.length} clickable files`);
// Click through files
for (let i = 0; i < fileElements.length; i++) {
const { el, fileName } = fileElements[i];
console.log(` [${i + 1}/${fileElements.length}] Clicking: ${fileName}`);
try {
el.click();
await sleep(600);
// Get new Monaco content
const newFiles = getMonacoFiles();
const newCount = newFiles.length - initialFiles.length;
if (newCount > 0) {
console.log(` โ
+${newCount} new file(s) loaded`);
}
} catch (e) {
console.warn(` โ ๏ธ Click failed:`, e.message);
}
}
// ============================================
// STEP 3: Final Monaco Extraction
// ============================================
console.log('๐ Step 3: Final extraction...');
const finalFiles = getMonacoFiles();
console.log(`โ
Total unique files: ${fileContents.size}`);
// ============================================
// STEP 4: Create ZIP
// ============================================
console.log('๐ฆ Step 4: Creating ZIP...');
if (fileContents.size === 0) {
console.error('โ No files were captured!');
alert('โ No files captured!\n\nTry this:\n1. Click a few files manually in Blink\n2. Run this script again\n3. It will capture what you clicked');
return;
}
const zip = new JSZip();
// Add all files
for (const [path, content] of fileContents.entries()) {
zip.file(path, content);
}
// Add README
const readme = `# Blink.new Project Export
Exported on: ${new Date().toLocaleString()}
Total files: ${fileContents.size}
## Files Included
${Array.from(fileContents.keys()).map(f => `- ${f}`).join('\n')}
## Notes
This export was created using the Fixed Scraper v3.0.
Files were extracted from Monaco Editor memory.
---
Created by Shihab Soft
`;
zip.file('README-EXPORT.md', readme);
// Generate ZIP
console.log('โณ Generating ZIP...');
const blob = await zip.generateAsync({
type: 'blob',
compression: 'DEFLATE',
compressionOptions: { level: 9 }
});
// Download
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `blink-project-${Date.now()}.zip`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
// ============================================
// SUCCESS!
// ============================================
console.log('');
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
console.log('๐ SUCCESS!');
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ');
console.log(`โ
Files: ${fileContents.size}`);
console.log(`โ
Size: ${(blob.size / 1024).toFixed(2)} KB`);
console.log('');
console.log('๐ Downloaded files:');
for (const [path, content] of fileContents.entries()) {
console.log(` โ
${path} (${(content.length / 1024).toFixed(2)} KB)`);
}
console.log('');
console.log('๐พ Check your Downloads folder!');
alert(`โ
Success!\n\n${fileContents.size} files downloaded\n${(blob.size / 1024).toFixed(2)} KB\n\nCheck Downloads folder!`);
// If only got a few files, suggest manual clicking
if (fileContents.size < 5) {
console.warn('');
console.warn('๐ก TIP: Only got a few files?');
console.warn(' 1. Manually click files in Blink file tree');
console.warn(' 2. Run this script again');
console.warn(' 3. Each clicked file will be captured!');
}
})();
Notes
- If you only get a few files, manually click more files in the tree, then rerun the script.
- Make sure you have a stable internet connection so JSZip can load from CDN.
- This captures files present in Monaco editor memory (opened/loaded files).