// 复合后缀兼容修改:只生成计划并持久化原值;真正修改 Eagle 字段由插件在用户确认后执行。 (function () { 'use strict'; const fs = require('fs'); const path = require('path'); const STORE_VERSION = 1; function fullName(name, ext) { return String(name || '') + (ext ? '.' + ext : ''); } /** 返回需要展示给用户的字段变更;不需要修改或被安全条件阻断时返回 null / blocked。 */ function planChange(item, eagleItem, splitCompoundName) { const sourceName = String((item && item.entryName) || ''); const currentName = String((eagleItem && eagleItem.name) || ''); const currentExt = String((eagleItem && eagleItem.ext) || ''); const currentFileName = fullName(currentName, currentExt); if (!sourceName || currentFileName !== sourceName) { return { blocked: true, reason: 'sourceMismatch', sourceName, currentName, currentExt, currentFileName, }; } const parts = splitCompoundName(sourceName); if (!parts || (currentName === parts.name && currentExt === parts.ext)) return null; if (fullName(parts.name, parts.ext) !== sourceName) { return { blocked: true, reason: 'sourceMismatch', sourceName, currentName, currentExt, currentFileName, }; } return { sourceName, currentName, currentExt, currentFileName, newName: parts.name, newExt: parts.ext, newFileName: fullName(parts.name, parts.ext), }; } function emptyStore() { return { version: STORE_VERSION, entries: {} }; } function readStore(file) { try { const data = JSON.parse(fs.readFileSync(file, 'utf8')); if (!data || data.version !== STORE_VERSION || !data.entries || typeof data.entries !== 'object') { throw new Error('备份文件格式不正确'); } return data; } catch (error) { if (error && error.code === 'ENOENT') return emptyStore(); throw error; } } function writeStore(file, data) { fs.mkdirSync(path.dirname(file), { recursive: true }); const temp = file + '.' + process.pid + '.tmp'; fs.writeFileSync(temp, JSON.stringify(data, null, 2) + '\n', 'utf8'); fs.renameSync(temp, file); } function createStore(userDataPath) { const file = path.join(userDataPath, 'SpineThumbnailGenerateServer', 'compound-name-backups.json'); return { file, list() { return Object.values(readStore(file).entries) .sort((left, right) => (right.updatedAt || 0) - (left.updatedAt || 0)); }, remember(change) { const data = readStore(file); if (!data.entries[change.itemId]) { data.entries[change.itemId] = { itemId: change.itemId, sourceName: change.sourceName, folderPath: change.folderPath || '', originalName: change.currentName, originalExt: change.currentExt, appliedName: change.newName, appliedExt: change.newExt, updatedAt: Date.now(), }; writeStore(file, data); } return data.entries[change.itemId]; }, remove(itemId) { const data = readStore(file); if (!data.entries[itemId]) return; delete data.entries[itemId]; writeStore(file, data); }, }; } /** * 为恢复对话框生成可审计列表,并标出哪些条目允许恢复。 * 用户后来亲自改过的字段不会被覆盖。 */ async function inspectBackups(store, getItem, sourceExists) { const entries = store.list(); const rows = []; for (const entry of entries) { let item = null; try { item = await getItem(entry.itemId); if (!item) { let sourcePresent = false; try { sourcePresent = sourceExists ? await sourceExists(entry) : false; } catch (error) { /* 检查失败时保守按缺失处理 */ } if (sourcePresent) { rows.push({ entry, item: null, currentName: entry.appliedName, currentExt: entry.appliedExt, status: 'pluginApplied', }); } else { rows.push({ entry, item: null, status: 'missing' }); } continue; } const currentName = String(item.name || ''); const currentExt = String(item.ext || ''); if (currentName === entry.originalName && currentExt === entry.originalExt) { rows.push({ entry, item, currentName, currentExt, status: 'alreadyOriginal' }); continue; } if (currentName !== entry.appliedName || currentExt !== entry.appliedExt) { rows.push({ entry, item, currentName, currentExt, status: 'changed' }); continue; } rows.push({ entry, item, currentName, currentExt, status: 'ready' }); } catch (error) { rows.push({ entry, item, status: 'error' }); } } return rows; } async function restoreBackups(store, selectedItemIds, getItem, saveItem) { const selected = new Set(selectedItemIds || []); const entries = store.list().filter((entry) => selected.has(entry.itemId)); const result = { total: entries.length, success: 0, skipped: 0, failed: 0 }; for (const entry of entries) { let item = null; try { item = await getItem(entry.itemId); if (!item) { result.skipped += 1; continue; } const currentName = String(item.name || ''); const currentExt = String(item.ext || ''); if (currentName === entry.originalName && currentExt === entry.originalExt) { store.remove(entry.itemId); result.success += 1; continue; } if (currentName !== entry.appliedName || currentExt !== entry.appliedExt) { result.skipped += 1; continue; } item.name = entry.originalName; item.ext = entry.originalExt; await saveItem(item); store.remove(entry.itemId); result.success += 1; } catch (error) { result.failed += 1; } } return result; } const api = { fullName, planChange, createStore, inspectBackups, restoreBackups, STORE_VERSION }; if (typeof window !== 'undefined') window.SpineThumbCompoundCompat = api; else if (typeof module !== 'undefined' && module.exports) module.exports = api; })();