/** * ZDDC Classifier — in-place rename engine. * * Renames SOURCE files to their canonical ZDDC names, ON DISK, IN PLACE. * DESTRUCTIVE — there is no backup. HTTP-backed handles (zddc-server) take the * atomic server-side move (single round-trip); local File System Access handles * copy+remove (the API has no native rename verb). The source folder is the only * thing written. * * Resumable + boring: a file already at its target name is skipped, so a re-run * after an interruption only renames what's left. One file in, one file out. * * Lifted out of the old Rename-in-place spreadsheet so the By-Tracking grid can * drive the same, already-proven rename path. */ (function () { 'use strict'; // The folder handle holding `file`. Fresh-scan files carry it; snapshot-loaded // files resolve it (and their own handle) lazily from the workspace root. async function folderHandleFor(file) { if (file.folderHandle) return file.folderHandle; if (window.app.modules.scanner && window.app.modules.scanner.resolveFileHandle && window.app.rootHandle) { await window.app.modules.scanner.resolveFileHandle(window.app.rootHandle, file); if (file.folderHandle) return file.folderHandle; } throw new Error('source folder not connected'); } // Rename one file in place to `newName`. Returns 'renamed' | 'skipped'. // Mutates the in-memory file object to its NEW identity (originalFilename / // extension / handle) so the rest of the app sees the renamed file. async function renameTo(file, newName) { var oldName = window.zddc.joinExtension(file.originalFilename, file.extension); if (oldName === newName) return 'skipped'; if (file.isVirtual) throw new Error('cannot rename a file inside a ZIP — extract it first'); var folder = await folderHandleFor(file); var perm = await folder.queryPermission({ mode: 'readwrite' }); if (perm !== 'granted') { var granted = await folder.requestPermission({ mode: 'readwrite' }); if (granted !== 'granted') throw new Error('write permission denied'); } var src = window.zddc.source; if (src && src.isHttpHandle && src.isHttpHandle(folder)) { var base = new URL(folder.url()).pathname; await src.moveFile(base + encodeURIComponent(oldName), base + encodeURIComponent(newName)); file.handle = await folder.getFileHandle(newName); } else { var oldHandle = await folder.getFileHandle(oldName); var data = await oldHandle.getFile(); var newHandle = await folder.getFileHandle(newName, { create: true }); var w = await newHandle.createWritable(); await w.write(data); await w.close(); await folder.removeEntry(oldName); file.handle = newHandle; } var split = window.zddc.splitExtension(newName); file.originalFilename = split.name; file.extension = split.extension; return 'renamed'; } // Rename a batch of { file, newName } items. Returns { renamed, skipped, errors }. // onProgress(done, total, name) is called before each file. async function runInPlace(items, onProgress) { var s = { renamed: 0, skipped: 0, errors: 0 }; for (var i = 0; i < items.length; i++) { if (onProgress) onProgress(i + 1, items.length, items[i].newName); try { s[await renameTo(items[i].file, items[i].newName)]++; } catch (e) { s.errors++; if (window.zddc && window.zddc.toast) window.zddc.toast('Rename failed for ' + items[i].newName + ' — ' + (e.message || e), 'error'); } } return s; } window.app.modules.rename = { renameTo: renameTo, runInPlace: runInPlace }; })();