From 2a5fe0ce1facfbfcc3b68c11be7f5432a04ac182 Mon Sep 17 00:00:00 2001 From: tianmo Date: Thu, 17 Sep 2026 18:40:29 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B5=84=E6=BA=90=E7=BB=84=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- _locales/de_DE.json | 14 +- _locales/en.json | 12 +- _locales/es_ES.json | 14 +- _locales/ja_JP.json | 14 +- _locales/ko_KR.json | 14 +- _locales/ru_RU.json | 14 +- _locales/zh_CN.json | 12 +- _locales/zh_TW.json | 12 +- js/spine-group-thumbnails.js | 75 ++++++++++ release/SpineViewer.eagleplugin | Bin 642302 -> 645544 bytes release/UNIVERSAL_SpineViewer/README.md | 4 +- .../UNIVERSAL_SpineViewer/_locales/de_DE.json | 14 +- .../UNIVERSAL_SpineViewer/_locales/en.json | 12 +- .../UNIVERSAL_SpineViewer/_locales/es_ES.json | 14 +- .../UNIVERSAL_SpineViewer/_locales/ja_JP.json | 14 +- .../UNIVERSAL_SpineViewer/_locales/ko_KR.json | 14 +- .../UNIVERSAL_SpineViewer/_locales/ru_RU.json | 14 +- .../UNIVERSAL_SpineViewer/_locales/zh_CN.json | 12 +- .../UNIVERSAL_SpineViewer/_locales/zh_TW.json | 12 +- .../js/spine-group-thumbnails.js | 75 ++++++++++ .../UNIVERSAL_SpineViewer/viewer/spine.css | 1 + .../UNIVERSAL_SpineViewer/viewer/spine.html | 130 ++++++++++++------ tests/group-thumbnail-batch.test.js | 85 ++++++++++++ tests/security-privacy.test.js | 6 +- viewer/spine.css | 1 + viewer/spine.html | 130 ++++++++++++------ 27 files changed, 562 insertions(+), 161 deletions(-) create mode 100644 js/spine-group-thumbnails.js create mode 100644 release/UNIVERSAL_SpineViewer/js/spine-group-thumbnails.js create mode 100644 tests/group-thumbnail-batch.test.js diff --git a/README.md b/README.md index e7e1e7c..a9d7406 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ SpineViewer/ - 零时长动画按单帧静态姿势预览 - 自动适配并居中 - 用户可主动将当前帧设为当前素材的自定义缩略图;若已有自定义缩略图,替换前会明确确认 -4. **缩略图**:导入时不运行插件缩略图生成器,由 Eagle 自身处理。用户打开 Spine 预览后,仍可用原有按钮将当前帧设为**当前素材**的自定义缩略图。左侧的“为当前资源组生成缩略图…”会先列出已验证的骨骼、atlas 和贴图,明确确认后才批量处理,并始终跳过已有自定义缩略图的素材。手动缩略图会添加 Spine badge 和导出版本号。 +4. **缩略图**:导入时不运行插件缩略图生成器,由 Eagle 自身处理。用户打开 Spine 预览后,仍可用原有按钮将当前帧设为**当前素材**的自定义缩略图。左侧的“为关联资源生成缩略图”会先列出已验证的同 stem `json / skel / skel.bytes / atlas / atlas.txt` 和 atlas 引用贴图;骨骼与 atlas 默认勾选,图片和已有自定义缩略图的素材默认不勾选;用户可主动勾选已有自定义缩略图的素材,确认后覆盖,原图无法由插件自动恢复。手动缩略图会添加 Spine badge 和导出版本号。 --- @@ -77,7 +77,7 @@ SpineViewer/ Eagle 的公开素材 API 不提供任意自定义元数据字段。预乘设置保存在 Eagle 用户数据目录的 `SpineViewer/preview-settings/` 下,以素材库和素材 ID 区分;不修改 Eagle 的 `metadata.json`、标签或注释,也不会随素材导出到其他电脑。 -Atlas 页面路径按不可信输入处理:插件拒绝绝对路径、`..`、盘符、UNC、URI 以及越出允许目录的符号链接;跨素材贴图只从当前 Eagle 素材库中已经枚举并验证的素材选择。导入阶段不由插件生成缩略图;手动批量操作只作用于明确列出并得到确认的当前资源组,且跳过已有自定义缩略图的素材。诊断日志默认关闭;显式设置 `SPINEVIEWER_DEBUG_LOG=1` 时仅写系统临时目录。 +Atlas 页面路径按不可信输入处理:插件拒绝绝对路径、`..`、盘符、UNC、URI 以及越出允许目录的符号链接;跨素材贴图只从当前 Eagle 素材库中已经枚举并验证的素材选择。导入阶段不由插件生成缩略图;手动批量操作只作用于明确列出并得到确认的当前资源组,已有自定义缩略图的素材默认不选中,只有用户明确勾选才会覆盖。诊断日志默认关闭;显式设置 `SPINEVIEWER_DEBUG_LOG=1` 时仅写系统临时目录。 - 将 Spine 导出的一整套文件(`.skel`/`.json` + `.atlas` + `.png` 等)放在**同一个文件夹**并导入 Eagle。 - 点击其中任何一个文件即可预览动画;点击配套的贴图或 atlas 也会自动找到整套资源。 diff --git a/_locales/de_DE.json b/_locales/de_DE.json index 3f06cac..88e962e 100644 --- a/_locales/de_DE.json +++ b/_locales/de_DE.json @@ -20,18 +20,20 @@ "backgroundTitle": "50×50-Schachbrett, das mit der Leinwand verschoben und skaliert wird und an Blend-Modi teilnimmt", "thumbnail": "Als aktuelles Vorschaubild setzen", "thumbnailTitle": "Aktuellen Frame als benutzerdefiniertes 400×400-Vorschaubild dieses Elements setzen", - "groupThumbnail": "Vorschaubilder für aktuelle Ressourcengruppe erstellen…", - "groupThumbnailTitle": "Aktuelle Spine-Ressourcengruppe prüfen und Vorschaubilder gesammelt erstellen", - "groupDialogTitle": "Vorschaubilder für aktuelle Ressourcengruppe erstellen", + "groupThumbnail": "Vorschaubilder für verknüpfte Ressourcen erstellen", + "groupThumbnailTitle": "Verknüpfte Spine-Ressourcen prüfen und Vorschaubilder gesammelt erstellen", + "groupDialogTitle": "Vorschaubilder für verknüpfte Ressourcen erstellen", "groupDialogSummary": "{generate} werden erstellt, {skip} werden übersprungen.", - "groupDialogNote": "Nur die unten aufgeführten Elemente werden aktualisiert. Elemente mit eigenen Vorschaubildern werden immer übersprungen.", + "groupDialogNote": "Nur markierte verknüpfte Ressourcen erhalten Vorschaubilder. Bilder und Ressourcen mit eigenen Vorschaubildern sind standardmäßig abgewählt. Werden letztere ausgewählt, wird das vorhandene Vorschaubild ersetzt und kann vom Plugin nicht automatisch wiederhergestellt werden.", "cancel": "Abbrechen", "groupConfirm": "Erstellen", "groupWillGenerate": "Wird erstellt", + "groupNotSelected": "Nicht ausgewählt", "groupSkipCustom": "Übersprungen: eigenes Vorschaubild vorhanden", "groupUnavailable": "Übersprungen: nicht verifizierbar", "groupNoTargets": "In der aktuellen Ressourcengruppe gibt es keine geeigneten Vorschaubilder.", "groupGenerating": "Vorschaubilder werden erstellt {current}/{total}…", + "groupApplyNotConfirmed": "Eagle hat die Anwendung des Vorschaubilds nicht bestätigt", "groupComplete": "Fertig: {success} erfolgreich, {skip} übersprungen, {failed} fehlgeschlagen.", "versionTitle": "Spine-Version", "reloadTitle": "Ordner neu laden", @@ -89,6 +91,8 @@ "loadFailed": "Laden fehlgeschlagen", "notSpineText": "Diese Datei ist keine Spine-Ressource im Format .atlas.txt oder .skel.bytes.", "truncated256": "\n\n(nur die ersten 256 KB werden angezeigt)", - "truncated1m": "\n\n(große Datei; nur das erste 1 MB wird angezeigt)" + "truncated1m": "\n\n(große Datei; nur das erste 1 MB wird angezeigt)", + "groupWillReplaceCustom": "Ersetzt vorhandenes eigenes Vorschaubild", + "groupCustomNotSelected": "Eigenes Vorschaubild vorhanden (nicht ausgewählt)" } } diff --git a/_locales/en.json b/_locales/en.json index de4fc86..60950a5 100644 --- a/_locales/en.json +++ b/_locales/en.json @@ -20,18 +20,22 @@ "backgroundTitle": "50×50 checkerboard that pans and zooms with the canvas and participates in blend modes", "thumbnail": "Set current item thumbnail", "thumbnailTitle": "Set the current frame as this item's 400×400 custom thumbnail", - "groupThumbnail": "Generate thumbnails for current asset group…", - "groupThumbnailTitle": "Review the current Spine asset group, then generate thumbnails in a batch", - "groupDialogTitle": "Generate thumbnails for current asset group", + "groupThumbnail": "Generate thumbnails for related assets", + "groupThumbnailTitle": "Review related Spine assets, then generate thumbnails in a batch", + "groupDialogTitle": "Generate thumbnails for related assets", "groupDialogSummary": "Generate {generate} item(s) and skip {skip} item(s).", - "groupDialogNote": "Only the items explicitly listed below will be updated. Items with existing custom thumbnails are always skipped.", + "groupDialogNote": "Only checked related assets will receive thumbnails. Images and assets with custom thumbnails are unchecked by default. Selecting the latter replaces the existing thumbnail, which the plugin cannot automatically restore.", "cancel": "Cancel", "groupConfirm": "Generate", "groupWillGenerate": "Will generate", + "groupWillReplaceCustom": "Will replace existing custom thumbnail", + "groupCustomNotSelected": "Custom thumbnail exists (not selected)", + "groupNotSelected": "Not selected", "groupSkipCustom": "Skipped: custom thumbnail exists", "groupUnavailable": "Skipped: could not verify", "groupNoTargets": "There are no eligible thumbnails in the current asset group.", "groupGenerating": "Generating asset-group thumbnails {current}/{total}…", + "groupApplyNotConfirmed": "Eagle did not confirm that the thumbnail was applied", "groupComplete": "Asset-group thumbnails complete: {success} succeeded, {skip} skipped, {failed} failed.", "versionTitle": "Spine version", "reloadTitle": "Reload folder", diff --git a/_locales/es_ES.json b/_locales/es_ES.json index b0694fc..e53a8ba 100644 --- a/_locales/es_ES.json +++ b/_locales/es_ES.json @@ -20,18 +20,20 @@ "backgroundTitle": "Fondo de cuadros de 50×50 que se desplaza y escala con el lienzo y participa en los modos de fusión", "thumbnail": "Usar como miniatura actual", "thumbnailTitle": "Usar el fotograma actual como miniatura personalizada de 400×400 de este elemento", - "groupThumbnail": "Generar miniaturas del grupo actual…", - "groupThumbnailTitle": "Revisar el grupo de recursos Spine actual y generar miniaturas por lotes", - "groupDialogTitle": "Generar miniaturas del grupo actual", + "groupThumbnail": "Generar miniaturas de recursos relacionados", + "groupThumbnailTitle": "Revisar los recursos Spine relacionados y generar miniaturas por lotes", + "groupDialogTitle": "Generar miniaturas de recursos relacionados", "groupDialogSummary": "Se generarán {generate} y se omitirán {skip}.", - "groupDialogNote": "Solo se actualizarán los elementos indicados abajo. Los elementos con miniaturas personalizadas siempre se omiten.", + "groupDialogNote": "Solo se generarán miniaturas para los recursos relacionados marcados. Las imágenes y los recursos con miniaturas personalizadas no están marcados por defecto. Si seleccionas estos últimos, se reemplazará la miniatura existente y el complemento no podrá restaurarla automáticamente.", "cancel": "Cancelar", "groupConfirm": "Generar", "groupWillGenerate": "Se generará", + "groupNotSelected": "No seleccionado", "groupSkipCustom": "Omitido: ya tiene miniatura personalizada", "groupUnavailable": "Omitido: no se pudo verificar", "groupNoTargets": "No hay miniaturas disponibles para generar en el grupo actual.", "groupGenerating": "Generando miniaturas {current}/{total}…", + "groupApplyNotConfirmed": "Eagle no confirmó que se aplicara la miniatura", "groupComplete": "Completado: {success} correctas, {skip} omitidas y {failed} fallidas.", "versionTitle": "Versión de Spine", "reloadTitle": "Recargar carpeta", @@ -89,6 +91,8 @@ "loadFailed": "Error al cargar", "notSpineText": "Este archivo no es un recurso Spine en formato .atlas.txt o .skel.bytes.", "truncated256": "\n\n(solo se muestran los primeros 256 KB)", - "truncated1m": "\n\n(archivo grande; solo se muestra el primer 1 MB)" + "truncated1m": "\n\n(archivo grande; solo se muestra el primer 1 MB)", + "groupWillReplaceCustom": "Reemplazará la miniatura personalizada", + "groupCustomNotSelected": "Tiene miniatura personalizada (no seleccionado)" } } diff --git a/_locales/ja_JP.json b/_locales/ja_JP.json index 574c0bf..841e1b1 100644 --- a/_locales/ja_JP.json +++ b/_locales/ja_JP.json @@ -20,18 +20,20 @@ "backgroundTitle": "50×50 のチェッカー背景。キャンバスの移動・拡大に追従し、ブレンドモードにも参加します", "thumbnail": "現在の項目のサムネイルに設定", "thumbnailTitle": "現在のフレームをこの項目の 400×400 カスタムサムネイルに設定", - "groupThumbnail": "現在のアセットグループのサムネイルを生成…", - "groupThumbnailTitle": "現在の Spine アセットグループを確認して一括生成", - "groupDialogTitle": "現在のアセットグループのサムネイルを生成", + "groupThumbnail": "関連アセットのサムネイルを生成", + "groupThumbnailTitle": "関連する Spine アセットを確認して一括生成", + "groupDialogTitle": "関連アセットのサムネイルを生成", "groupDialogSummary": "{generate} 件を生成し、{skip} 件をスキップします。", - "groupDialogNote": "下に明示された項目だけを更新します。カスタムサムネイルがある項目は必ずスキップします。", + "groupDialogNote": "チェックした関連アセットだけにサムネイルを生成します。画像とカスタムサムネイルがあるアセットは初期状態で未選択です。後者を選ぶと既存のサムネイルが置き換えられ、プラグインでは自動復元できません。", "cancel": "キャンセル", "groupConfirm": "生成", "groupWillGenerate": "生成対象", + "groupNotSelected": "未選択", "groupSkipCustom": "スキップ:カスタムサムネイルあり", "groupUnavailable": "スキップ:検証できません", "groupNoTargets": "現在のアセットグループに生成可能なサムネイルはありません。", "groupGenerating": "アセットグループのサムネイルを生成中 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle でサムネイルの適用を確認できませんでした", "groupComplete": "完了:成功 {success}、スキップ {skip}、失敗 {failed}。", "versionTitle": "Spine バージョン", "reloadTitle": "フォルダーを再読み込み", @@ -89,6 +91,8 @@ "loadFailed": "読み込みに失敗しました", "notSpineText": "このファイルは .atlas.txt または .skel.bytes 形式の Spine リソースではありません。", "truncated256": "\n\n(先頭 256 KB のみ表示)", - "truncated1m": "\n\n(ファイルが大きいため、先頭 1 MB のみ表示)" + "truncated1m": "\n\n(ファイルが大きいため、先頭 1 MB のみ表示)", + "groupWillReplaceCustom": "既存のカスタムサムネイルを置き換えます", + "groupCustomNotSelected": "カスタムサムネイルあり(未選択)" } } diff --git a/_locales/ko_KR.json b/_locales/ko_KR.json index 4d86323..2ad05f1 100644 --- a/_locales/ko_KR.json +++ b/_locales/ko_KR.json @@ -20,18 +20,20 @@ "backgroundTitle": "50×50 체커 배경. 캔버스 이동·확대를 따라가며 블렌드 모드에도 참여합니다", "thumbnail": "현재 항목 썸네일로 설정", "thumbnailTitle": "현재 프레임을 이 항목의 400×400 사용자 지정 썸네일로 설정", - "groupThumbnail": "현재 자산 그룹 썸네일 생성…", - "groupThumbnailTitle": "현재 Spine 자산 그룹을 확인한 후 일괄 생성", - "groupDialogTitle": "현재 자산 그룹 썸네일 생성", + "groupThumbnail": "관련 자산 썸네일 생성", + "groupThumbnailTitle": "관련 Spine 자산을 확인한 후 일괄 생성", + "groupDialogTitle": "관련 자산 썸네일 생성", "groupDialogSummary": "{generate}개를 생성하고 {skip}개를 건너뜁니다.", - "groupDialogNote": "아래에 명시된 항목만 업데이트합니다. 기존 사용자 지정 썸네일이 있는 항목은 항상 건너뜁니다.", + "groupDialogNote": "선택한 관련 자산에만 썸네일을 생성합니다. 이미지와 사용자 지정 썸네일이 있는 자산은 기본적으로 선택하지 않습니다. 후자를 선택하면 기존 썸네일이 교체되며 플러그인에서 자동 복원할 수 없습니다.", "cancel": "취소", "groupConfirm": "생성", "groupWillGenerate": "생성 예정", + "groupNotSelected": "선택하지 않음", "groupSkipCustom": "건너뛰: 사용자 지정 썸네일 있음", "groupUnavailable": "건너뛰: 확인할 수 없음", "groupNoTargets": "현재 자산 그룹에 생성할 수 있는 썸네일이 없습니다.", "groupGenerating": "자산 그룹 썸네일 생성 중 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle에서 썸네일 적용을 확인하지 못했습니다", "groupComplete": "완료: 성공 {success}, 건너뛰 {skip}, 실패 {failed}.", "versionTitle": "Spine 버전", "reloadTitle": "폴더 다시 불러오기", @@ -89,6 +91,8 @@ "loadFailed": "불러오기 실패", "notSpineText": "이 파일은 .atlas.txt 또는 .skel.bytes 형식의 Spine 리소스가 아닙니다.", "truncated256": "\n\n(앞부분 256 KB만 표시)", - "truncated1m": "\n\n(파일이 커서 앞부분 1 MB만 표시)" + "truncated1m": "\n\n(파일이 커서 앞부분 1 MB만 표시)", + "groupWillReplaceCustom": "기존 사용자 지정 썸네일 교체", + "groupCustomNotSelected": "사용자 지정 썸네일 있음(선택 안 함)" } } diff --git a/_locales/ru_RU.json b/_locales/ru_RU.json index 6e0b32b..074ab2a 100644 --- a/_locales/ru_RU.json +++ b/_locales/ru_RU.json @@ -20,18 +20,20 @@ "backgroundTitle": "Шахматный фон 50×50: следует за сдвигом и масштабом холста и участвует в режимах смешивания", "thumbnail": "Сделать миниатюрой элемента", "thumbnailTitle": "Установить текущий кадр как пользовательскую миниатюру 400×400 для этого элемента", - "groupThumbnail": "Создать миниатюры для текущей группы…", - "groupThumbnailTitle": "Проверить группу Spine и создать миниатюры пакетно", - "groupDialogTitle": "Создать миниатюры для текущей группы", + "groupThumbnail": "Создать миниатюры для связанных ресурсов", + "groupThumbnailTitle": "Проверить связанные ресурсы Spine и создать миниатюры", + "groupDialogTitle": "Создать миниатюры для связанных ресурсов", "groupDialogSummary": "Будет создано: {generate}; пропущено: {skip}.", - "groupDialogNote": "Будут обновлены только явно указанные ниже элементы. Элементы с пользовательскими миниатюрами всегда пропускаются.", + "groupDialogNote": "Миниатюры будут созданы только для отмеченных связанных ресурсов. Изображения и ресурсы со своими миниатюрами по умолчанию не отмечены. Выбор последних заменит существующую миниатюру, и плагин не сможет восстановить её автоматически.", "cancel": "Отмена", "groupConfirm": "Создать", "groupWillGenerate": "Будет создано", + "groupNotSelected": "Не выбрано", "groupSkipCustom": "Пропущено: есть своя миниатюра", "groupUnavailable": "Пропущено: не удалось проверить", "groupNoTargets": "В текущей группе нет подходящих миниатюр.", "groupGenerating": "Создание миниатюр {current}/{total}…", + "groupApplyNotConfirmed": "Eagle не подтвердил применение миниатюры", "groupComplete": "Готово: {success} успешно, {skip} пропущено, {failed} с ошибкой.", "versionTitle": "Версия Spine", "reloadTitle": "Перезагрузить папку", @@ -89,6 +91,8 @@ "loadFailed": "Не удалось загрузить", "notSpineText": "Этот файл не является ресурсом Spine в формате .atlas.txt или .skel.bytes.", "truncated256": "\n\n(показаны только первые 256 КБ)", - "truncated1m": "\n\n(файл большой, показан только первый 1 МБ)" + "truncated1m": "\n\n(файл большой, показан только первый 1 МБ)", + "groupWillReplaceCustom": "Заменит существующую миниатюру", + "groupCustomNotSelected": "Есть своя миниатюра (не выбрано)" } } diff --git a/_locales/zh_CN.json b/_locales/zh_CN.json index d019130..d9ff0f2 100644 --- a/_locales/zh_CN.json +++ b/_locales/zh_CN.json @@ -20,18 +20,22 @@ "backgroundTitle": "50×50 方格背景,随画布移动和缩放,并参与混合模式", "thumbnail": "设为当前素材缩略图", "thumbnailTitle": "将当前帧设为当前素材的 400×400 自定义缩略图", - "groupThumbnail": "为当前资源组生成缩略图…", - "groupThumbnailTitle": "列出当前 Spine 资源组,确认后批量生成缩略图", - "groupDialogTitle": "为当前资源组生成缩略图", + "groupThumbnail": "为关联资源生成缩略图", + "groupThumbnailTitle": "列出当前 Spine 关联资源,确认后批量生成缩略图", + "groupDialogTitle": "为关联资源生成缩略图", "groupDialogSummary": "将生成 {generate} 项,跳过 {skip} 项。", - "groupDialogNote": "只会更新下列明确列出的素材;已有自定义缩略图的素材会自动跳过。", + "groupDialogNote": "只会为勾选的关联资源生成缩略图。图片和已有自定义缩略图的资源默认不勾选;若勾选后者,原缩略图将被替换且插件无法自动恢复。", "cancel": "取消", "groupConfirm": "确认生成", "groupWillGenerate": "将生成", + "groupWillReplaceCustom": "将替换已有自定义缩略图", + "groupCustomNotSelected": "已有自定义缩略图(未选择)", + "groupNotSelected": "未选择", "groupSkipCustom": "跳过:已有自定义缩略图", "groupUnavailable": "跳过:无法验证", "groupNoTargets": "当前资源组没有可生成的缩略图。", "groupGenerating": "正在生成资源组缩略图 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle 未确认缩略图已应用", "groupComplete": "资源组缩略图已完成:成功 {success},跳过 {skip},失败 {failed}。", "versionTitle": "Spine 版本", "reloadTitle": "重新加载目录", diff --git a/_locales/zh_TW.json b/_locales/zh_TW.json index 08395d6..6683cdb 100644 --- a/_locales/zh_TW.json +++ b/_locales/zh_TW.json @@ -20,18 +20,22 @@ "backgroundTitle": "50×50 方格背景,隨畫布移動和縮放,並參與混合模式", "thumbnail": "設為目前素材縮圖", "thumbnailTitle": "將目前影格設為目前素材的 400×400 自訂縮圖", - "groupThumbnail": "為目前資源組產生縮圖…", - "groupThumbnailTitle": "列出目前 Spine 資源組,確認後批次產生縮圖", - "groupDialogTitle": "為目前資源組產生縮圖", + "groupThumbnail": "為關聯資源產生縮圖", + "groupThumbnailTitle": "列出目前 Spine 關聯資源,確認後批次產生縮圖", + "groupDialogTitle": "為關聯資源產生縮圖", "groupDialogSummary": "將產生 {generate} 項,跳過 {skip} 項。", - "groupDialogNote": "只會更新下列明確列出的素材;已有自訂縮圖的素材會自動跳過。", + "groupDialogNote": "只會為勾選的關聯資源產生縮圖。圖片和已有自訂縮圖的資源預設不勾選;若勾選後者,原縮圖將被取代且外掛無法自動復原。", "cancel": "取消", "groupConfirm": "確認產生", "groupWillGenerate": "將產生", + "groupWillReplaceCustom": "將取代已有自訂縮圖", + "groupCustomNotSelected": "已有自訂縮圖(未選擇)", + "groupNotSelected": "未選擇", "groupSkipCustom": "跳過:已有自訂縮圖", "groupUnavailable": "跳過:無法驗證", "groupNoTargets": "目前資源組沒有可產生的縮圖。", "groupGenerating": "正在產生資源組縮圖 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle 未確認縮圖已套用", "groupComplete": "資源組縮圖已完成:成功 {success},跳過 {skip},失敗 {failed}。", "versionTitle": "Spine 版本", "reloadTitle": "重新載入目錄", diff --git a/js/spine-group-thumbnails.js b/js/spine-group-thumbnails.js new file mode 100644 index 0000000..822e4b2 --- /dev/null +++ b/js/spine-group-thumbnails.js @@ -0,0 +1,75 @@ +'use strict'; + +const crypto = require('crypto'); +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +function orderCurrentTargetLast(targets, currentSourcePath) { + if (!currentSourcePath) return [...targets]; + const current = path.resolve(currentSourcePath); + return [...targets].sort((left, right) => { + const leftIsCurrent = path.resolve(left.sourcePath) === current; + const rightIsCurrent = path.resolve(right.sourcePath) === current; + return Number(leftIsCurrent) - Number(rightIsCurrent); + }); +} + +/** + * Apply one rendered frame to explicitly selected Eagle items. + * Each item gets an independent temporary file because Eagle may consume or + * defer reading the file passed to setCustomThumbnail. + */ +async function applyThumbnailTargets(options) { + const targets = options.targets || []; + const settleDelayMs = options.settleDelayMs === undefined ? 800 : options.settleDelayMs; + const cleanupDelayMs = options.cleanupDelayMs === undefined ? 1200 : options.cleanupDelayMs; + const retryAttempts = options.retryAttempts === undefined ? 3 : options.retryAttempts; + const delay = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve(); + const tempPaths = []; + let success = 0; + let skipped = Number(options.initialSkipped) || 0; + let failed = 0; + for (let index = 0; index < targets.length; index++) { + if (options.onProgress) options.onProgress(index + 1, targets.length); + let itemTempPath = null; + try { + const target = targets[index]; + const fresh = await options.getItem(target.sourcePath); + if (fresh.data.customThumbnail === true && target.allowOverwrite !== true) { skipped++; continue; } + itemTempPath = path.join(os.tmpdir(), 'spineviewer-group-' + fresh.id + '-' + crypto.randomBytes(12).toString('hex') + options.rendered.extension); + fs.writeFileSync(itemTempPath, options.rendered.buffer); + tempPaths.push(itemTempPath); + let applied = false; + let lastError = null; + for (let attempt = 0; attempt < retryAttempts && !applied; attempt++) { + try { + const accepted = await options.setThumbnail(fresh.id, itemTempPath); + if (accepted !== true) throw new Error(options.notConfirmedMessage || 'Thumbnail update was rejected'); + applied = await options.waitForApplied(target.sourcePath); + if (!applied) throw new Error(options.notConfirmedMessage || 'Thumbnail update was not confirmed'); + } catch (error) { + lastError = error; + if (attempt < retryAttempts - 1) await delay(settleDelayMs); + } + } + if (!applied) throw lastError || new Error(options.notConfirmedMessage || 'Thumbnail update was not confirmed'); + // The local HTTP API can resolve before Eagle has finished consuming the + // supplied file. Keep every file alive and serialize requests with a short + // settling interval so a later request cannot replace an earlier queued job. + await delay(settleDelayMs); + success++; + if (options.onSuccess) options.onSuccess(fresh); + } catch (error) { + failed++; + if (options.onError) options.onError(error); + } finally { /* temporary inputs are retained until the whole queue settles */ } + } + await delay(cleanupDelayMs); + for (const tempPath of tempPaths) { + try { if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath); } catch (e) { /* ignore */ } + } + return { success, skipped, failed }; +} + +module.exports = { applyThumbnailTargets, orderCurrentTargetLast }; diff --git a/release/SpineViewer.eagleplugin b/release/SpineViewer.eagleplugin index 9f26253866a535508724ec74a0d8db0f487d142b..a0ad2b319b5e72394ceace52a87e828bc2aa50f9 100644 GIT binary patch delta 43617 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 TXnX)ZzzP-s&^i2iQUv@Tj;vp& delta 40417 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 JBh!pQ{{tWr8aMy| diff --git a/release/UNIVERSAL_SpineViewer/README.md b/release/UNIVERSAL_SpineViewer/README.md index 105d7b4..56d6d87 100644 --- a/release/UNIVERSAL_SpineViewer/README.md +++ b/release/UNIVERSAL_SpineViewer/README.md @@ -7,13 +7,13 @@ Eagle 的离线 Spine 骨骼动画预览插件,支持 Spine 3.4–4.3,适用 1. 将同一套骨骼文件(`.skel` / `.skel.bytes` / Spine `.json`)、图集(`.atlas` / `.atlas.txt`)和配套贴图一起导入 Eagle,建议放在同一个 Eagle 文件夹内。 2. 打开骨骼或图集文件即可预览动画,并可切换动画、皮肤、速度、循环、背景和 PMA。 3. 插件不接管导入阶段的缩略图,由 Eagle 自身处理。 -4. 打开预览后,原有按钮可把当前帧设为当前素材的自定义缩略图。其左侧的“为当前资源组生成缩略图…”会先明确列出受影响的骨骼、atlas 和贴图,得到确认后才批量生成,并始终跳过已有自定义缩略图的素材。 +4. 打开预览后,原有按钮可把当前帧设为当前素材的自定义缩略图。其左侧的“为关联资源生成缩略图”会列出同 stem 的骨骼、atlas 及已验证贴图;骨骼与 atlas 默认勾选,图片和已有自定义缩略图的素材默认不勾选;用户仍可主动选择并覆盖,原图无法由插件自动恢复。 ## 安全与隐私 - Atlas 贴图只允许安全的相对路径;绝对路径、`..`、盘符、UNC、URI 和越界符号链接会被拒绝。 - 跨素材配对只使用当前 Eagle 素材库中已枚举并验证的文件。 -- 单素材按钮只作用于当前素材。资源组按钮会先列出全部受影响素材并要求确认,且不会覆盖已有自定义缩略图。 +- 单素材按钮只作用于当前素材。资源组按钮会先列出全部受影响素材并要求确认,已有自定义缩略图默认不选中,只有用户明确勾选才会覆盖。 ## 多语言 diff --git a/release/UNIVERSAL_SpineViewer/_locales/de_DE.json b/release/UNIVERSAL_SpineViewer/_locales/de_DE.json index 3f06cac..88e962e 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/de_DE.json +++ b/release/UNIVERSAL_SpineViewer/_locales/de_DE.json @@ -20,18 +20,20 @@ "backgroundTitle": "50×50-Schachbrett, das mit der Leinwand verschoben und skaliert wird und an Blend-Modi teilnimmt", "thumbnail": "Als aktuelles Vorschaubild setzen", "thumbnailTitle": "Aktuellen Frame als benutzerdefiniertes 400×400-Vorschaubild dieses Elements setzen", - "groupThumbnail": "Vorschaubilder für aktuelle Ressourcengruppe erstellen…", - "groupThumbnailTitle": "Aktuelle Spine-Ressourcengruppe prüfen und Vorschaubilder gesammelt erstellen", - "groupDialogTitle": "Vorschaubilder für aktuelle Ressourcengruppe erstellen", + "groupThumbnail": "Vorschaubilder für verknüpfte Ressourcen erstellen", + "groupThumbnailTitle": "Verknüpfte Spine-Ressourcen prüfen und Vorschaubilder gesammelt erstellen", + "groupDialogTitle": "Vorschaubilder für verknüpfte Ressourcen erstellen", "groupDialogSummary": "{generate} werden erstellt, {skip} werden übersprungen.", - "groupDialogNote": "Nur die unten aufgeführten Elemente werden aktualisiert. Elemente mit eigenen Vorschaubildern werden immer übersprungen.", + "groupDialogNote": "Nur markierte verknüpfte Ressourcen erhalten Vorschaubilder. Bilder und Ressourcen mit eigenen Vorschaubildern sind standardmäßig abgewählt. Werden letztere ausgewählt, wird das vorhandene Vorschaubild ersetzt und kann vom Plugin nicht automatisch wiederhergestellt werden.", "cancel": "Abbrechen", "groupConfirm": "Erstellen", "groupWillGenerate": "Wird erstellt", + "groupNotSelected": "Nicht ausgewählt", "groupSkipCustom": "Übersprungen: eigenes Vorschaubild vorhanden", "groupUnavailable": "Übersprungen: nicht verifizierbar", "groupNoTargets": "In der aktuellen Ressourcengruppe gibt es keine geeigneten Vorschaubilder.", "groupGenerating": "Vorschaubilder werden erstellt {current}/{total}…", + "groupApplyNotConfirmed": "Eagle hat die Anwendung des Vorschaubilds nicht bestätigt", "groupComplete": "Fertig: {success} erfolgreich, {skip} übersprungen, {failed} fehlgeschlagen.", "versionTitle": "Spine-Version", "reloadTitle": "Ordner neu laden", @@ -89,6 +91,8 @@ "loadFailed": "Laden fehlgeschlagen", "notSpineText": "Diese Datei ist keine Spine-Ressource im Format .atlas.txt oder .skel.bytes.", "truncated256": "\n\n(nur die ersten 256 KB werden angezeigt)", - "truncated1m": "\n\n(große Datei; nur das erste 1 MB wird angezeigt)" + "truncated1m": "\n\n(große Datei; nur das erste 1 MB wird angezeigt)", + "groupWillReplaceCustom": "Ersetzt vorhandenes eigenes Vorschaubild", + "groupCustomNotSelected": "Eigenes Vorschaubild vorhanden (nicht ausgewählt)" } } diff --git a/release/UNIVERSAL_SpineViewer/_locales/en.json b/release/UNIVERSAL_SpineViewer/_locales/en.json index de4fc86..60950a5 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/en.json +++ b/release/UNIVERSAL_SpineViewer/_locales/en.json @@ -20,18 +20,22 @@ "backgroundTitle": "50×50 checkerboard that pans and zooms with the canvas and participates in blend modes", "thumbnail": "Set current item thumbnail", "thumbnailTitle": "Set the current frame as this item's 400×400 custom thumbnail", - "groupThumbnail": "Generate thumbnails for current asset group…", - "groupThumbnailTitle": "Review the current Spine asset group, then generate thumbnails in a batch", - "groupDialogTitle": "Generate thumbnails for current asset group", + "groupThumbnail": "Generate thumbnails for related assets", + "groupThumbnailTitle": "Review related Spine assets, then generate thumbnails in a batch", + "groupDialogTitle": "Generate thumbnails for related assets", "groupDialogSummary": "Generate {generate} item(s) and skip {skip} item(s).", - "groupDialogNote": "Only the items explicitly listed below will be updated. Items with existing custom thumbnails are always skipped.", + "groupDialogNote": "Only checked related assets will receive thumbnails. Images and assets with custom thumbnails are unchecked by default. Selecting the latter replaces the existing thumbnail, which the plugin cannot automatically restore.", "cancel": "Cancel", "groupConfirm": "Generate", "groupWillGenerate": "Will generate", + "groupWillReplaceCustom": "Will replace existing custom thumbnail", + "groupCustomNotSelected": "Custom thumbnail exists (not selected)", + "groupNotSelected": "Not selected", "groupSkipCustom": "Skipped: custom thumbnail exists", "groupUnavailable": "Skipped: could not verify", "groupNoTargets": "There are no eligible thumbnails in the current asset group.", "groupGenerating": "Generating asset-group thumbnails {current}/{total}…", + "groupApplyNotConfirmed": "Eagle did not confirm that the thumbnail was applied", "groupComplete": "Asset-group thumbnails complete: {success} succeeded, {skip} skipped, {failed} failed.", "versionTitle": "Spine version", "reloadTitle": "Reload folder", diff --git a/release/UNIVERSAL_SpineViewer/_locales/es_ES.json b/release/UNIVERSAL_SpineViewer/_locales/es_ES.json index b0694fc..e53a8ba 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/es_ES.json +++ b/release/UNIVERSAL_SpineViewer/_locales/es_ES.json @@ -20,18 +20,20 @@ "backgroundTitle": "Fondo de cuadros de 50×50 que se desplaza y escala con el lienzo y participa en los modos de fusión", "thumbnail": "Usar como miniatura actual", "thumbnailTitle": "Usar el fotograma actual como miniatura personalizada de 400×400 de este elemento", - "groupThumbnail": "Generar miniaturas del grupo actual…", - "groupThumbnailTitle": "Revisar el grupo de recursos Spine actual y generar miniaturas por lotes", - "groupDialogTitle": "Generar miniaturas del grupo actual", + "groupThumbnail": "Generar miniaturas de recursos relacionados", + "groupThumbnailTitle": "Revisar los recursos Spine relacionados y generar miniaturas por lotes", + "groupDialogTitle": "Generar miniaturas de recursos relacionados", "groupDialogSummary": "Se generarán {generate} y se omitirán {skip}.", - "groupDialogNote": "Solo se actualizarán los elementos indicados abajo. Los elementos con miniaturas personalizadas siempre se omiten.", + "groupDialogNote": "Solo se generarán miniaturas para los recursos relacionados marcados. Las imágenes y los recursos con miniaturas personalizadas no están marcados por defecto. Si seleccionas estos últimos, se reemplazará la miniatura existente y el complemento no podrá restaurarla automáticamente.", "cancel": "Cancelar", "groupConfirm": "Generar", "groupWillGenerate": "Se generará", + "groupNotSelected": "No seleccionado", "groupSkipCustom": "Omitido: ya tiene miniatura personalizada", "groupUnavailable": "Omitido: no se pudo verificar", "groupNoTargets": "No hay miniaturas disponibles para generar en el grupo actual.", "groupGenerating": "Generando miniaturas {current}/{total}…", + "groupApplyNotConfirmed": "Eagle no confirmó que se aplicara la miniatura", "groupComplete": "Completado: {success} correctas, {skip} omitidas y {failed} fallidas.", "versionTitle": "Versión de Spine", "reloadTitle": "Recargar carpeta", @@ -89,6 +91,8 @@ "loadFailed": "Error al cargar", "notSpineText": "Este archivo no es un recurso Spine en formato .atlas.txt o .skel.bytes.", "truncated256": "\n\n(solo se muestran los primeros 256 KB)", - "truncated1m": "\n\n(archivo grande; solo se muestra el primer 1 MB)" + "truncated1m": "\n\n(archivo grande; solo se muestra el primer 1 MB)", + "groupWillReplaceCustom": "Reemplazará la miniatura personalizada", + "groupCustomNotSelected": "Tiene miniatura personalizada (no seleccionado)" } } diff --git a/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json b/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json index 574c0bf..841e1b1 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json +++ b/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json @@ -20,18 +20,20 @@ "backgroundTitle": "50×50 のチェッカー背景。キャンバスの移動・拡大に追従し、ブレンドモードにも参加します", "thumbnail": "現在の項目のサムネイルに設定", "thumbnailTitle": "現在のフレームをこの項目の 400×400 カスタムサムネイルに設定", - "groupThumbnail": "現在のアセットグループのサムネイルを生成…", - "groupThumbnailTitle": "現在の Spine アセットグループを確認して一括生成", - "groupDialogTitle": "現在のアセットグループのサムネイルを生成", + "groupThumbnail": "関連アセットのサムネイルを生成", + "groupThumbnailTitle": "関連する Spine アセットを確認して一括生成", + "groupDialogTitle": "関連アセットのサムネイルを生成", "groupDialogSummary": "{generate} 件を生成し、{skip} 件をスキップします。", - "groupDialogNote": "下に明示された項目だけを更新します。カスタムサムネイルがある項目は必ずスキップします。", + "groupDialogNote": "チェックした関連アセットだけにサムネイルを生成します。画像とカスタムサムネイルがあるアセットは初期状態で未選択です。後者を選ぶと既存のサムネイルが置き換えられ、プラグインでは自動復元できません。", "cancel": "キャンセル", "groupConfirm": "生成", "groupWillGenerate": "生成対象", + "groupNotSelected": "未選択", "groupSkipCustom": "スキップ:カスタムサムネイルあり", "groupUnavailable": "スキップ:検証できません", "groupNoTargets": "現在のアセットグループに生成可能なサムネイルはありません。", "groupGenerating": "アセットグループのサムネイルを生成中 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle でサムネイルの適用を確認できませんでした", "groupComplete": "完了:成功 {success}、スキップ {skip}、失敗 {failed}。", "versionTitle": "Spine バージョン", "reloadTitle": "フォルダーを再読み込み", @@ -89,6 +91,8 @@ "loadFailed": "読み込みに失敗しました", "notSpineText": "このファイルは .atlas.txt または .skel.bytes 形式の Spine リソースではありません。", "truncated256": "\n\n(先頭 256 KB のみ表示)", - "truncated1m": "\n\n(ファイルが大きいため、先頭 1 MB のみ表示)" + "truncated1m": "\n\n(ファイルが大きいため、先頭 1 MB のみ表示)", + "groupWillReplaceCustom": "既存のカスタムサムネイルを置き換えます", + "groupCustomNotSelected": "カスタムサムネイルあり(未選択)" } } diff --git a/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json b/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json index 4d86323..2ad05f1 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json +++ b/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json @@ -20,18 +20,20 @@ "backgroundTitle": "50×50 체커 배경. 캔버스 이동·확대를 따라가며 블렌드 모드에도 참여합니다", "thumbnail": "현재 항목 썸네일로 설정", "thumbnailTitle": "현재 프레임을 이 항목의 400×400 사용자 지정 썸네일로 설정", - "groupThumbnail": "현재 자산 그룹 썸네일 생성…", - "groupThumbnailTitle": "현재 Spine 자산 그룹을 확인한 후 일괄 생성", - "groupDialogTitle": "현재 자산 그룹 썸네일 생성", + "groupThumbnail": "관련 자산 썸네일 생성", + "groupThumbnailTitle": "관련 Spine 자산을 확인한 후 일괄 생성", + "groupDialogTitle": "관련 자산 썸네일 생성", "groupDialogSummary": "{generate}개를 생성하고 {skip}개를 건너뜁니다.", - "groupDialogNote": "아래에 명시된 항목만 업데이트합니다. 기존 사용자 지정 썸네일이 있는 항목은 항상 건너뜁니다.", + "groupDialogNote": "선택한 관련 자산에만 썸네일을 생성합니다. 이미지와 사용자 지정 썸네일이 있는 자산은 기본적으로 선택하지 않습니다. 후자를 선택하면 기존 썸네일이 교체되며 플러그인에서 자동 복원할 수 없습니다.", "cancel": "취소", "groupConfirm": "생성", "groupWillGenerate": "생성 예정", + "groupNotSelected": "선택하지 않음", "groupSkipCustom": "건너뛰: 사용자 지정 썸네일 있음", "groupUnavailable": "건너뛰: 확인할 수 없음", "groupNoTargets": "현재 자산 그룹에 생성할 수 있는 썸네일이 없습니다.", "groupGenerating": "자산 그룹 썸네일 생성 중 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle에서 썸네일 적용을 확인하지 못했습니다", "groupComplete": "완료: 성공 {success}, 건너뛰 {skip}, 실패 {failed}.", "versionTitle": "Spine 버전", "reloadTitle": "폴더 다시 불러오기", @@ -89,6 +91,8 @@ "loadFailed": "불러오기 실패", "notSpineText": "이 파일은 .atlas.txt 또는 .skel.bytes 형식의 Spine 리소스가 아닙니다.", "truncated256": "\n\n(앞부분 256 KB만 표시)", - "truncated1m": "\n\n(파일이 커서 앞부분 1 MB만 표시)" + "truncated1m": "\n\n(파일이 커서 앞부분 1 MB만 표시)", + "groupWillReplaceCustom": "기존 사용자 지정 썸네일 교체", + "groupCustomNotSelected": "사용자 지정 썸네일 있음(선택 안 함)" } } diff --git a/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json b/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json index 6e0b32b..074ab2a 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json +++ b/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json @@ -20,18 +20,20 @@ "backgroundTitle": "Шахматный фон 50×50: следует за сдвигом и масштабом холста и участвует в режимах смешивания", "thumbnail": "Сделать миниатюрой элемента", "thumbnailTitle": "Установить текущий кадр как пользовательскую миниатюру 400×400 для этого элемента", - "groupThumbnail": "Создать миниатюры для текущей группы…", - "groupThumbnailTitle": "Проверить группу Spine и создать миниатюры пакетно", - "groupDialogTitle": "Создать миниатюры для текущей группы", + "groupThumbnail": "Создать миниатюры для связанных ресурсов", + "groupThumbnailTitle": "Проверить связанные ресурсы Spine и создать миниатюры", + "groupDialogTitle": "Создать миниатюры для связанных ресурсов", "groupDialogSummary": "Будет создано: {generate}; пропущено: {skip}.", - "groupDialogNote": "Будут обновлены только явно указанные ниже элементы. Элементы с пользовательскими миниатюрами всегда пропускаются.", + "groupDialogNote": "Миниатюры будут созданы только для отмеченных связанных ресурсов. Изображения и ресурсы со своими миниатюрами по умолчанию не отмечены. Выбор последних заменит существующую миниатюру, и плагин не сможет восстановить её автоматически.", "cancel": "Отмена", "groupConfirm": "Создать", "groupWillGenerate": "Будет создано", + "groupNotSelected": "Не выбрано", "groupSkipCustom": "Пропущено: есть своя миниатюра", "groupUnavailable": "Пропущено: не удалось проверить", "groupNoTargets": "В текущей группе нет подходящих миниатюр.", "groupGenerating": "Создание миниатюр {current}/{total}…", + "groupApplyNotConfirmed": "Eagle не подтвердил применение миниатюры", "groupComplete": "Готово: {success} успешно, {skip} пропущено, {failed} с ошибкой.", "versionTitle": "Версия Spine", "reloadTitle": "Перезагрузить папку", @@ -89,6 +91,8 @@ "loadFailed": "Не удалось загрузить", "notSpineText": "Этот файл не является ресурсом Spine в формате .atlas.txt или .skel.bytes.", "truncated256": "\n\n(показаны только первые 256 КБ)", - "truncated1m": "\n\n(файл большой, показан только первый 1 МБ)" + "truncated1m": "\n\n(файл большой, показан только первый 1 МБ)", + "groupWillReplaceCustom": "Заменит существующую миниатюру", + "groupCustomNotSelected": "Есть своя миниатюра (не выбрано)" } } diff --git a/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json b/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json index d019130..d9ff0f2 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json +++ b/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json @@ -20,18 +20,22 @@ "backgroundTitle": "50×50 方格背景,随画布移动和缩放,并参与混合模式", "thumbnail": "设为当前素材缩略图", "thumbnailTitle": "将当前帧设为当前素材的 400×400 自定义缩略图", - "groupThumbnail": "为当前资源组生成缩略图…", - "groupThumbnailTitle": "列出当前 Spine 资源组,确认后批量生成缩略图", - "groupDialogTitle": "为当前资源组生成缩略图", + "groupThumbnail": "为关联资源生成缩略图", + "groupThumbnailTitle": "列出当前 Spine 关联资源,确认后批量生成缩略图", + "groupDialogTitle": "为关联资源生成缩略图", "groupDialogSummary": "将生成 {generate} 项,跳过 {skip} 项。", - "groupDialogNote": "只会更新下列明确列出的素材;已有自定义缩略图的素材会自动跳过。", + "groupDialogNote": "只会为勾选的关联资源生成缩略图。图片和已有自定义缩略图的资源默认不勾选;若勾选后者,原缩略图将被替换且插件无法自动恢复。", "cancel": "取消", "groupConfirm": "确认生成", "groupWillGenerate": "将生成", + "groupWillReplaceCustom": "将替换已有自定义缩略图", + "groupCustomNotSelected": "已有自定义缩略图(未选择)", + "groupNotSelected": "未选择", "groupSkipCustom": "跳过:已有自定义缩略图", "groupUnavailable": "跳过:无法验证", "groupNoTargets": "当前资源组没有可生成的缩略图。", "groupGenerating": "正在生成资源组缩略图 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle 未确认缩略图已应用", "groupComplete": "资源组缩略图已完成:成功 {success},跳过 {skip},失败 {failed}。", "versionTitle": "Spine 版本", "reloadTitle": "重新加载目录", diff --git a/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json b/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json index 08395d6..6683cdb 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json +++ b/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json @@ -20,18 +20,22 @@ "backgroundTitle": "50×50 方格背景,隨畫布移動和縮放,並參與混合模式", "thumbnail": "設為目前素材縮圖", "thumbnailTitle": "將目前影格設為目前素材的 400×400 自訂縮圖", - "groupThumbnail": "為目前資源組產生縮圖…", - "groupThumbnailTitle": "列出目前 Spine 資源組,確認後批次產生縮圖", - "groupDialogTitle": "為目前資源組產生縮圖", + "groupThumbnail": "為關聯資源產生縮圖", + "groupThumbnailTitle": "列出目前 Spine 關聯資源,確認後批次產生縮圖", + "groupDialogTitle": "為關聯資源產生縮圖", "groupDialogSummary": "將產生 {generate} 項,跳過 {skip} 項。", - "groupDialogNote": "只會更新下列明確列出的素材;已有自訂縮圖的素材會自動跳過。", + "groupDialogNote": "只會為勾選的關聯資源產生縮圖。圖片和已有自訂縮圖的資源預設不勾選;若勾選後者,原縮圖將被取代且外掛無法自動復原。", "cancel": "取消", "groupConfirm": "確認產生", "groupWillGenerate": "將產生", + "groupWillReplaceCustom": "將取代已有自訂縮圖", + "groupCustomNotSelected": "已有自訂縮圖(未選擇)", + "groupNotSelected": "未選擇", "groupSkipCustom": "跳過:已有自訂縮圖", "groupUnavailable": "跳過:無法驗證", "groupNoTargets": "目前資源組沒有可產生的縮圖。", "groupGenerating": "正在產生資源組縮圖 {current}/{total}…", + "groupApplyNotConfirmed": "Eagle 未確認縮圖已套用", "groupComplete": "資源組縮圖已完成:成功 {success},跳過 {skip},失敗 {failed}。", "versionTitle": "Spine 版本", "reloadTitle": "重新載入目錄", diff --git a/release/UNIVERSAL_SpineViewer/js/spine-group-thumbnails.js b/release/UNIVERSAL_SpineViewer/js/spine-group-thumbnails.js new file mode 100644 index 0000000..822e4b2 --- /dev/null +++ b/release/UNIVERSAL_SpineViewer/js/spine-group-thumbnails.js @@ -0,0 +1,75 @@ +'use strict'; + +const crypto = require('crypto'); +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +function orderCurrentTargetLast(targets, currentSourcePath) { + if (!currentSourcePath) return [...targets]; + const current = path.resolve(currentSourcePath); + return [...targets].sort((left, right) => { + const leftIsCurrent = path.resolve(left.sourcePath) === current; + const rightIsCurrent = path.resolve(right.sourcePath) === current; + return Number(leftIsCurrent) - Number(rightIsCurrent); + }); +} + +/** + * Apply one rendered frame to explicitly selected Eagle items. + * Each item gets an independent temporary file because Eagle may consume or + * defer reading the file passed to setCustomThumbnail. + */ +async function applyThumbnailTargets(options) { + const targets = options.targets || []; + const settleDelayMs = options.settleDelayMs === undefined ? 800 : options.settleDelayMs; + const cleanupDelayMs = options.cleanupDelayMs === undefined ? 1200 : options.cleanupDelayMs; + const retryAttempts = options.retryAttempts === undefined ? 3 : options.retryAttempts; + const delay = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve(); + const tempPaths = []; + let success = 0; + let skipped = Number(options.initialSkipped) || 0; + let failed = 0; + for (let index = 0; index < targets.length; index++) { + if (options.onProgress) options.onProgress(index + 1, targets.length); + let itemTempPath = null; + try { + const target = targets[index]; + const fresh = await options.getItem(target.sourcePath); + if (fresh.data.customThumbnail === true && target.allowOverwrite !== true) { skipped++; continue; } + itemTempPath = path.join(os.tmpdir(), 'spineviewer-group-' + fresh.id + '-' + crypto.randomBytes(12).toString('hex') + options.rendered.extension); + fs.writeFileSync(itemTempPath, options.rendered.buffer); + tempPaths.push(itemTempPath); + let applied = false; + let lastError = null; + for (let attempt = 0; attempt < retryAttempts && !applied; attempt++) { + try { + const accepted = await options.setThumbnail(fresh.id, itemTempPath); + if (accepted !== true) throw new Error(options.notConfirmedMessage || 'Thumbnail update was rejected'); + applied = await options.waitForApplied(target.sourcePath); + if (!applied) throw new Error(options.notConfirmedMessage || 'Thumbnail update was not confirmed'); + } catch (error) { + lastError = error; + if (attempt < retryAttempts - 1) await delay(settleDelayMs); + } + } + if (!applied) throw lastError || new Error(options.notConfirmedMessage || 'Thumbnail update was not confirmed'); + // The local HTTP API can resolve before Eagle has finished consuming the + // supplied file. Keep every file alive and serialize requests with a short + // settling interval so a later request cannot replace an earlier queued job. + await delay(settleDelayMs); + success++; + if (options.onSuccess) options.onSuccess(fresh); + } catch (error) { + failed++; + if (options.onError) options.onError(error); + } finally { /* temporary inputs are retained until the whole queue settles */ } + } + await delay(cleanupDelayMs); + for (const tempPath of tempPaths) { + try { if (fs.existsSync(tempPath)) fs.unlinkSync(tempPath); } catch (e) { /* ignore */ } + } + return { success, skipped, failed }; +} + +module.exports = { applyThumbnailTargets, orderCurrentTargetLast }; diff --git a/release/UNIVERSAL_SpineViewer/viewer/spine.css b/release/UNIVERSAL_SpineViewer/viewer/spine.css index 6bc7685..08b58bc 100644 --- a/release/UNIVERSAL_SpineViewer/viewer/spine.css +++ b/release/UNIVERSAL_SpineViewer/viewer/spine.css @@ -100,6 +100,7 @@ border-bottom: 1px solid var(--border); } .thumb-dialog-row:last-child { border-bottom: 0; } + .thumb-dialog-check { width: 17px; height: 17px; margin: 0; flex: none; accent-color: var(--accent); } .thumb-dialog-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .thumb-dialog-state { flex: none; color: var(--accent); font-size: 12px; } .thumb-dialog-row.skipped .thumb-dialog-name, diff --git a/release/UNIVERSAL_SpineViewer/viewer/spine.html b/release/UNIVERSAL_SpineViewer/viewer/spine.html index 232015c..7bcec35 100644 --- a/release/UNIVERSAL_SpineViewer/viewer/spine.html +++ b/release/UNIVERSAL_SpineViewer/viewer/spine.html @@ -25,7 +25,7 @@ 背景

- + @@ -61,10 +61,10 @@