feat: add functionality to open file location from model modal and update translations, fixes #405

This commit is contained in:
Will Miao
2025-09-11 15:54:32 +08:00
parent c66cbc800b
commit 8b4e3128ff
13 changed files with 146 additions and 12 deletions

View File

@@ -678,7 +678,12 @@
"editBaseModel": "Basis-Modell bearbeiten",
"viewOnCivitai": "Auf Civitai anzeigen",
"viewOnCivitaiText": "Auf Civitai anzeigen",
"viewCreatorProfile": "Ersteller-Profil anzeigen"
"viewCreatorProfile": "Ersteller-Profil anzeigen",
"openFileLocation": "Dateispeicherort öffnen"
},
"openFileLocation": {
"success": "Dateispeicherort erfolgreich geöffnet",
"failed": "Fehler beim Öffnen des Dateispeicherorts"
},
"metadata": {
"version": "Version",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "Edit base model",
"viewOnCivitai": "View on Civitai",
"viewOnCivitaiText": "View on Civitai",
"viewCreatorProfile": "View Creator Profile"
"viewCreatorProfile": "View Creator Profile",
"openFileLocation": "Open File Location"
},
"openFileLocation": {
"success": "File location opened successfully",
"failed": "Failed to open file location"
},
"metadata": {
"version": "Version",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "Editar modelo base",
"viewOnCivitai": "Ver en Civitai",
"viewOnCivitaiText": "Ver en Civitai",
"viewCreatorProfile": "Ver perfil del creador"
"viewCreatorProfile": "Ver perfil del creador",
"openFileLocation": "Abrir ubicación del archivo"
},
"openFileLocation": {
"success": "Ubicación del archivo abierta exitosamente",
"failed": "Error al abrir la ubicación del archivo"
},
"metadata": {
"version": "Versión",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "Modifier le modèle de base",
"viewOnCivitai": "Voir sur Civitai",
"viewOnCivitaiText": "Voir sur Civitai",
"viewCreatorProfile": "Voir le profil du créateur"
"viewCreatorProfile": "Voir le profil du créateur",
"openFileLocation": "Ouvrir l'emplacement du fichier"
},
"openFileLocation": {
"success": "Emplacement du fichier ouvert avec succès",
"failed": "Échec de l'ouverture de l'emplacement du fichier"
},
"metadata": {
"version": "Version",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "ベースモデルを編集",
"viewOnCivitai": "Civitaiで表示",
"viewOnCivitaiText": "Civitaiで表示",
"viewCreatorProfile": "作成者プロフィールを表示"
"viewCreatorProfile": "作成者プロフィールを表示",
"openFileLocation": "ファイルの場所を開く"
},
"openFileLocation": {
"success": "ファイルの場所を正常に開きました",
"failed": "ファイルの場所を開くのに失敗しました"
},
"metadata": {
"version": "バージョン",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "베이스 모델 편집",
"viewOnCivitai": "Civitai에서 보기",
"viewOnCivitaiText": "Civitai에서 보기",
"viewCreatorProfile": "제작자 프로필 보기"
"viewCreatorProfile": "제작자 프로필 보기",
"openFileLocation": "파일 위치 열기"
},
"openFileLocation": {
"success": "파일 위치가 성공적으로 열렸습니다",
"failed": "파일 위치 열기에 실패했습니다"
},
"metadata": {
"version": "버전",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "Редактировать базовую модель",
"viewOnCivitai": "Посмотреть на Civitai",
"viewOnCivitaiText": "Посмотреть на Civitai",
"viewCreatorProfile": "Посмотреть профиль создателя"
"viewCreatorProfile": "Посмотреть профиль создателя",
"openFileLocation": "Открыть расположение файла"
},
"openFileLocation": {
"success": "Расположение файла успешно открыто",
"failed": "Не удалось открыть расположение файла"
},
"metadata": {
"version": "Версия",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "编辑基础模型",
"viewOnCivitai": "在 Civitai 查看",
"viewOnCivitaiText": "在 Civitai 查看",
"viewCreatorProfile": "查看创作者主页"
"viewCreatorProfile": "查看创作者主页",
"openFileLocation": "打开文件位置"
},
"openFileLocation": {
"success": "文件位置已成功打开",
"failed": "打开文件位置失败"
},
"metadata": {
"version": "版本",

View File

@@ -678,7 +678,12 @@
"editBaseModel": "編輯基礎模型",
"viewOnCivitai": "在 Civitai 查看",
"viewOnCivitaiText": "在 Civitai 查看",
"viewCreatorProfile": "查看創作者個人檔案"
"viewCreatorProfile": "查看創作者個人檔案",
"openFileLocation": "開啟檔案位置"
},
"openFileLocation": {
"success": "檔案位置已成功開啟",
"failed": "開啟檔案位置失敗"
},
"metadata": {
"version": "版本",

View File

@@ -3,6 +3,7 @@ import os
import sys
import threading
import asyncio
import subprocess
from server import PromptServer # type: ignore
from aiohttp import web
from ..services.settings_manager import settings
@@ -90,6 +91,8 @@ class MiscRoutes:
app.router.add_get('/api/health-check', lambda request: web.json_response({'status': 'ok'}))
app.router.add_post('/api/open-file-location', MiscRoutes.open_file_location)
# Usage stats routes
app.router.add_post('/api/update-usage-stats', MiscRoutes.update_usage_stats)
app.router.add_get('/api/get-usage-stats', MiscRoutes.get_usage_stats)
@@ -770,3 +773,54 @@ class MiscRoutes:
'success': False,
'error': str(e)
}, status=500)
@staticmethod
async def open_file_location(request):
"""
Open the folder containing the specified file and select the file in the file explorer.
Expects a JSON request body with:
{
"file_path": "absolute/path/to/file"
}
"""
try:
data = await request.json()
file_path = data.get('file_path')
if not file_path:
return web.json_response({
'success': False,
'error': 'Missing file_path parameter'
}, status=400)
file_path = os.path.abspath(file_path)
if not os.path.isfile(file_path):
return web.json_response({
'success': False,
'error': 'File does not exist'
}, status=404)
# Open the folder and select the file
if os.name == 'nt': # Windows
# explorer /select,"C:\path\to\file"
subprocess.Popen(['explorer', '/select,', file_path])
elif os.name == 'posix':
if sys.platform == 'darwin': # macOS
subprocess.Popen(['open', '-R', file_path])
else: # Linux (selecting file is not standard, just open folder)
folder = os.path.dirname(file_path)
subprocess.Popen(['xdg-open', folder])
return web.json_response({
'success': True,
'message': f'Opened folder and selected file: {file_path}'
})
except Exception as e:
logger.error(f"Failed to open file location: {e}", exc_info=True)
return web.json_response({
'success': False,
'error': str(e)
}, status=500)

View File

@@ -1,6 +1,5 @@
import logging
import os
import re
import sys
import subprocess
from aiohttp import web

View File

@@ -67,6 +67,14 @@
font-size: 0.9em;
}
.file-path[data-action="open-file-location"] {
cursor: pointer;
text-decoration: underline;
}
.file-path[data-action="open-file-location"]:hover {
opacity: 0.8;
}
.description-text {
line-height: 1.5;
max-height: 100px;

View File

@@ -166,10 +166,14 @@ export async function showModelModal(model, modelType) {
</button>
</div>
</div>
<div class="info-item location-size">
<div class="info-item">
<div class="location-wrapper">
<label>${translate('modals.model.metadata.location', {}, 'Location')}</label>
<span class="file-path">${modelWithFullData.file_path.replace(/[^/]+$/, '') || 'N/A'}</span>
<span class="file-path" title="${translate('modals.model.actions.openFileLocation', {}, 'Open file location')}"
data-action="open-file-location"
data-filepath="${modelWithFullData.file_path}">
${modelWithFullData.file_path.replace(/[^/]+$/, '') || 'N/A'}
</span>
</div>
</div>
<div class="info-item base-size">
@@ -318,6 +322,12 @@ function setupEventHandlers(filePath) {
window.open(`https://civitai.com/user/${username}`, '_blank');
}
break;
case 'open-file-location':
const filePath = target.dataset.filepath;
if (filePath) {
openFileLocation(filePath);
}
break;
}
}
@@ -444,6 +454,24 @@ async function saveNotes(filePath) {
}
}
/**
* Call backend to open file location and select the file
* @param {string} filePath
*/
async function openFileLocation(filePath) {
try {
const resp = await fetch('/api/open-file-location', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ 'file_path': filePath })
});
if (!resp.ok) throw new Error('Failed to open file location');
showToast('modals.model.openFileLocation.success', {}, 'success');
} catch (err) {
showToast('modals.model.openFileLocation.failed', {}, 'error');
}
}
// Export the model modal API
const modelModal = {
show: showModelModal,