From 2cb70c49d4f452644a4775a25970d839436aac49 Mon Sep 17 00:00:00 2001 From: tianmo Date: Thu, 17 Sep 2026 18:47:17 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=89=AB=E6=8F=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/spine-utils.js | 13 ++++--- release/SpineViewer.eagleplugin | Bin 645544 -> 646001 bytes .../UNIVERSAL_SpineViewer/js/spine-utils.js | 13 ++++--- .../UNIVERSAL_SpineViewer/viewer/spine.html | 34 +++++++++++++++++- tests/compound-extensions.test.js | 2 ++ viewer/spine.html | 34 +++++++++++++++++- 6 files changed, 86 insertions(+), 10 deletions(-) diff --git a/js/spine-utils.js b/js/spine-utils.js index b3b90f2..6d47839 100644 --- a/js/spine-utils.js +++ b/js/spine-utils.js @@ -507,10 +507,15 @@ function discoverAssets(filePath, options) { const selected = path.basename(filePath); const selectedStem = normalizeStem(selected); // 先扫码“选中 item 文件夹 + 同级所有 .info”(精确、不跨批次)。 - const roots = getSearchRoots(filePath); - // 若同级范围无法凑齐骨架+图集(常见于 Eagle 导入瞬间,同伴落在别的 .info), - // 则扩展搜索到整个库的 images/ 目录(全库兜底,靠“同家族 + 同文件夹 + 最近 btime”配对)。 - buildRootsWithLibraryRoot(filePath, roots); + let roots; + if (Array.isArray(options.searchRoots) && options.searchRoots.length) { + roots = [...new Set(options.searchRoots.map((root) => path.resolve(root)))]; + } else { + roots = getSearchRoots(filePath); + // 兼容旧的非查询调用:扩展到整个库。查看器会传入 Eagle API + // 明确列举的候选 item 目录,避免每次预览扫描整库。 + buildRootsWithLibraryRoot(filePath, roots); + } // 导入时 Eagle 会先创建各个 .info,再异步写 folders。严格模式必须把尚未写入 // folders 的同批资源也纳入候选,之后用 metadata.json 的 birthtime 精确配对。 diff --git a/release/SpineViewer.eagleplugin b/release/SpineViewer.eagleplugin index a0ad2b319b5e72394ceace52a87e828bc2aa50f9..3995e28977f8ae813000b8b8ae7d05708eaef426 100644 GIT binary patch delta 17673 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 delta 17150 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%0ATQoMVOh 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 diff --git a/release/UNIVERSAL_SpineViewer/js/spine-utils.js b/release/UNIVERSAL_SpineViewer/js/spine-utils.js index b3b90f2..6d47839 100644 --- a/release/UNIVERSAL_SpineViewer/js/spine-utils.js +++ b/release/UNIVERSAL_SpineViewer/js/spine-utils.js @@ -507,10 +507,15 @@ function discoverAssets(filePath, options) { const selected = path.basename(filePath); const selectedStem = normalizeStem(selected); // 先扫码“选中 item 文件夹 + 同级所有 .info”(精确、不跨批次)。 - const roots = getSearchRoots(filePath); - // 若同级范围无法凑齐骨架+图集(常见于 Eagle 导入瞬间,同伴落在别的 .info), - // 则扩展搜索到整个库的 images/ 目录(全库兜底,靠“同家族 + 同文件夹 + 最近 btime”配对)。 - buildRootsWithLibraryRoot(filePath, roots); + let roots; + if (Array.isArray(options.searchRoots) && options.searchRoots.length) { + roots = [...new Set(options.searchRoots.map((root) => path.resolve(root)))]; + } else { + roots = getSearchRoots(filePath); + // 兼容旧的非查询调用:扩展到整个库。查看器会传入 Eagle API + // 明确列举的候选 item 目录,避免每次预览扫描整库。 + buildRootsWithLibraryRoot(filePath, roots); + } // 导入时 Eagle 会先创建各个 .info,再异步写 folders。严格模式必须把尚未写入 // folders 的同批资源也纳入候选,之后用 metadata.json 的 birthtime 精确配对。 diff --git a/release/UNIVERSAL_SpineViewer/viewer/spine.html b/release/UNIVERSAL_SpineViewer/viewer/spine.html index 7bcec35..3847479 100644 --- a/release/UNIVERSAL_SpineViewer/viewer/spine.html +++ b/release/UNIVERSAL_SpineViewer/viewer/spine.html @@ -545,6 +545,37 @@ return false; } + async function getPreviewSearchRoots(sourcePath) { + const currentDir = path.dirname(sourcePath); + const libraryRoot = utils.findLibraryRoot(sourcePath); + if (!libraryRoot) return null; + const folders = utils.foldersOfItem(sourcePath); + const params = new URLSearchParams({ + limit: '1000', + keyword: utils.normalizeStem(path.basename(sourcePath)), + }); + if (folders.length) params.set('folders', folders.join(',')); + try { + const response = await fetch('http://localhost:41595/api/item/list?' + params.toString() + '&_=' + Date.now(), { + cache: 'no-store', + }); + const result = await response.json(); + if (!response.ok || !result || result.status !== 'success' || !Array.isArray(result.data)) return null; + const imagesDir = path.join(libraryRoot, 'images'); + const roots = [currentDir]; + for (const item of result.data) { + if (!item || !/^[A-Za-z0-9_-]+$/.test(item.id || '')) continue; + if (!utils.extOf(String(item.name || '') + '.' + String(item.ext || ''))) continue; + const itemDir = path.join(imagesDir, item.id + '.info'); + if (utils.isEagleItemDir(itemDir)) roots.push(itemDir); + } + return [...new Set(roots.map((root) => path.resolve(root)))]; + } catch (error) { + log('Eagle 候选素材查询失败,回退到本地发现: ' + error.message); + return null; + } + } + function currentResourcePaths() { if (!activeAssets) return []; const groupStems = new Set([ @@ -1142,7 +1173,8 @@ else showTextPreview(name, parsed === undefined ? text : JSON.stringify(parsed, null, 2)); return; } - const assets = utils.discoverAssets(filePath); + const previewSearchRoots = await getPreviewSearchRoots(filePath); + const assets = utils.discoverAssets(filePath, previewSearchRoots ? { searchRoots: previewSearchRoots } : undefined); if (!assets.skeletonPath || !assets.atlasPath) { if (!assets.skeletonPath) { diff --git a/tests/compound-extensions.test.js b/tests/compound-extensions.test.js index 85493ff..de0a81b 100644 --- a/tests/compound-extensions.test.js +++ b/tests/compound-extensions.test.js @@ -35,6 +35,8 @@ try { assert.equal(utils.discoverAssets(lateAtlas, { strictStem: true }).skeletonPath, null); const lateSkeleton = path.join(late, 'hero.skel.bytes'); fs.writeFileSync(lateSkeleton, Buffer.from('\0' + '3.8.1\0')); assert.equal(utils.discoverAssets(lateAtlas, { strictStem: true, refreshIndex: true }).skeletonPath, lateSkeleton); + const scoped = utils.discoverAssets(lateAtlas, { searchRoots: [late] }); + assert.equal(scoped.skeletonPath, lateSkeleton); for (const [name, json, expected] of [ ['spine.json', { skeleton: { spine: '4.2.43' }, bones: [] }, 'spine'], ['empty-version.json', { skeleton: { spine: '' }, bones: [] }, 'other'], diff --git a/viewer/spine.html b/viewer/spine.html index 7bcec35..3847479 100644 --- a/viewer/spine.html +++ b/viewer/spine.html @@ -545,6 +545,37 @@ return false; } + async function getPreviewSearchRoots(sourcePath) { + const currentDir = path.dirname(sourcePath); + const libraryRoot = utils.findLibraryRoot(sourcePath); + if (!libraryRoot) return null; + const folders = utils.foldersOfItem(sourcePath); + const params = new URLSearchParams({ + limit: '1000', + keyword: utils.normalizeStem(path.basename(sourcePath)), + }); + if (folders.length) params.set('folders', folders.join(',')); + try { + const response = await fetch('http://localhost:41595/api/item/list?' + params.toString() + '&_=' + Date.now(), { + cache: 'no-store', + }); + const result = await response.json(); + if (!response.ok || !result || result.status !== 'success' || !Array.isArray(result.data)) return null; + const imagesDir = path.join(libraryRoot, 'images'); + const roots = [currentDir]; + for (const item of result.data) { + if (!item || !/^[A-Za-z0-9_-]+$/.test(item.id || '')) continue; + if (!utils.extOf(String(item.name || '') + '.' + String(item.ext || ''))) continue; + const itemDir = path.join(imagesDir, item.id + '.info'); + if (utils.isEagleItemDir(itemDir)) roots.push(itemDir); + } + return [...new Set(roots.map((root) => path.resolve(root)))]; + } catch (error) { + log('Eagle 候选素材查询失败,回退到本地发现: ' + error.message); + return null; + } + } + function currentResourcePaths() { if (!activeAssets) return []; const groupStems = new Set([ @@ -1142,7 +1173,8 @@ else showTextPreview(name, parsed === undefined ? text : JSON.stringify(parsed, null, 2)); return; } - const assets = utils.discoverAssets(filePath); + const previewSearchRoots = await getPreviewSearchRoots(filePath); + const assets = utils.discoverAssets(filePath, previewSearchRoots ? { searchRoots: previewSearchRoots } : undefined); if (!assets.skeletonPath || !assets.atlasPath) { if (!assets.skeletonPath) {