* Download a StackBlitz project using browser automation * @param {URL} url * @param {string} target_dir
(url, target_dir)
| 136 | * @param {string} target_dir |
| 137 | */ |
| 138 | async function download_stackblitz_project(url, target_dir) { |
| 139 | console.log(`Downloading StackBlitz project via browser automation...`); |
| 140 | console.log(`URL: ${url.href}`); |
| 141 | |
| 142 | const browser = await chromium.launch({ headless: true }); |
| 143 | const context = await browser.newContext({ acceptDownloads: true }); |
| 144 | const page = await context.newPage(); |
| 145 | |
| 146 | try { |
| 147 | // Navigate to the StackBlitz project |
| 148 | console.log('Loading StackBlitz project (this may take a moment)...'); |
| 149 | await page.goto(url.href, { waitUntil: 'domcontentloaded', timeout: 20000 }); |
| 150 | |
| 151 | // Set up download handler |
| 152 | const downloadPromise = page.waitForEvent('download', { timeout: 30000 }); |
| 153 | await page.locator('button[aria-label*="Download Project" i]', { timeout: 30000 }).click(); |
| 154 | console.log('Triggering download...'); |
| 155 | |
| 156 | // Wait for the download to start |
| 157 | const download = await downloadPromise; |
| 158 | |
| 159 | // Save the downloaded file |
| 160 | const zip_path = path.join(target_dir, 'project.zip'); |
| 161 | await download.saveAs(zip_path); |
| 162 | |
| 163 | console.log('Download complete, extracting...'); |
| 164 | |
| 165 | // Extract the zip file |
| 166 | if (process.platform === 'win32') { |
| 167 | execSync( |
| 168 | `powershell -Command "Expand-Archive -Path '${zip_path}' -DestinationPath '${target_dir}' -Force"`, |
| 169 | { stdio: 'inherit' } |
| 170 | ); |
| 171 | } else { |
| 172 | execSync(`unzip -o "${zip_path}" -d "${target_dir}"`, { stdio: 'inherit' }); |
| 173 | } |
| 174 | |
| 175 | // Remove the zip file |
| 176 | fs.unlinkSync(zip_path); |
| 177 | |
| 178 | // Check if files were extracted into a subdirectory |
| 179 | const entries = fs.readdirSync(target_dir); |
| 180 | if (entries.length === 1) { |
| 181 | const subdir = path.join(target_dir, entries[0]); |
| 182 | if (fs.statSync(subdir).isDirectory()) { |
| 183 | // Move files from subdirectory to target_dir |
| 184 | const subentries = fs.readdirSync(subdir); |
| 185 | for (const entry of subentries) { |
| 186 | fs.renameSync(path.join(subdir, entry), path.join(target_dir, entry)); |
| 187 | } |
| 188 | fs.rmdirSync(subdir); |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | console.log('StackBlitz project downloaded successfully'); |
| 193 | } finally { |
| 194 | await browser.close(); |
| 195 | } |