diff --git a/AvatarExplorer.Core/Data/Localization/en-US.json b/AvatarExplorer.Core/Data/Localization/en-US.json
index 23236781..1136a077 100644
--- a/AvatarExplorer.Core/Data/Localization/en-US.json
+++ b/AvatarExplorer.Core/Data/Localization/en-US.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "Rename tag \"{0}\" to \"{1}\"?",
"Dialog.Confirmation.RemoveTag": "Remove tag \"{0}\"?\n※Removing will delete this tag from all items.",
"Dialog.Confirmation.RenameTagAlreadyExist": "Tag \"{0}\" already exists. If you continue, it will be recognized as the same tag. Do you want to continue?",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "Set Booth ID for this temporary avatar?\n\n※Setting a Booth ID enables linking when adding items via ID search or from Booth.",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "A temporary avatar \"{0}\" with a matching Booth ID was found.\nWould you like to link this temporary avatar as a permanent item?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "Replace the supported avatars of items containing avatars in the common avatar group with the common avatar group?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "Replace the supported avatars of items that have the common avatar group set as supported avatars with individual avatars?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "New Temporary Avatar Name",
"Dialog.Title.NewCustomCategoryName": "New Custom Category Name",
"Dialog.Title.AddUrl": "Enter Download URL",
+ "Dialog.Title.SetBoothIdForTempAvatar": "Set Booth ID for Temporary Avatar (link accepted)",
"Dialog.SelectSaveFolderPath": "Please select the folder to save to",
"Dialog.SelectFolderPath": "Please select a folder",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "Open PDF Viewer",
"ContextMenu.BulkImportPreset.RemovePreset": "Remove Preset",
"ContextMenu.TempAvatar.EditTempAvatarName": "Edit Temporary Avatar Name",
+ "ContextMenu.TempAvatar.EditBoothId": "Edit Booth ID",
"ContextMenu.TempAvatar.ResolveTempAvatar": "Link to Permanent Item",
"ContextMenu.TempAvatar.RemoveTempAvatar": "Remove Temporary Avatar",
"ContextMenu.ItemCategory.EditCustomCategoryName": "Edit Custom Category Name",
@@ -202,6 +206,8 @@
"Success.ShowItem": "Item has been unhidden",
"Success.EnableIndirectCommonAvatarCheck": "Indirect common avatar check has been enabled",
"Success.SkipIndirectCommonAvatarCheck": "Indirect common avatar check has been skipped",
+ "Success.CreateTempAvatar": "Temporary avatar created",
+ "Success.ResolveTempAvatar": "Temporary avatar linked as a permanent item",
"VariationUpdate.UpdateAvailable": "Item updates are available",
"VariationUpdate.NoUpdatesAvailable": "No updates available",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "In administrator mode, some operations like drag & drop may not be available.",
"Warning.FetchAllItemThumbnailsCancelled": "Bulk thumbnail fetch was cancelled. Success: {0} / Failed: {1} / Total: {2}",
"Warning.FetchAllVariationHashesCancelled": "Bulk hash fetch was cancelled. Success: {0} / Failed: {1} / Total: {2}",
+ "Warning.InvalidBoothId": "Invalid Booth ID. The Booth ID has been cleared.",
"Error.Default": "Error",
"Error.Nothing": "No items found!",
diff --git a/AvatarExplorer.Core/Data/Localization/es-ES.json b/AvatarExplorer.Core/Data/Localization/es-ES.json
index 36fa6f4f..e1ed5e9a 100644
--- a/AvatarExplorer.Core/Data/Localization/es-ES.json
+++ b/AvatarExplorer.Core/Data/Localization/es-ES.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "¿Renombrar la etiqueta «{0}» a «{1}»?",
"Dialog.Confirmation.RemoveTag": "¿Eliminar la etiqueta «{0}»?\n※Al eliminar, se eliminará esta etiqueta de todos los elementos.",
"Dialog.Confirmation.RenameTagAlreadyExist": "La etiqueta \"{0}\" ya existe. Si continúas, se reconocerá como la misma etiqueta. ¿Deseas continuar?",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "¿Establecer Booth ID para este avatar temporal?\n\n※Establecer un Booth ID permite la vinculación al agregar elementos mediante búsqueda de ID o desde Booth.",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "Se encontró un avatar temporal \"{0}\" con un Booth ID coincidente.\n¿Desea vincular este avatar temporal como un elemento permanente?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "¿Reemplazar los avatares compatibles de los elementos que contienen avatares en el grupo de avatares comunes por el grupo de avatares comunes?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "¿Reemplazar los avatares compatibles de los elementos que tienen el grupo de avatares comunes configurado como avatares compatibles por avatares individuales?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "Nuevo nombre de avatar temporal",
"Dialog.Title.NewCustomCategoryName": "Nuevo nombre de categoría personalizada",
"Dialog.Title.AddUrl": "Introducir URL de descarga",
+ "Dialog.Title.SetBoothIdForTempAvatar": "Establecer Booth ID para Avatar Temporal (también acepta enlace)",
"Dialog.SelectSaveFolderPath": "Selecciona la carpeta donde guardar",
"Dialog.SelectFolderPath": "Selecciona una carpeta",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "Abrir con PDF Viewer",
"ContextMenu.BulkImportPreset.RemovePreset": "Eliminar ajuste preestablecido",
"ContextMenu.TempAvatar.EditTempAvatarName": "Editar nombre de avatar temporal",
+ "ContextMenu.TempAvatar.EditBoothId": "Editar Booth ID",
"ContextMenu.TempAvatar.ResolveTempAvatar": "Vincular al elemento permanente",
"ContextMenu.TempAvatar.RemoveTempAvatar": "Eliminar avatar temporal",
"ContextMenu.ItemCategory.EditCustomCategoryName": "Editar nombre de categoría personalizada",
@@ -202,6 +206,8 @@
"Success.ShowItem": "Elemento visible",
"Success.EnableIndirectCommonAvatarCheck": "Comprobación indirecta de avatar común habilitada",
"Success.SkipIndirectCommonAvatarCheck": "Se omitió la comprobación indirecta de avatar común",
+ "Success.CreateTempAvatar": "Avatar temporal creado",
+ "Success.ResolveTempAvatar": "Avatar temporal vinculado como elemento permanente",
"VariationUpdate.UpdateAvailable": "Hay actualizaciones disponibles para el elemento",
"VariationUpdate.NoUpdatesAvailable": "No hay actualizaciones disponibles",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "En modo administrador, algunas operaciones como arrastrar y soltar pueden no estar disponibles.",
"Warning.FetchAllItemThumbnailsCancelled": "La obtención masiva de miniaturas se canceló. Correctos: {0} / Fallidos: {1} / Total: {2}",
"Warning.FetchAllVariationHashesCancelled": "La obtención masiva de hashes se canceló. Correctos: {0} / Fallidos: {1} / Total: {2}",
+ "Warning.InvalidBoothId": "Booth ID no válido. Se ha borrado el Booth ID.",
"Error.Default": "Error",
"Error.Nothing": "¡No se encontraron elementos!",
diff --git a/AvatarExplorer.Core/Data/Localization/fr-FR.json b/AvatarExplorer.Core/Data/Localization/fr-FR.json
index 2a45c3ff..c6929848 100644
--- a/AvatarExplorer.Core/Data/Localization/fr-FR.json
+++ b/AvatarExplorer.Core/Data/Localization/fr-FR.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "Renommer le tag « {0} » en « {1} » ?",
"Dialog.Confirmation.Remove": "Supprimer le tag « {0} » ?\n※La suppression entraînera la suppression de ce tag de tous les éléments.",
"Dialog.Confirmation.RemoveTag": "Supprimer le tag « {0} » ?\n※La suppression entraînera la suppression de ce tag de tous les éléments.",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "Définir l'ID Booth pour cet avatar temporaire ?\n\n※Définir un ID Booth permet la liaison lors de l'ajout d'éléments par recherche ID ou depuis Booth.",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "Un avatar temporaire « {0} » avec un ID Booth correspondant a été trouvé.\nVoulez-vous lier cet avatar temporaire en tant qu'élément permanent ?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "Remplacer les avatars pris en charge des éléments contenant des avatars du groupe d'avatars communs par le groupe d'avatars communs ?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "Remplacer les avatars pris en charge des éléments dont les avatars pris en charge sont définis sur le groupe d'avatars communs par des avatars individuels ?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "Nouveau nom d'avatar temporaire",
"Dialog.Title.NewCustomCategoryName": "Nouveau nom de catégorie personnalisée",
"Dialog.Title.AddUrl": "Entrez l'URL de téléchargement",
+ "Dialog.Title.SetBoothIdForTempAvatar": "Définir l'ID Booth pour l'avatar temporaire (lien accepté)",
"Dialog.SelectSaveFolderPath": "Veuillez sélectionner le dossier d'enregistrement",
"Dialog.SelectFolderPath": "Veuillez sélectionner un dossier",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "Ouvrir avec PDF Viewer",
"ContextMenu.BulkImportPreset.RemovePreset": "Supprimer le préréglage",
"ContextMenu.TempAvatar.EditTempAvatarName": "Modifier le nom de l'avatar temporaire",
+ "ContextMenu.TempAvatar.EditBoothId": "Modifier l'ID Booth",
"ContextMenu.TempAvatar.ResolveTempAvatar": "Lier à l'élément permanent",
"ContextMenu.TempAvatar.RemoveTempAvatar": "Supprimer l'avatar temporaire",
"ContextMenu.ItemCategory.EditCustomCategoryName": "Modifier le nom de la catégorie personnalisée",
@@ -202,6 +206,8 @@
"Success.ShowItem": "Élément affiché",
"Success.EnableIndirectCommonAvatarCheck": "La vérification indirecte de l'avatar commun a été activée",
"Success.SkipIndirectCommonAvatarCheck": "La vérification indirecte de l'avatar commun a été ignorée",
+ "Success.CreateTempAvatar": "Avatar temporaire créé",
+ "Success.ResolveTempAvatar": "Avatar temporaire lié en tant qu'élément permanent",
"VariationUpdate.UpdateAvailable": "Des mises à jour d'éléments sont disponibles",
"VariationUpdate.NoUpdatesAvailable": "Aucune mise à jour disponible",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "En mode administrateur, certaines opérations comme le glisser-déposer peuvent ne pas être disponibles.",
"Warning.FetchAllItemThumbnailsCancelled": "La récupération groupée des vignettes a été annulée. Réussies : {0} / Échouées : {1} / Total : {2}",
"Warning.FetchAllVariationHashesCancelled": "La récupération groupée des hachages a été annulée. Réussies : {0} / Échouées : {1} / Total : {2}",
+ "Warning.InvalidBoothId": "ID Booth invalide. L'ID Booth a été effacé.",
"Error.Default": "Erreur",
"Error.Nothing": "Aucun élément trouvé !",
diff --git a/AvatarExplorer.Core/Data/Localization/ja-JP.json b/AvatarExplorer.Core/Data/Localization/ja-JP.json
index 1a9636a5..1970c8e3 100644
--- a/AvatarExplorer.Core/Data/Localization/ja-JP.json
+++ b/AvatarExplorer.Core/Data/Localization/ja-JP.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "タグ「{0}」を「{1}」に変更しますか?",
"Dialog.Confirmation.RemoveTag": "タグ「{0}」を削除しますか?\n※削除すると、全てのアイテムからこのタグが削除されます。",
"Dialog.Confirmation.RenameTagAlreadyExist": "タグ「{0}」は既に存在します。続行すると、同じタグとして認識されるようになります。続行しますか?",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "仮アバターにBooth IDを設定しますか?\n\n※Booth IDを設定すると、ID検索や該当アイテム追加時に自動で紐付けされるようになります。",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "Booth IDが一致する仮アバター「{0}」が見つかりました。\nこの仮アバターを正式アイテムとして紐付けますか?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "共通素体グループ内のアバターが含まれているアイテムの対応アバターを共通素体グループに置き換えますか?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "共通素体グループが対応アバターとして設定されているアイテムの対応アバターを、個別のアバターに置き換えますか?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "新しい仮アバター名",
"Dialog.Title.NewCustomCategoryName": "新しいカスタムカテゴリ名",
"Dialog.Title.AddUrl": "ダウンロードURLを入力",
+ "Dialog.Title.SetBoothIdForTempAvatar": "仮アバターのBooth IDを設定(リンクでも可)",
"Dialog.SelectSaveFolderPath": "保存先フォルダを選択してください",
"Dialog.SelectFolderPath": "フォルダを選択してください",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "PDF Viewerで開く",
"ContextMenu.BulkImportPreset.RemovePreset": "プリセットを削除する",
"ContextMenu.TempAvatar.EditTempAvatarName": "仮アバター名を編集する",
+ "ContextMenu.TempAvatar.EditBoothId": "Booth IDを編集する",
"ContextMenu.TempAvatar.ResolveTempAvatar": "正式なアイテムと紐付ける",
"ContextMenu.TempAvatar.RemoveTempAvatar": "仮アバターを削除する",
"ContextMenu.ItemCategory.EditCustomCategoryName": "カスタムカテゴリ名を編集する",
@@ -202,6 +206,8 @@
"Success.ShowItem": "アイテムを非表示から解除しました",
"Success.EnableIndirectCommonAvatarCheck": "間接的な共通素体チェックを有効にしました",
"Success.SkipIndirectCommonAvatarCheck": "間接的な共通素体チェックをスキップするように設定しました",
+ "Success.CreateTempAvatar": "仮アバターを作成しました",
+ "Success.ResolveTempAvatar": "仮アバターを正式アイテムとして紐付けました",
"VariationUpdate.UpdateAvailable": "アイテムの更新が利用可能です",
"VariationUpdate.NoUpdatesAvailable": "更新はありませんでした",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "管理者モードでは、ドラッグ&ドロップなど一部の操作が利用できなくなります。",
"Warning.FetchAllItemThumbnailsCancelled": "サムネイル一括取得をキャンセルしました。成功: {0}件 / 失敗: {1}件 / 合計: {2}件",
"Warning.FetchAllVariationHashesCancelled": "ハッシュ一括取得をキャンセルしました。成功: {0}件 / 失敗: {1}件 / 合計: {2}件",
+ "Warning.InvalidBoothId": "無効なBooth IDだったため、空のBooth IDが設定されました。",
"Error.Default": "エラー",
"Error.Nothing": "アイテムが見つからないよっ!",
diff --git a/AvatarExplorer.Core/Data/Localization/ko-KR.json b/AvatarExplorer.Core/Data/Localization/ko-KR.json
index 3d655013..1d2b8865 100644
--- a/AvatarExplorer.Core/Data/Localization/ko-KR.json
+++ b/AvatarExplorer.Core/Data/Localization/ko-KR.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "태그 \"{0}\"을(를) \"{1}\"(으)로 변경하시겠습니까?",
"Dialog.Confirmation.RemoveTag": "태그 \"{0}\"을(를) 삭제하시겠습니까?\n※삭제하면 모든 아이템에서 이 태그가 제거됩니다.",
"Dialog.Confirmation.RenameTagAlreadyExist": "태그 \"{0}\"은(는) 이미 존재합니다. 계속하면 같은 태그로 인식됩니다. 계속하시겠습니까?",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "이 임시 아바타에 Booth ID를 설정하시겠습니까?\n\n※Booth ID를 설정하면 ID 검색이나 Booth에서 항목 추가 시 연결에 이용됩니다.",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "Booth ID가 일치하는 임시 아바타 \"{0}\"를 찾았습니다.\n이 임시 아바타를 정식 아이템으로 연결하시겠습니까?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "공통 바디 그룹에 포함된 아바타가 들어 있는 아이템의 대응 아바타를 공통 바디 그룹으로 바꾸시겠습니까?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "공통 바디 그룹이 대응 아바타로 설정된 아이템의 대응 아바타를 개별 아바타로 바꾸시겠습니까?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "새 임시 아바타 이름",
"Dialog.Title.NewCustomCategoryName": "새 사용자 지정 카테고리 이름",
"Dialog.Title.AddUrl": "다운로드 URL 입력",
+ "Dialog.Title.SetBoothIdForTempAvatar": "임시 아바타의 Booth ID 설정 (링크 입력 가능)",
"Dialog.SelectSaveFolderPath": "저장할 폴더를 선택해 주세요",
"Dialog.SelectFolderPath": "폴더를 선택해 주세요",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "PDF Viewer로 열기",
"ContextMenu.BulkImportPreset.RemovePreset": "프리셋 삭제",
"ContextMenu.TempAvatar.EditTempAvatarName": "임시 아바타 이름 편집",
+ "ContextMenu.TempAvatar.EditBoothId": "Booth ID 편집",
"ContextMenu.TempAvatar.ResolveTempAvatar": "정식 아이템과 연결",
"ContextMenu.TempAvatar.RemoveTempAvatar": "임시 아바타 삭제",
"ContextMenu.ItemCategory.EditCustomCategoryName": "사용자 지정 카테고리 이름 편집",
@@ -202,6 +206,8 @@
"Success.ShowItem": "아이템이 표시되었습니다",
"Success.EnableIndirectCommonAvatarCheck": "간접적인 공통 아바타 확인이 활성화되었습니다",
"Success.SkipIndirectCommonAvatarCheck": "간접적인 공통 아바타 확인을 건너뛰도록 설정되었습니다",
+ "Success.CreateTempAvatar": "임시 아바타가 생성되었습니다",
+ "Success.ResolveTempAvatar": "임시 아바타가 정식 아이템으로 연결되었습니다",
"VariationUpdate.UpdateAvailable": "아이템 업데이트를 사용할 수 있습니다",
"VariationUpdate.NoUpdatesAvailable": "사용 가능한 업데이트 없음",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "관리자 모드에서는 드래그 앤 드롭 등 일부 작업을 사용할 수 없습니다.",
"Warning.FetchAllItemThumbnailsCancelled": "썸네일 일괄 가져오기를 취소했습니다. 성공: {0}개 / 실패: {1}개 / 전체: {2}개",
"Warning.FetchAllVariationHashesCancelled": "해시 일괄 가져오기를 취소했습니다. 성공: {0}개 / 실패: {1}개 / 전체: {2}개",
+ "Warning.InvalidBoothId": "Booth ID가 유효하지 않습니다. Booth ID가 초기화되었습니다.",
"Error.Default": "오류",
"Error.Nothing": "아이템을 찾을 수 없어요!",
diff --git a/AvatarExplorer.Core/Data/Localization/zh-CN.json b/AvatarExplorer.Core/Data/Localization/zh-CN.json
index f74a41b9..d8303c5b 100644
--- a/AvatarExplorer.Core/Data/Localization/zh-CN.json
+++ b/AvatarExplorer.Core/Data/Localization/zh-CN.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "要将标签「{0}」更改为「{1}」吗?",
"Dialog.Confirmation.RemoveTag": "要删除标签「{0}」吗?\n※删除后,该标签将从所有项目中移除。",
"Dialog.Confirmation.RenameTagAlreadyExist": "标签「{0}」已存在。继续的话,将被识别为同一标签。要继续吗?",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "要为此临时头像设置 Booth ID 吗?\n\n※设置 Booth ID 后,可通过 ID 搜索或从 Booth 添加项目时进行关联。",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "找到了 Booth ID 一致的临时头像「{0}」。\n要将此临时头像关联为正式项目吗?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "要将包含共用基体组头像的项目的支持头像替换为共用基体组吗?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "要将将共用基体组设置为支持头像的项目的支持头像替换为单独头像吗?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "新建临时头像名称",
"Dialog.Title.NewCustomCategoryName": "新建自定义类别名称",
"Dialog.Title.AddUrl": "输入下载 URL",
+ "Dialog.Title.SetBoothIdForTempAvatar": "设置临时头像的 Booth ID(也可输入链接)",
"Dialog.SelectSaveFolderPath": "请选择要保存的文件夹",
"Dialog.SelectFolderPath": "请选择文件夹",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "使用 PDF Viewer 打开",
"ContextMenu.BulkImportPreset.RemovePreset": "删除预设",
"ContextMenu.TempAvatar.EditTempAvatarName": "编辑临时头像名称",
+ "ContextMenu.TempAvatar.EditBoothId": "编辑 Booth ID",
"ContextMenu.TempAvatar.ResolveTempAvatar": "关联到正式项目",
"ContextMenu.TempAvatar.RemoveTempAvatar": "删除临时头像",
"ContextMenu.ItemCategory.EditCustomCategoryName": "编辑自定义类别名称",
@@ -202,6 +206,8 @@
"Success.ShowItem": "项目已取消隐藏",
"Success.EnableIndirectCommonAvatarCheck": "间接公共头像检查已启用",
"Success.SkipIndirectCommonAvatarCheck": "已设置跳过间接公共头像检查",
+ "Success.CreateTempAvatar": "临时头像已创建",
+ "Success.ResolveTempAvatar": "临时头像已关联为正式项目",
"VariationUpdate.UpdateAvailable": "有可用的项目更新",
"VariationUpdate.NoUpdatesAvailable": "没有更新",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "在管理员模式下,拖放等部分操作可能不可用。",
"Warning.FetchAllItemThumbnailsCancelled": "批量获取缩略图已取消。成功: {0} 个 / 失败: {1} 个 / 总计: {2} 个",
"Warning.FetchAllVariationHashesCancelled": "批量获取哈希已取消。成功: {0} 个 / 失败: {1} 个 / 总计: {2} 个",
+ "Warning.InvalidBoothId": "Booth ID 无效,已清除 Booth ID。",
"Error.Default": "错误",
"Error.Nothing": "没有找到项目!",
diff --git a/AvatarExplorer.Core/Data/Localization/zh-TW.json b/AvatarExplorer.Core/Data/Localization/zh-TW.json
index f5e8a03e..b2db35cb 100644
--- a/AvatarExplorer.Core/Data/Localization/zh-TW.json
+++ b/AvatarExplorer.Core/Data/Localization/zh-TW.json
@@ -72,6 +72,8 @@
"Dialog.Confirmation.RenameTag": "要將標籤「{0}」變更為「{1}」嗎?",
"Dialog.Confirmation.RemoveTag": "要刪除標籤「{0}」嗎?\n※刪除後,該標籤將從所有項目中移除。",
"Dialog.Confirmation.RenameTagAlreadyExist": "標籤「{0}」已存在。繼續的話,將被識別為同一標籤。要繼續嗎?",
+ "Dialog.Confirmation.SetBoothIdForTempAvatar": "要為此暫時頭像設定 Booth ID 嗎?\n\n※設定 Booth ID 後,可透過 ID 搜尋或從 Booth 新增項目時進行連結。",
+ "Dialog.Confirmation.ResolveSameBoothIdTempAvatar": "找到了 Booth ID 一致的暫時頭像「{0}」。\n要將此暫時頭像連結為正式項目嗎?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup": "要將包含共用基體群組頭像的項目的支援頭像替換為共用基體群組嗎?",
"Dialog.Confirmation.EditCommonAvatars.ReplaceGroupToAvatars": "要將將共用基體群組設定為支援頭像的項目的支援頭像替換為個別頭像嗎?",
@@ -87,6 +89,7 @@
"Dialog.Title.NewTempAvatarName": "新暫時頭像名稱",
"Dialog.Title.NewCustomCategoryName": "新自訂類別名稱",
"Dialog.Title.AddUrl": "輸入下載 URL",
+ "Dialog.Title.SetBoothIdForTempAvatar": "設定暫時頭像的 Booth ID(也可輸入連結)",
"Dialog.SelectSaveFolderPath": "請選擇要儲存的資料夾",
"Dialog.SelectFolderPath": "請選擇資料夾",
@@ -160,6 +163,7 @@
"ContextMenu.ItemFile.OpenPdfViewer": "使用 PDF Viewer 開啟",
"ContextMenu.BulkImportPreset.RemovePreset": "刪除預設",
"ContextMenu.TempAvatar.EditTempAvatarName": "編輯暫時頭像名稱",
+ "ContextMenu.TempAvatar.EditBoothId": "編輯 Booth ID",
"ContextMenu.TempAvatar.ResolveTempAvatar": "連結到正式項目",
"ContextMenu.TempAvatar.RemoveTempAvatar": "刪除暫時頭像",
"ContextMenu.ItemCategory.EditCustomCategoryName": "編輯自訂類別名稱",
@@ -202,6 +206,8 @@
"Success.ShowItem": "項目已取消隱藏",
"Success.EnableIndirectCommonAvatarCheck": "間接公共頭像檢查已啟用",
"Success.SkipIndirectCommonAvatarCheck": "已設定跳過間接公共頭像檢查",
+ "Success.CreateTempAvatar": "暫時頭像已建立",
+ "Success.ResolveTempAvatar": "暫時頭像已連結為正式項目",
"VariationUpdate.UpdateAvailable": "有可用的項目更新",
"VariationUpdate.NoUpdatesAvailable": "沒有更新",
@@ -215,6 +221,7 @@
"Warning.RunningInAdministratorMode": "在管理員模式下,拖放等部分操作可能無法使用。",
"Warning.FetchAllItemThumbnailsCancelled": "批次取得縮圖已取消。成功: {0} 個 / 失敗: {1} 個 / 總計: {2} 個",
"Warning.FetchAllVariationHashesCancelled": "批次取得雜湊已取消。成功: {0} 個 / 失敗: {1} 個 / 總計: {2} 個",
+ "Warning.InvalidBoothId": "Booth ID 無效,已清除 Booth ID。",
"Error.Default": "錯誤",
"Error.Nothing": "找不到項目!",
diff --git a/AvatarExplorer.Core/Localization/LocalizationKeys.g.cs b/AvatarExplorer.Core/Localization/LocalizationKeys.g.cs
index f3d88395..ecb1820c 100644
--- a/AvatarExplorer.Core/Localization/LocalizationKeys.g.cs
+++ b/AvatarExplorer.Core/Localization/LocalizationKeys.g.cs
@@ -128,6 +128,8 @@ public static class Confirmation
public const string RenameTag = "Dialog.Confirmation.RenameTag";
public const string RemoveTag = "Dialog.Confirmation.RemoveTag";
public const string RenameTagAlreadyExist = "Dialog.Confirmation.RenameTagAlreadyExist";
+ public const string SetBoothIdForTempAvatar = "Dialog.Confirmation.SetBoothIdForTempAvatar";
+ public const string ResolveSameBoothIdTempAvatar = "Dialog.Confirmation.ResolveSameBoothIdTempAvatar";
public static class EditCommonAvatars
{
public const string ReplaceAvatarsToGroup = "Dialog.Confirmation.EditCommonAvatars.ReplaceAvatarsToGroup";
@@ -146,6 +148,7 @@ public static class Title
public const string NewTempAvatarName = "Dialog.Title.NewTempAvatarName";
public const string NewCustomCategoryName = "Dialog.Title.NewCustomCategoryName";
public const string AddUrl = "Dialog.Title.AddUrl";
+ public const string SetBoothIdForTempAvatar = "Dialog.Title.SetBoothIdForTempAvatar";
}
public const string SelectSaveFolderPath = "Dialog.SelectSaveFolderPath";
public const string SelectFolderPath = "Dialog.SelectFolderPath";
@@ -280,6 +283,7 @@ public static class BulkImportPreset
public static class TempAvatar
{
public const string EditTempAvatarName = "ContextMenu.TempAvatar.EditTempAvatarName";
+ public const string EditBoothId = "ContextMenu.TempAvatar.EditBoothId";
public const string ResolveTempAvatar = "ContextMenu.TempAvatar.ResolveTempAvatar";
public const string RemoveTempAvatar = "ContextMenu.TempAvatar.RemoveTempAvatar";
}
@@ -330,6 +334,8 @@ public static class Success
public const string ShowItem = "Success.ShowItem";
public const string EnableIndirectCommonAvatarCheck = "Success.EnableIndirectCommonAvatarCheck";
public const string SkipIndirectCommonAvatarCheck = "Success.SkipIndirectCommonAvatarCheck";
+ public const string CreateTempAvatar = "Success.CreateTempAvatar";
+ public const string ResolveTempAvatar = "Success.ResolveTempAvatar";
}
public static class VariationUpdate
{
@@ -347,6 +353,7 @@ public static class Warning
public const string RunningInAdministratorMode = "Warning.RunningInAdministratorMode";
public const string FetchAllItemThumbnailsCancelled = "Warning.FetchAllItemThumbnailsCancelled";
public const string FetchAllVariationHashesCancelled = "Warning.FetchAllVariationHashesCancelled";
+ public const string InvalidBoothId = "Warning.InvalidBoothId";
}
public static class Error
{
diff --git a/AvatarExplorer.Core/Models/Items/TempAvatar.cs b/AvatarExplorer.Core/Models/Items/TempAvatar.cs
index 6b5ebd32..fa6d08a4 100644
--- a/AvatarExplorer.Core/Models/Items/TempAvatar.cs
+++ b/AvatarExplorer.Core/Models/Items/TempAvatar.cs
@@ -6,14 +6,22 @@ namespace AvatarExplorer.Core.Models.Items;
///
/// まだ正式に登録されていないアバターを一時的に識別するための「仮アバター」を表すモデルクラスです。後で正式なアバターに「解決(Resolve)」できます。
///
-public class TempAvatar(string avatarName) : AbstractDatabaseItem, IIdentifiable
+public class TempAvatar(string avatarName, int boothId = -1) : AbstractDatabaseItem, IIdentifiable
{
/// 仮アバターの名前です。
- [JsonInclude] public string AvatarName { get; private set; } = avatarName;
+ [JsonInclude] public string AvatarName { get; private set; } = avatarName;
+
+ /// 仮アバターのBoothIdです。未設定の場合は -1 です。
+ [JsonInclude] public int BoothId { get; set; } = boothId;
+
/// 仮アバター名を更新します。
/// 新しいアバター名。
public void UpdateAvatarName(string newName) => AvatarName = newName;
+ /// 仮アバターのBoothIdを更新します。
+ /// 新しいBoothId。
+ public void UpdateBoothId(int newBoothId) => BoothId = newBoothId;
+
/// この仮アバターを一意に識別する識別子("tempavatar:" + Id)です。
[JsonIgnore] public string Identifier => "tempavatar:" + Id;
}
diff --git a/AvatarExplorer.Core/Models/System/TempAvatarSearchIndex.cs b/AvatarExplorer.Core/Models/System/TempAvatarSearchIndex.cs
index 33b06064..91ef76dd 100644
--- a/AvatarExplorer.Core/Models/System/TempAvatarSearchIndex.cs
+++ b/AvatarExplorer.Core/Models/System/TempAvatarSearchIndex.cs
@@ -14,6 +14,11 @@ public record TempAvatarSearchIndex : ISearchIndex
///
public required string AvatarName { get; init; }
+ ///
+ /// 仮アバターのBooth 商品 ID(文字列)。
+ ///
+ public required string BoothId { get; init; }
+
///
/// フリーワード検索用文字列(アバター名の小文字表現)。
///
@@ -46,6 +51,7 @@ private string[] GetTargets(string? field)
return field?.ToLowerInvariant() switch
{
"title" => [AvatarName],
+ "boothid" or "booth" => [BoothId],
null => [FreeWord],
_ => []
};
@@ -58,10 +64,16 @@ private string[] GetTargets(string? field)
/// 構築された TempAvatarSearchIndex。
public static TempAvatarSearchIndex Build(TempAvatar tempAvatar)
{
+ var freeWord = string.Join("\n",
+ tempAvatar.AvatarName,
+ tempAvatar.BoothId.ToString()
+ ).ToLowerInvariant();
+
return new TempAvatarSearchIndex
{
AvatarName = tempAvatar.AvatarName,
- FreeWord = tempAvatar.AvatarName.ToLowerInvariant()
+ BoothId = tempAvatar.BoothId.ToString(),
+ FreeWord = freeWord
};
}
}
diff --git a/AvatarExplorer.Core/Services/System/BoothService.cs b/AvatarExplorer.Core/Services/System/BoothService.cs
index b82ed1f6..036e4732 100644
--- a/AvatarExplorer.Core/Services/System/BoothService.cs
+++ b/AvatarExplorer.Core/Services/System/BoothService.cs
@@ -5,6 +5,7 @@
using AvatarExplorer.Core.Models.Items;
using AvatarExplorer.Core.Services.IO;
using AvatarExplorer.Core.Services.Network;
+using AvatarExplorer.Core.Utils;
using ErrorOr;
namespace AvatarExplorer.Core.Services.System;
@@ -75,7 +76,7 @@ public static async Task> Fetch(string boothUrl, bool waitCoo
if (!waitCooldown && IsApiCooldownNow) return Error.Failure(description: "Booth API Cooldown Error.");
else await WaitForApiCooldownAsync();
- var boothId = boothUrl.Split('/')[^1];
+ var boothId = BoothUtils.ExtractBoothIdFromUrl(boothUrl);
_lastBoothApiGetTime = DateTime.Now;
diff --git a/AvatarExplorer.Core/Services/System/Repositories/TempAvatarRepository.cs b/AvatarExplorer.Core/Services/System/Repositories/TempAvatarRepository.cs
index 0ac4938c..dbfd210b 100644
--- a/AvatarExplorer.Core/Services/System/Repositories/TempAvatarRepository.cs
+++ b/AvatarExplorer.Core/Services/System/Repositories/TempAvatarRepository.cs
@@ -23,9 +23,10 @@ public override void Load()
/// 指定した名前で新しい仮アバターを作成し、データベースに保存します。
/// 作成する仮アバターの名前。
- public void Create(string avatarName)
+ /// 作成する仮アバターのBoothId。未設定の場合は -1。
+ public void Create(string avatarName, int boothId = -1)
{
- Add(new(avatarName));
+ Add(new(avatarName, boothId));
}
/// 指定した仮アバターの名前を変更します。
@@ -40,4 +41,17 @@ public void RenameAvatar(string identifier, string newName)
Save();
InvokeUpdated();
}
+
+ /// 指定した仮アバターのBoothIdを変更します。
+ /// 対象の仮アバターのIdentifier。
+ /// 変更後のBoothId。
+ public void UpdateBoothId(string identifier, int newBoothId)
+ {
+ var avatar = Get(identifier);
+ if (avatar == null) return;
+
+ avatar.UpdateBoothId(newBoothId);
+ Save();
+ InvokeUpdated();
+ }
}
diff --git a/AvatarExplorer.Core/Utils/BoothUtils.cs b/AvatarExplorer.Core/Utils/BoothUtils.cs
new file mode 100644
index 00000000..a30df5b9
--- /dev/null
+++ b/AvatarExplorer.Core/Utils/BoothUtils.cs
@@ -0,0 +1,9 @@
+namespace AvatarExplorer.Core.Utils;
+
+public static class BoothUtils
+{
+ public static string ExtractBoothIdFromUrl(string url)
+ {
+ return url.Split('/')[^1];
+ }
+}
diff --git a/AvatarExplorer.UI/Factories/NavigationItemFactory.cs b/AvatarExplorer.UI/Factories/NavigationItemFactory.cs
index 05ccd1f9..743c9ab4 100644
--- a/AvatarExplorer.UI/Factories/NavigationItemFactory.cs
+++ b/AvatarExplorer.UI/Factories/NavigationItemFactory.cs
@@ -113,16 +113,26 @@ private static ItemViewModel FromItemFile(ItemFile file)
ViewModelType = ViewModelType.CommonAvatar
};
- private static ItemViewModel FromTempAvatar(Avatar avatar, TempAvatar tempAvatar) => new()
+ private static ItemViewModel FromTempAvatar(Avatar avatar, TempAvatar tempAvatar)
{
- ThumbnailSource = new() { Primary = SystemIconKey.AvatarIcon },
- TitleRaw = tempAvatar.AvatarName,
- TitleLocalizable = false,
- DescriptionRaw = new(Loc.Button.Description.TempAvatar),
- Identifier = avatar.Identifier,
- ActualValue = tempAvatar.Identifier,
- ViewModelType = ViewModelType.TempAvatar
- };
+ var vm = new ItemViewModel()
+ {
+ ThumbnailSource = new() { Primary = SystemIconKey.AvatarIcon },
+ TitleRaw = tempAvatar.AvatarName,
+ TitleLocalizable = false,
+ DescriptionRaw = new(Loc.Button.Description.TempAvatar),
+ Identifier = avatar.Identifier,
+ ActualValue = tempAvatar.Identifier,
+ ViewModelType = ViewModelType.TempAvatar
+ };
+
+ if (tempAvatar.BoothId != -1)
+ {
+ vm.Tags = [new() { ValueRaw = tempAvatar.BoothId.ToString() }];
+ }
+
+ return vm;
+ }
private static ItemViewModel CreateEmpty() => new()
{
diff --git a/AvatarExplorer.UI/Models/ContextMenu/ActionKey.cs b/AvatarExplorer.UI/Models/ContextMenu/ActionKey.cs
index 89c9eed4..4ea68b73 100644
--- a/AvatarExplorer.UI/Models/ContextMenu/ActionKey.cs
+++ b/AvatarExplorer.UI/Models/ContextMenu/ActionKey.cs
@@ -34,6 +34,7 @@ public enum ActionKey
RemovePreset,
EditTempAvatarName,
+ EditBoothId,
ResolveTempAvatar,
RemoveTempAvatar,
diff --git a/AvatarExplorer.UI/Services/ContextMenu/ContextMenuHandlerService.cs b/AvatarExplorer.UI/Services/ContextMenu/ContextMenuHandlerService.cs
index 1a561ade..9e0ea552 100644
--- a/AvatarExplorer.UI/Services/ContextMenu/ContextMenuHandlerService.cs
+++ b/AvatarExplorer.UI/Services/ContextMenu/ContextMenuHandlerService.cs
@@ -64,6 +64,7 @@ public static void Initialize()
Register(ActionKey.OpenPdfViewer, OpenPdfViewer);
Register(ActionKey.RemovePreset, RemovePreset);
Register(ActionKey.EditTempAvatarName, EditTempAvatarName);
+ Register(ActionKey.EditBoothId, EditBoothId);
Register(ActionKey.ResolveTempAvatar, ResolveTempAvatar);
Register(ActionKey.RemoveTempAvatar, RemoveTempAvatar);
Register(ActionKey.EditCustomCategoryName, EditCustomCategoryName);
@@ -531,6 +532,43 @@ private static async void EditTempAvatarName(string identifier)
NotificationType.Success
);
}
+ private static async void EditBoothId(string identifier)
+ {
+ var tempAvatar = InstanceRepository.TempAvatars.Get(identifier);
+ if (tempAvatar == null)
+ {
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Error.Default],
+ Localizer.Instance[Loc.Error.TempAvatarNotFound],
+ NotificationType.Error
+ );
+ return;
+ }
+
+ var newBoothId = await InstanceRepository.MainWindow.ShowTextDialog(
+ Localizer.Instance[Loc.Dialog.Title.SetBoothIdForTempAvatar],
+ tempAvatar.BoothId == -1 ? string.Empty : tempAvatar.BoothId.ToString()
+ );
+ if (string.IsNullOrEmpty(newBoothId)) return;
+
+ var boothId = ValueParser.Int(BoothUtils.ExtractBoothIdFromUrl(newBoothId), -1);
+ if (boothId == -1)
+ {
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Warning.Default],
+ Localizer.Instance[Loc.Warning.InvalidBoothId],
+ NotificationType.Warning
+ );
+ }
+
+ InstanceRepository.TempAvatars.UpdateBoothId(tempAvatar.Identifier, boothId);
+
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Success.Default],
+ Localizer.Instance[Loc.Success.ItemEdit],
+ NotificationType.Success
+ );
+ }
private static void ResolveTempAvatar(string identifier)
{
InstanceRepository.MainWindow.ResolveTempAvatarVM.Open(identifier);
diff --git a/AvatarExplorer.UI/Services/ViewControl/ContextMenuCreator.cs b/AvatarExplorer.UI/Services/ViewControl/ContextMenuCreator.cs
index b9c1e092..e2715d73 100644
--- a/AvatarExplorer.UI/Services/ViewControl/ContextMenuCreator.cs
+++ b/AvatarExplorer.UI/Services/ViewControl/ContextMenuCreator.cs
@@ -158,6 +158,7 @@ private static ContextMenuAction[] CreateFromTempAvatar()
List contextMenuActions =
[
new(Loc.ContextMenu.TempAvatar.EditTempAvatarName, ActionKey.EditTempAvatarName, ContextMenuIconType.Edit),
+ new(Loc.ContextMenu.TempAvatar.EditBoothId, ActionKey.EditBoothId, ContextMenuIconType.Edit),
new(Loc.ContextMenu.TempAvatar.ResolveTempAvatar, ActionKey.ResolveTempAvatar, ContextMenuIconType.Link, addSeparator: true),
new(Loc.ContextMenu.TempAvatar.RemoveTempAvatar, ActionKey.RemoveTempAvatar, ContextMenuIconType.Delete),
];
diff --git a/AvatarExplorer.UI/ViewModels/Overlays/ItemEditorViewModel.cs b/AvatarExplorer.UI/ViewModels/Overlays/ItemEditorViewModel.cs
index a3e5a7b7..f0035d25 100644
--- a/AvatarExplorer.UI/ViewModels/Overlays/ItemEditorViewModel.cs
+++ b/AvatarExplorer.UI/ViewModels/Overlays/ItemEditorViewModel.cs
@@ -250,6 +250,8 @@ public async Task Confirm()
Close();
+ await CheckTempAvatarBoothId(identifier);
+
if (itemPaths.Count == 0) return;
_ = AddPathsInBackground(identifier, itemPaths, shouldLinkToOriginal);
}
@@ -321,6 +323,31 @@ private async Task ConfirmCreate()
return item.Identifier;
}
+ private async static Task CheckTempAvatarBoothId(string identidier)
+ {
+ var boothId = InstanceRepository.Items.Get(identidier)?.BoothId ?? -1;
+ if (boothId == -1) return;
+
+ var sameIdAvatar = InstanceRepository.TempAvatars.GetAll()
+ .Where(i => i.BoothId != -1)
+ .FirstOrDefault(i => i.BoothId == boothId);
+ if (sameIdAvatar == null) return;
+
+ var resolveTempAvatar = await InstanceRepository.MainWindow.ShowYesNoDialog(
+ Localizer.Instance[Loc.Dialog.Confirmation.Default],
+ Localizer.Instance.Get(Loc.Dialog.Confirmation.ResolveSameBoothIdTempAvatar, sameIdAvatar.AvatarName)
+ );
+ if (!resolveTempAvatar) return;
+
+ InstanceRepository.ItemGroupService.ResolveTempAvatar(sameIdAvatar.Identifier, identidier);
+
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Success.Default],
+ Localizer.Instance[Loc.Success.ResolveTempAvatar],
+ NotificationType.Success
+ );
+ }
+
private static async Task AddPathsInBackground(string identifier, List itemPaths, bool shouldLinkToOriginal)
{
NotificationManager.Show(
diff --git a/AvatarExplorer.UI/ViewModels/Overlays/ResolveTempAvatarViewModel.cs b/AvatarExplorer.UI/ViewModels/Overlays/ResolveTempAvatarViewModel.cs
index e70b0d3c..308c6bd5 100644
--- a/AvatarExplorer.UI/ViewModels/Overlays/ResolveTempAvatarViewModel.cs
+++ b/AvatarExplorer.UI/ViewModels/Overlays/ResolveTempAvatarViewModel.cs
@@ -102,6 +102,13 @@ private async Task SelectItem(ItemViewModel item)
if (!resolveConfirmationResult) return;
InstanceRepository.ItemGroupService.ResolveTempAvatar(SelectedAvatar, item.Identifier);
+
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Success.Default],
+ Localizer.Instance[Loc.Success.ResolveTempAvatar],
+ NotificationType.Success
+ );
+
IsVisible = false;
}
diff --git a/AvatarExplorer.UI/ViewModels/Overlays/SelectAvatarsViewModel.cs b/AvatarExplorer.UI/ViewModels/Overlays/SelectAvatarsViewModel.cs
index d7dccc45..6d265df5 100644
--- a/AvatarExplorer.UI/ViewModels/Overlays/SelectAvatarsViewModel.cs
+++ b/AvatarExplorer.UI/ViewModels/Overlays/SelectAvatarsViewModel.cs
@@ -2,14 +2,17 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Avalonia.Controls.Notifications;
using AvatarExplorer.Core.Extensions;
using AvatarExplorer.Core.Localization;
using AvatarExplorer.Core.Models.Search;
+using AvatarExplorer.Core.Utils;
using AvatarExplorer.UI.Factories;
using AvatarExplorer.UI.Interfaces;
using AvatarExplorer.UI.Localization;
using AvatarExplorer.UI.Services;
using AvatarExplorer.UI.Services.Sort;
+using AvatarExplorer.UI.Services.System;
using AvatarExplorer.UI.ViewModels.Component;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
@@ -119,7 +122,41 @@ private async Task AddTempAvatar()
var newTempAvatarName = await InstanceRepository.MainWindow.ShowTextDialog(Localizer.Instance[Loc.Dialog.Title.NewTempAvatarName]);
if (string.IsNullOrEmpty(newTempAvatarName)) return;
- InstanceRepository.TempAvatars.Create(newTempAvatarName);
+ // BoothIdを指定するかどうか
+ var setBoothId = await InstanceRepository.MainWindow.ShowYesNoDialog(
+ Localizer.Instance[Loc.Dialog.Confirmation.Default],
+ Localizer.Instance[Loc.Dialog.Confirmation.SetBoothIdForTempAvatar]
+ );
+
+ var boothId = -1;
+ var parseBoothIdFailed = false;
+ if (setBoothId)
+ {
+ var boothIdInput = await InstanceRepository.MainWindow.ShowTextDialog(Localizer.Instance[Loc.Dialog.Title.SetBoothIdForTempAvatar]);
+ if (boothIdInput != null)
+ {
+ boothId = ValueParser.Int(BoothUtils.ExtractBoothIdFromUrl(boothIdInput), -1);
+ if (boothId < 0) parseBoothIdFailed = true;
+ }
+ }
+
+ if (parseBoothIdFailed)
+ {
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Warning.Default],
+ Localizer.Instance[Loc.Warning.InvalidBoothId],
+ NotificationType.Warning
+ );
+ }
+
+ InstanceRepository.TempAvatars.Create(newTempAvatarName, boothId);
+
+ NotificationManager.Show(
+ Localizer.Instance[Loc.Success.Default],
+ Localizer.Instance[Loc.Success.CreateTempAvatar],
+ NotificationType.Success
+ );
+
RefleshAvatars(IncludeCommonAvatar, IncludeTempAvatar);
ApplySearchResult(SearchText);
}
diff --git a/AvatarExplorer.UI/Views/Overlays/TextDialog.axaml b/AvatarExplorer.UI/Views/Overlays/TextDialog.axaml
index e9720e5a..c9b5ec4b 100644
--- a/AvatarExplorer.UI/Views/Overlays/TextDialog.axaml
+++ b/AvatarExplorer.UI/Views/Overlays/TextDialog.axaml
@@ -6,19 +6,16 @@
x:DataType="vm:TextDialogViewModel">
-
+
-
-
+
-
-
+
-
-
-
+
+
diff --git a/docs/04-avatar-management.md b/docs/04-avatar-management.md
index 4b4866d9..cfef0630 100644
--- a/docs/04-avatar-management.md
+++ b/docs/04-avatar-management.md
@@ -106,6 +106,8 @@ public class CommonAvatar : IIdentifiable
仮アバターは、まだ正式に登録されていないアバターを一時的に識別するための機能です。後で正式なアバターに「解決」することができます。
+仮アバターにはBooth IDを設定でき、Boothからアイテムを追加した際に紐付けに利用できます。
+
## TempAvatarRepository
### 取得
@@ -117,8 +119,13 @@ var tempAvatarRepo = app.TempAvatarRepository;
### Create() - 仮アバターの作成
```csharp
+// Booth IDなしで作成
var tempAvatar = tempAvatarRepo.Create("仮アバター名");
Console.WriteLine($"作成された仮アバター: {tempAvatar.Identifier}");
+
+// Booth IDを指定して作成
+var tempAvatarWithBooth = tempAvatarRepo.Create("仮アバター名", boothId: 12345678);
+Console.WriteLine($"Booth ID: {tempAvatarWithBooth.BoothId}");
```
### GetAll() - 全仮アバターの取得
@@ -138,6 +145,19 @@ foreach (var temp in allTempAvatars)
var temp = tempAvatarRepo.Get("tempavatar:xxxxx");
```
+### UpdateBoothId() - 仮アバターのBooth IDを変更
+
+```csharp
+// Booth IDを設定
+tempAvatarRepo.UpdateBoothId("tempavatar:xxxxx", 12345678);
+
+// Booth IDをクリア
+tempAvatarRepo.UpdateBoothId("tempavatar:xxxxx", -1);
+```
+
+> [!NOTE]
+> Booth IDを設定すると、Boothからアイテムを追加した際に仮アバターとの紐付けに利用できます。
+
### Remove() - 仮アバターの削除
**重要**: 仮アバターの削除には、`ItemGroupService.RemoveTempAvatar()`を使用してください。
@@ -168,6 +188,7 @@ app.ItemGroupService.ResolveTempAvatar(
public class TempAvatar : IIdentifiable
{
public string AvatarName { get; } // アバター名
+ public int BoothId { get; } // Booth商品ID(未設定の場合は-1)
public string Identifier { get; } // "tempavatar:" + Id
}
```
diff --git a/docs/05-booth-integration.md b/docs/05-booth-integration.md
index 8a39fa44..fdb9ebf6 100644
--- a/docs/05-booth-integration.md
+++ b/docs/05-booth-integration.md
@@ -229,6 +229,34 @@ if (item != null)
}
```
+## BoothUtils
+
+Booth URLから商品IDを抽出するユーティリティクラスです。
+
+```csharp
+using AvatarExplorer.Core.Utils;
+
+// URLからBooth IDを抽出
+var boothId = BoothUtils.ExtractBoothIdFromUrl("https://booth.pm/ja/items/12345678");
+// boothId: "12345678"
+
+// リンク形式でも抽出可能
+var boothId2 = BoothUtils.ExtractBoothIdFromUrl("https://xxx.booth.pm/items/12345678");
+// boothId2: "12345678"
+```
+
+### 仮アバターへのBooth ID設定
+
+仮アバターにBooth IDを設定すると、Boothからアイテムを追加した際に紐付けに利用できます。
+
+```csharp
+// 仮アバターにBooth IDを設定
+app.TempAvatarRepository.UpdateBoothId("tempavatar:xxxxx", 12345678);
+
+// 作成時にBooth IDを指定
+app.TempAvatarRepository.Create("新しい仮アバター", boothId: 12345678);
+```
+
## サムネイルの取得
### Boothからサムネイルを再取得
diff --git a/docs/09-search.md b/docs/09-search.md
index cf960cd9..99472169 100644
--- a/docs/09-search.md
+++ b/docs/09-search.md
@@ -201,6 +201,7 @@ foreach (var item in viewItems)
| `implemented` | 実装済みアバター名 |
| `notimplemented` | 未実装アバター名 |
| `commonavatar` | 共通素体グループ名 |
+| `boothid` / `booth` | 仮アバターのBooth商品ID |
## SearchResultTypes