תיקנתי את הסקריפט שוב עם קלוד והתברר שהבעיה הייתה כי Base44 עברו למבנה role="treeitem" עם ARIA מלא, במקום button + SVG עם קלאס lucide. זה ההסבר לכל התקלה (לא באמת הבנתי... קלוד ניתח את זה עם בדיקות בקונסול וזה התוצאה)
מדביק את הסקריפט המעודכן, בהצלחה.
javascript:(async()=>{
if(document.querySelector("html").className.includes("translated"))return alert("⚠ בטל תרגום דפדפן.");
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
const waitFor=async(checkFn,{maxWait=2000,interval=30,stableChecks=2}={})=>{
const start=Date.now();let last=undefined,stable=0;
while(Date.now()-start<maxWait){
let val;try{val=await checkFn();}catch(e){val=undefined;}
if(val!==undefined&&val===last){stable++;if(stable>=stableChecks)return val;}else{stable=0;}
last=val;await sleep(interval);
}
return last;
};
const nav=document.querySelector('[data-testid="ds-file-tree"]')||document.querySelector('nav.flex-1.overflow-y-auto');
if(!nav)return alert("❌ לא נמצא עץ קבצים. ודא שאתה בלשונית 'Code'.");
let root;try{root=await window.showDirectoryPicker({mode:"readwrite"})}catch{return}
const panel=document.createElement("div");
panel.style="position:fixed;top:12px;left:50%;transform:translateX(-50%);width:450px;background:#111;color:#fff;font:13px system-ui;padding:16px;border-radius:14px;z-index:999999;direction:rtl;box-shadow:0 10px 30px rgba(0,0,0,0.8);border:1px solid #333";
panel.innerHTML=`<div style="display:flex;gap:10px;align-items:center;margin-bottom:12px"><div style="width:16px;height:16px;border:3px solid #444;border-top-color:#4caf50;border-radius:50%;animation:spin 1s linear infinite"></div><b style="font-size:15px">Base44 Extractor V16 (Fast)</b></div><div id="stg" style="color:#aaa;margin-bottom:8px">מאתחל...</div><div style="background:#222;height:12px;border-radius:6px;overflow:hidden"><div id="bar" style="height:100%;width:0%;background:#4caf50;transition:width 0.3s"></div></div><div id="pct" style="margin-top:6px;color:#888;font-size:12px">0%</div><div id="logArea" style="margin-top:10px;height:150px;background:#000;border:1px solid #444;border-radius:6px;overflow-y:auto;font-family:monospace;font-size:11px;padding:6px;text-align:left;direction:ltr;white-space:nowrap;color:#0f0;"></div><style>@keyframes spin{to{transform:rotate(360deg)}}</style>`;
document.body.appendChild(panel);
const stage=t=>{panel.querySelector("#stg").textContent=t;};
let fullLog="";
const logFn=m=>{console.log(m);fullLog+=m+"\r\n";const l=panel.querySelector("#logArea");if(l){l.innerHTML+='<div>> '+m+'</div>';l.scrollTop=l.scrollHeight;}};
const progress=(d,t)=>{const p=Math.floor((d/t)*100);panel.querySelector("#bar").style.width=p+"%";panel.querySelector("#pct").textContent=`${p}% (${d} מתוך ${t} קבצים)`;};
logFn("System Initialized V16 - Fast Mode.");
const getNodes=()=>Array.from(nav.querySelectorAll('[role="treeitem"]')).map(el=>{
const isFolder=el.hasAttribute('data-group-id');
const isFile=el.hasAttribute('data-file-id');
const fullPath=isFolder?el.getAttribute('data-group-id'):el.getAttribute('data-file-id');
if(!fullPath)return null;
const nameSpan=el.querySelector('span[data-testid="ds-text"]')||el.querySelector('span[data-ds-tooltip-anchor]');
const text=nameSpan?nameSpan.innerText.trim():fullPath.split('/').pop();
const isClosed=isFolder&&el.getAttribute('aria-expanded')==='false';
const clickTarget=el.querySelector('div.cursor-pointer')||el;
return{el,clickTarget,text,fullPath,isFolder,isFile,isClosed};
}).filter(Boolean);
const scrollTop=async()=>{nav.scrollTop=0;await waitFor(()=>nav.scrollTop,{maxWait:400,interval:30,stableChecks:2});};
const scrollStep=async(px=700)=>{const oldScroll=nav.scrollTop;nav.scrollTop+=px;await waitFor(()=>nav.scrollTop,{maxWait:250,interval:25,stableChecks:2});return nav.scrollTop!==oldScroll;};
stage("פותח תיקיות...");
await scrollTop();
let expStable=0,attempts=new Map();
while(expStable<5){
const nodes=getNodes();
let expanded=false;
for(const n of nodes){
if(n.isClosed){
const tries=attempts.get(n.fullPath)||0;
if(tries<3){
attempts.set(n.fullPath,tries+1);
logFn(`Expanding folder: ${n.fullPath}`);
n.el.scrollIntoView({block:"center"});
n.clickTarget.click();
await waitFor(()=>{const fresh=getNodes().find(x=>x.fullPath===n.fullPath);return fresh?(fresh.isClosed===false?true:undefined):undefined;},{maxWait:600,interval:25,stableChecks:1});
expanded=true;expStable=0;break;
}
}
}
if(!expanded){const moved=await scrollStep(700);if(!moved)expStable++;else expStable=0;}
}
stage("ממפה פרויקט...");
await scrollTop();
let mappedFiles=new Map(),mapStable=0;
while(mapStable<5){
const nodes=getNodes();
for(const n of nodes){
if(n.isFile&&!mappedFiles.has(n.fullPath)){
const saveName=n.text.includes(".")?n.text:n.text+".js";
const parts=n.fullPath.split('/');
mappedFiles.set(n.fullPath,{name:saveName,path:n.fullPath,dir:parts.slice(0,-1)});
logFn(`Mapped: ${n.fullPath}`);
}
}
const moved=await scrollStep(700);
if(!moved)mapStable++;else mapStable=0;
}
const fList=Array.from(mappedFiles.values());
logFn(`Mapping complete. Found ${fList.length} files.`);
if(!fList.length){panel.remove();return alert("לא נמצאו קבצים. נסה לרענן את העמוד.");}
const sanitize=s=>s.replace(/[<>:"\/\\|?*]/g,"_");
const readMonacoContent=async(fileName)=>{
return await waitFor(()=>{
if(window.monaco?.editor){
const m=window.monaco.editor.getModels();
if(m.length){
const md=m.find(x=>x.uri.path.toLowerCase().endsWith(fileName.toLowerCase()))||m[0];
const val=md.getValue();
if(val)return val;
}
}
return undefined;
},{maxWait:2500,interval:30,stableChecks:2});
};
let saved=0,failed=[];
for(let i=0;i<fList.length;i++){
const file=fList[i];
stage(`מוריד: ${file.name}`);
progress(i,fList.length);
logFn(`--- Target: ${file.path} ---`);
await scrollTop();
let tgt=null,tgtEl=null,sStable=0;
while(sStable<5&&!tgt){
const nodes=getNodes();
const found=nodes.find(n=>n.fullPath===file.path);
if(found){tgt=found.clickTarget;tgtEl=found.el;break;}
const moved=await scrollStep(700);
if(!moved)sStable++;else sStable=0;
}
let content="";
let retryCount=0;
while(retryCount<2&&!content){
if(tgt){
tgtEl.scrollIntoView({block:"center"});
tgt.click();
await sleep(70);
try{
content=await readMonacoContent(file.name)||"";
if(content)logFn("Read from Monaco API.");
}catch(e){logFn(`Monaco error: ${e.message}`);}
}
if(!content){
retryCount++;
if(retryCount<2){logFn(`Retry ${retryCount} for ${file.name}...`);await sleep(300);}
}
}
if(content){
try{
let dH=root;
for(const p of file.dir)dH=await dH.getDirectoryHandle(sanitize(p),{create:true});
const fH=await dH.getFileHandle(sanitize(file.name),{create:true});
const w=await fH.createWritable();
await w.write(content);
await w.close();
saved++;
logFn(`Saved: ${file.name}`);
}catch(e){
logFn(`Save error: ${e.message}`);
failed.push(file.path);
}
}else{
logFn(`ERROR: No content after retries — ${file.path}`);
failed.push(file.path);
}
}
progress(fList.length,fList.length);
stage("הושלם ✅");
logFn(`Done! Saved ${saved}/${fList.length}`);
try{
const logFH=await root.getFileHandle("extraction_log.txt",{create:true});
const logW=await logFH.createWritable();
await logW.write(fullLog);
await logW.close();
}catch(e){}
setTimeout(()=>{
panel.remove();
alert(`✅ החילוץ הסתיים!\nנשמרו ${saved}/${fList.length} קבצים.\n${failed.length?"נכשלו:\n"+failed.join("\n"):""}`);
},1200);
})();

