Tired of manually copying and pasting multiple code snippets from Large Language Model (LLM) responses like ChatGPT, Claude, Gemini, etc.? This simple bookmarklet extracts all code blocks from the current page, attempts to detect their filenames, packages them into a structured .tar
archive, and downloads it – all with one click!
Say goodbye to tedious copy-pasting and lost file structure! 🚀
- 🖱️ One-Click Extraction: Grab all code blocks instantly.
- 📄 Filename Detection: Intelligently guesses filenames from text preceding the code blocks (e.g.,
path/to/your/file.py
). - 🏷️ Language-Based Fallback: Uses code block language (e.g.,
language-python
) to assign extensions (.py
) if no filename is found. - 📦 TAR Archive: Packages files into a
.tar
archive, preserving directory structures mentioned in filenames (e.g.,src/utils/helper.js
). - 🌐 Browser-Based: Runs entirely in your browser, no installation needed.
- ✨ Self-Contained: Includes a minimal TAR implementation – no external libraries required.
- 📝 UTF-8 Support: Handles UTF-8 characters within the code content.
There are two easy ways to install the bookmarklet:
Method 1: Drag and Drop (Recommended):
- Drag and Drop following link to your bookmark bar: Export LLM Code
Usage:
- Navigate to the page containing the LLM response with code blocks you want to save.
- Click the
Export LLM Code
bookmarklet you created. - A
.tar
file (e.g.,llm_response_export.tar
) containing the extracted code files will be downloaded automatically!
Method 2: Copy & Paste
- Bookmark Any Page: Create a new bookmark in your browser (Ctrl+D or Cmd+D). Name it something memorable like
Export LLM Code
. - Edit the Bookmark: Right-click the new bookmark and choose "Edit" or "Properties".
- Replace URL: Delete the current content in the "URL" or "Location" field.
- Paste the Code: Copy the link location from above and paste it into the "URL" / "Location" field.
- Save: Save the changes to the bookmark.
Method 3: Manual Execute
-
Paste the Code: Copy the minified code below and paste it into the bowsers console (F12 -> Console).:
!function(){if("/gloryknight/IA_file_extractor"===document.location.pathname)return;let e=/[`\*]?([\w\/.-]+\.\w+)[`\*]?$/i;console.log("Bookmarklet: Starting code extraction...");let t=document.querySelectorAll("pre > code"),l=[],n=1;if(0===t.length){console.log('Bookmarklet: No code blocks found using selector "pre > code".');return}if(t.forEach(t=>{let o=t.closest("pre");if(!o)return;let r=t.textContent;if(!r||""===r.trim()){console.log("Bookmarklet: Skipping empty code block.");return}let i="",$=o.previousElementSibling,s=0;for(;$&&s<3;){let a=$.textContent?.trim();if(a){let c=a.match(e);if(c&&c[1]&&c[1].length<150&&!c[1].includes(" ")&&c[1].includes(".")){i=c[1],console.log(`Bookmarklet: Found potential filename "${i}" in preceding element.`);break}}$=$.previousElementSibling,s++}if(!i){let p=".txt",f=Array.from(t.classList).find(e=>e.startsWith("language-"));if(f){let u=f.substring(9),g={python:".py",javascript:".js",html:".html",css:".css",bash:".sh",shell:".sh",java:".java",csharp:".cs",cpp:".cpp",c:".c",typescript:".ts",json:".json",yaml:".yaml",markdown:".md",sql:".sql",xml:".xml",dockerfile:".dockerfile",plaintext:".txt"};g[u]?p=g[u]:u&&(p="."+u)}i=`file_${n}${p}`,console.log(`Bookmarklet: Could not find filename, using default: "${i}"`)}i=i.replace(/^\/+/,"").replace(/\.\.\//g,""),l.push({name:i,content:r}),n++}),l.length>0)try{let o=function e(t){let l=[];function n(e,t){let l=[],n=0;for(let o=0;o<e.length&&n<t;o++){let r=e.charCodeAt(o);r<128?(l.push(r),n++):console.warn("Non-ASCII character skipped in TAR header string:",e[o])}for(;l.length<t;)l.push(0);return l}function o(e,t){let l=e.toString(8),o="0".repeat(t-1-l.length)+l+"\0";return n(o,t)}t.forEach(e=>{let t=function e(t){let l=[];for(let n=0;n<t.length;n++){let o=t.charCodeAt(n);o<128?l.push(o):o<2048?l.push(192|o>>6,128|63&o):o<65536?l.push(224|o>>12,128|o>>6&63,128|63&o):l.push(240|o>>18,128|o>>12&63,128|o>>6&63,128|63&o)}return l}(e.content),r=t.length,i=e.name,$="";if(i.length>100){let s=-1;for(let a=Math.min(i.length,155)-1;a>=0;a--)if("/"===i[a]){let c=i.substring(0,a),p=i.substring(a+1);if(c.length<=155&&p.length<=100){s=a;break}}-1!==s?($=i.substring(0,s),i=i.substring(s+1)):(console.warn(`Filename "${e.name}" too long and could not be split cleanly for TAR. Truncating.`),$=i.substring(0,155),i=i.substring(155,255))}let f=new Uint8Array(512),u=0,g=[i,100,420,8,0,8,0,8,r,12,Math.floor(Date.now()/1e3),12," ",8,"0",1,"",100,"ustar\0",6,"00",2,"user",32,"group",32,0,8,0,8,$,155];for(let h=0;h<g.length;h+=2){let _=g[h],m=g[h+1];"string"==typeof _?f.set(n(_,m),u):f.set(o(_,m),u),u+=m}let d=0;for(let k=0;k<512;k++)d+=f[k];f.set(o(d,8),148),l.push(...f),l.push(...t);let x=(512-r%512)%512;for(let b=0;b<x;b++)l.push(0)});let r=new Uint8Array(512);return l.push(...r,...r),new Uint8Array(l)}(l),r=new Blob([o],{type:"application/x-tar"}),i=(document.title||"llm_export").replace(/[^a-z0-9_-]/gi,"_").replace(/_+/g,"_");i.length>50&&(i=i.substring(0,50)),i=i||"llm_code_export",i+=".tar",function e(t,l){let n=URL.createObjectURL(t),o=document.createElement("a");o.href=n,o.download=l,o.style.display="none",document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(n)}(r,i),console.log(`Bookmarklet: Successfully packaged ${l.length} file(s) into "${i}".`)}catch($){console.error("Bookmarklet Error:",$)}else console.log("Bookmarklet: No non-empty code blocks were found to package.")}();
-
Execute the Code: Press enter after pasting.
The bookmarklet executes JavaScript in the context of the current page:
- It finds all
<pre><code>
elements. - For each code block, it searches the preceding sibling elements for text that looks like a filename (using regex).
- If no filename is found, it checks the code block's
class
for a language (e.g.,language-python
) and uses that to generate a default filename (file_1.py
). - It uses a built-in, minimal JavaScript function to construct a TAR archive (USTAR format) in memory.
- File content is encoded as UTF-8.
- The generated TAR archive is converted to a
Blob
. - A hidden link is created with the Blob URL and download attribute, then programmatically clicked to trigger the download.
- Filename Accuracy: Filename detection is heuristic and might fail if the LLM response structure is unusual or filenames aren't near the code block.
- HTML Structure: Relies on the common
<pre><code>...</code></pre>
structure. It won't work on pages using different elements for code display. - TAR Features: The TAR implementation is basic. It supports USTAR long filenames (up to ~255 characters split between prefix/name) but lacks features like complex permission handling or symbolic links.
- Browser Security: May be restricted by Content Security Policy (CSP) on some websites.
- Bookmarklet Length Limits: The code is minified, but extremely complex future versions might hit browser limits.
Found a bug or have an idea for improvement? Feel free to:
⭐️ If you find this useful, please consider starring the repository! ⭐️
This project is licensed under the MIT License - see the LICENSE file for details.