mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-05-07 00:46:44 -03:00
Compare commits
3 Commits
ba1800095e
...
6d0d9600a7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d0d9600a7 | ||
|
|
70cd3f4e1b | ||
|
|
a95c518b30 |
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "Early Access",
|
"earlyAccess": "Early Access",
|
||||||
"earlyAccessTooltip": "Early Access erforderlich",
|
"earlyAccessTooltip": "Early Access erforderlich",
|
||||||
"inLibrary": "In Bibliothek",
|
"inLibrary": "In Bibliothek",
|
||||||
|
"downloaded": "Heruntergeladen",
|
||||||
|
"downloadedTooltip": "Zuvor heruntergeladen, aber derzeit nicht in Ihrer Bibliothek.",
|
||||||
"alreadyInLibrary": "Bereits in Bibliothek",
|
"alreadyInLibrary": "Bereits in Bibliothek",
|
||||||
"autoOrganizedPath": "[Automatisch organisiert durch Pfadvorlage]",
|
"autoOrganizedPath": "[Automatisch organisiert durch Pfadvorlage]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "in {count}d"
|
"days": "in {count}d"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "Aktuelle Version",
|
"current": "Geöffnete Version",
|
||||||
|
"currentTooltip": "Das ist die Version, mit der dieses Modal geöffnet wurde",
|
||||||
"inLibrary": "In der Bibliothek",
|
"inLibrary": "In der Bibliothek",
|
||||||
|
"inLibraryTooltip": "Diese Version befindet sich in Ihrer lokalen Bibliothek",
|
||||||
|
"downloaded": "Heruntergeladen",
|
||||||
|
"downloadedTooltip": "Diese Version wurde bereits heruntergeladen, befindet sich aber derzeit nicht in Ihrer Bibliothek",
|
||||||
"newer": "Neuere Version",
|
"newer": "Neuere Version",
|
||||||
|
"newerTooltip": "Diese Version ist neuer als Ihre neueste lokale Version",
|
||||||
"earlyAccess": "Früher Zugriff",
|
"earlyAccess": "Früher Zugriff",
|
||||||
"ignored": "Ignoriert"
|
"earlyAccessTooltip": "Für diese Version ist derzeit Civitai Early Access erforderlich",
|
||||||
|
"ignored": "Ignoriert",
|
||||||
|
"ignoredTooltip": "Für diese Version sind Update-Benachrichtigungen deaktiviert"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "Herunterladen",
|
"download": "Herunterladen",
|
||||||
|
"downloadTooltip": "Diese Version herunterladen",
|
||||||
|
"downloadEarlyAccessTooltip": "Diese Early-Access-Version von Civitai herunterladen",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
|
"deleteTooltip": "Diese lokale Version löschen",
|
||||||
"ignore": "Ignorieren",
|
"ignore": "Ignorieren",
|
||||||
"unignore": "Ignorierung aufheben",
|
"unignore": "Ignorierung aufheben",
|
||||||
|
"ignoreTooltip": "Update-Benachrichtigungen für diese Version ignorieren",
|
||||||
|
"unignoreTooltip": "Update-Benachrichtigungen für diese Version fortsetzen",
|
||||||
|
"viewVersionOnCivitai": "Version auf Civitai anzeigen",
|
||||||
"earlyAccessTooltip": "Erfordert Early-Access-Kauf",
|
"earlyAccessTooltip": "Erfordert Early-Access-Kauf",
|
||||||
"resumeModelUpdates": "Aktualisierungen für dieses Modell fortsetzen",
|
"resumeModelUpdates": "Aktualisierungen für dieses Modell fortsetzen",
|
||||||
"ignoreModelUpdates": "Aktualisierungen für dieses Modell ignorieren",
|
"ignoreModelUpdates": "Aktualisierungen für dieses Modell ignorieren",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "Early Access",
|
"earlyAccess": "Early Access",
|
||||||
"earlyAccessTooltip": "Early access required",
|
"earlyAccessTooltip": "Early access required",
|
||||||
"inLibrary": "In Library",
|
"inLibrary": "In Library",
|
||||||
|
"downloaded": "Downloaded",
|
||||||
|
"downloadedTooltip": "Previously downloaded, but it is not currently in your library.",
|
||||||
"alreadyInLibrary": "Already in Library",
|
"alreadyInLibrary": "Already in Library",
|
||||||
"autoOrganizedPath": "[Auto-organized by path template]",
|
"autoOrganizedPath": "[Auto-organized by path template]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "in {count}d"
|
"days": "in {count}d"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "Current Version",
|
"current": "Opened Version",
|
||||||
|
"currentTooltip": "This is the version you opened this modal from",
|
||||||
"inLibrary": "In Library",
|
"inLibrary": "In Library",
|
||||||
|
"inLibraryTooltip": "This version exists in your local library",
|
||||||
|
"downloaded": "Downloaded",
|
||||||
|
"downloadedTooltip": "This version was downloaded before, but is not currently in your library",
|
||||||
"newer": "Newer Version",
|
"newer": "Newer Version",
|
||||||
|
"newerTooltip": "This version is newer than your latest local version",
|
||||||
"earlyAccess": "Early Access",
|
"earlyAccess": "Early Access",
|
||||||
"ignored": "Ignored"
|
"earlyAccessTooltip": "This version currently requires Civitai early access",
|
||||||
|
"ignored": "Ignored",
|
||||||
|
"ignoredTooltip": "Update notifications are disabled for this version"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
|
"downloadTooltip": "Download this version",
|
||||||
|
"downloadEarlyAccessTooltip": "Download this early access version from Civitai",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
|
"deleteTooltip": "Delete this local version",
|
||||||
"ignore": "Ignore",
|
"ignore": "Ignore",
|
||||||
"unignore": "Unignore",
|
"unignore": "Unignore",
|
||||||
|
"ignoreTooltip": "Ignore update notifications for this version",
|
||||||
|
"unignoreTooltip": "Resume update notifications for this version",
|
||||||
|
"viewVersionOnCivitai": "View version on Civitai",
|
||||||
"earlyAccessTooltip": "Requires early access purchase",
|
"earlyAccessTooltip": "Requires early access purchase",
|
||||||
"resumeModelUpdates": "Resume updates for this model",
|
"resumeModelUpdates": "Resume updates for this model",
|
||||||
"ignoreModelUpdates": "Ignore updates for this model",
|
"ignoreModelUpdates": "Ignore updates for this model",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "Acceso temprano",
|
"earlyAccess": "Acceso temprano",
|
||||||
"earlyAccessTooltip": "Acceso temprano requerido",
|
"earlyAccessTooltip": "Acceso temprano requerido",
|
||||||
"inLibrary": "En la biblioteca",
|
"inLibrary": "En la biblioteca",
|
||||||
|
"downloaded": "Descargado",
|
||||||
|
"downloadedTooltip": "Descargado anteriormente, pero actualmente no está en tu biblioteca.",
|
||||||
"alreadyInLibrary": "Ya en la biblioteca",
|
"alreadyInLibrary": "Ya en la biblioteca",
|
||||||
"autoOrganizedPath": "[Auto-organizado por plantilla de ruta]",
|
"autoOrganizedPath": "[Auto-organizado por plantilla de ruta]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "en {count}d"
|
"days": "en {count}d"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "Versión actual",
|
"current": "Versión abierta",
|
||||||
|
"currentTooltip": "Es la versión con la que abriste este modal",
|
||||||
"inLibrary": "En la biblioteca",
|
"inLibrary": "En la biblioteca",
|
||||||
|
"inLibraryTooltip": "Esta versión existe en tu biblioteca local",
|
||||||
|
"downloaded": "Descargado",
|
||||||
|
"downloadedTooltip": "Esta versión se descargó antes, pero ahora no está en tu biblioteca",
|
||||||
"newer": "Versión más reciente",
|
"newer": "Versión más reciente",
|
||||||
|
"newerTooltip": "Esta versión es más reciente que tu última versión local",
|
||||||
"earlyAccess": "Acceso temprano",
|
"earlyAccess": "Acceso temprano",
|
||||||
"ignored": "Ignorada"
|
"earlyAccessTooltip": "Esta versión requiere actualmente acceso temprano de Civitai",
|
||||||
|
"ignored": "Ignorada",
|
||||||
|
"ignoredTooltip": "Las notificaciones de actualización están desactivadas para esta versión"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "Descargar",
|
"download": "Descargar",
|
||||||
|
"downloadTooltip": "Descargar esta versión",
|
||||||
|
"downloadEarlyAccessTooltip": "Descargar esta versión de acceso temprano desde Civitai",
|
||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
|
"deleteTooltip": "Eliminar esta versión local",
|
||||||
"ignore": "Ignorar",
|
"ignore": "Ignorar",
|
||||||
"unignore": "Dejar de ignorar",
|
"unignore": "Dejar de ignorar",
|
||||||
|
"ignoreTooltip": "Ignorar las notificaciones de actualización de esta versión",
|
||||||
|
"unignoreTooltip": "Reanudar las notificaciones de actualización de esta versión",
|
||||||
|
"viewVersionOnCivitai": "Ver versión en Civitai",
|
||||||
"earlyAccessTooltip": "Requiere compra de acceso temprano",
|
"earlyAccessTooltip": "Requiere compra de acceso temprano",
|
||||||
"resumeModelUpdates": "Reanudar actualizaciones para este modelo",
|
"resumeModelUpdates": "Reanudar actualizaciones para este modelo",
|
||||||
"ignoreModelUpdates": "Ignorar actualizaciones para este modelo",
|
"ignoreModelUpdates": "Ignorar actualizaciones para este modelo",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "Accès anticipé",
|
"earlyAccess": "Accès anticipé",
|
||||||
"earlyAccessTooltip": "Accès anticipé requis",
|
"earlyAccessTooltip": "Accès anticipé requis",
|
||||||
"inLibrary": "Dans la bibliothèque",
|
"inLibrary": "Dans la bibliothèque",
|
||||||
|
"downloaded": "Téléchargé",
|
||||||
|
"downloadedTooltip": "Déjà téléchargé, mais il n'est actuellement pas dans votre bibliothèque.",
|
||||||
"alreadyInLibrary": "Déjà dans la bibliothèque",
|
"alreadyInLibrary": "Déjà dans la bibliothèque",
|
||||||
"autoOrganizedPath": "[Auto-organisé par modèle de chemin]",
|
"autoOrganizedPath": "[Auto-organisé par modèle de chemin]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "dans {count}j"
|
"days": "dans {count}j"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "Version actuelle",
|
"current": "Version ouverte",
|
||||||
|
"currentTooltip": "C'est la version à partir de laquelle cette fenêtre a été ouverte",
|
||||||
"inLibrary": "Dans la bibliothèque",
|
"inLibrary": "Dans la bibliothèque",
|
||||||
|
"inLibraryTooltip": "Cette version existe dans votre bibliothèque locale",
|
||||||
|
"downloaded": "Téléchargé",
|
||||||
|
"downloadedTooltip": "Cette version a déjà été téléchargée, mais n'est pas actuellement dans votre bibliothèque",
|
||||||
"newer": "Version plus récente",
|
"newer": "Version plus récente",
|
||||||
|
"newerTooltip": "Cette version est plus récente que votre dernière version locale",
|
||||||
"earlyAccess": "Accès anticipé",
|
"earlyAccess": "Accès anticipé",
|
||||||
"ignored": "Ignorée"
|
"earlyAccessTooltip": "Cette version nécessite actuellement l'accès anticipé Civitai",
|
||||||
|
"ignored": "Ignorée",
|
||||||
|
"ignoredTooltip": "Les notifications de mise à jour sont désactivées pour cette version"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "Télécharger",
|
"download": "Télécharger",
|
||||||
|
"downloadTooltip": "Télécharger cette version",
|
||||||
|
"downloadEarlyAccessTooltip": "Télécharger cette version en accès anticipé depuis Civitai",
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
|
"deleteTooltip": "Supprimer cette version locale",
|
||||||
"ignore": "Ignorer",
|
"ignore": "Ignorer",
|
||||||
"unignore": "Ne plus ignorer",
|
"unignore": "Ne plus ignorer",
|
||||||
|
"ignoreTooltip": "Ignorer les notifications de mise à jour pour cette version",
|
||||||
|
"unignoreTooltip": "Reprendre les notifications de mise à jour pour cette version",
|
||||||
|
"viewVersionOnCivitai": "Voir la version sur Civitai",
|
||||||
"earlyAccessTooltip": "Nécessite l'achat de l'accès anticipé",
|
"earlyAccessTooltip": "Nécessite l'achat de l'accès anticipé",
|
||||||
"resumeModelUpdates": "Reprendre les mises à jour pour ce modèle",
|
"resumeModelUpdates": "Reprendre les mises à jour pour ce modèle",
|
||||||
"ignoreModelUpdates": "Ignorer les mises à jour pour ce modèle",
|
"ignoreModelUpdates": "Ignorer les mises à jour pour ce modèle",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "גישה מוקדמת",
|
"earlyAccess": "גישה מוקדמת",
|
||||||
"earlyAccessTooltip": "נדרשת גישה מוקדמת",
|
"earlyAccessTooltip": "נדרשת גישה מוקדמת",
|
||||||
"inLibrary": "בספרייה",
|
"inLibrary": "בספרייה",
|
||||||
|
"downloaded": "הורד",
|
||||||
|
"downloadedTooltip": "הורד בעבר, אך הוא אינו נמצא כרגע בספרייה שלך.",
|
||||||
"alreadyInLibrary": "כבר בספרייה",
|
"alreadyInLibrary": "כבר בספרייה",
|
||||||
"autoOrganizedPath": "[מאורגן אוטומטית לפי תבנית נתיב]",
|
"autoOrganizedPath": "[מאורגן אוטומטית לפי תבנית נתיב]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "בעוד {count} ימים"
|
"days": "בעוד {count} ימים"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "גרסה נוכחית",
|
"current": "גרסה שנפתחה",
|
||||||
|
"currentTooltip": "זוהי הגרסה שממנה נפתח החלון הזה",
|
||||||
"inLibrary": "בספרייה",
|
"inLibrary": "בספרייה",
|
||||||
|
"inLibraryTooltip": "גרסה זו קיימת בספרייה המקומית שלך",
|
||||||
|
"downloaded": "הורד",
|
||||||
|
"downloadedTooltip": "גרסה זו הורדה בעבר, אך אינה נמצאת כרגע בספרייה שלך",
|
||||||
"newer": "גרסה חדשה יותר",
|
"newer": "גרסה חדשה יותר",
|
||||||
|
"newerTooltip": "גרסה זו חדשה יותר מהגרסה המקומית האחרונה שלך",
|
||||||
"earlyAccess": "גישה מוקדמת",
|
"earlyAccess": "גישה מוקדמת",
|
||||||
"ignored": "התעלם"
|
"earlyAccessTooltip": "גרסה זו דורשת כרגע גישת Early Access של Civitai",
|
||||||
|
"ignored": "התעלם",
|
||||||
|
"ignoredTooltip": "התראות העדכון מושבתות עבור גרסה זו"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "הורדה",
|
"download": "הורדה",
|
||||||
|
"downloadTooltip": "הורד את הגרסה הזו",
|
||||||
|
"downloadEarlyAccessTooltip": "הורד את גרסת ה-Early Access הזו מ-Civitai",
|
||||||
"delete": "מחיקה",
|
"delete": "מחיקה",
|
||||||
|
"deleteTooltip": "מחק את הגרסה המקומית הזו",
|
||||||
"ignore": "התעלם",
|
"ignore": "התעלם",
|
||||||
"unignore": "בטל התעלמות",
|
"unignore": "בטל התעלמות",
|
||||||
|
"ignoreTooltip": "התעלם מהתראות העדכון עבור גרסה זו",
|
||||||
|
"unignoreTooltip": "חזור לקבל התראות עדכון עבור גרסה זו",
|
||||||
|
"viewVersionOnCivitai": "הצג את הגרסה ב-Civitai",
|
||||||
"earlyAccessTooltip": "נדרש רכישת גישה מוקדמת",
|
"earlyAccessTooltip": "נדרש רכישת גישה מוקדמת",
|
||||||
"resumeModelUpdates": "המשך עדכונים עבור מודל זה",
|
"resumeModelUpdates": "המשך עדכונים עבור מודל זה",
|
||||||
"ignoreModelUpdates": "התעלם מעדכונים עבור מודל זה",
|
"ignoreModelUpdates": "התעלם מעדכונים עבור מודל זה",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "アーリーアクセス",
|
"earlyAccess": "アーリーアクセス",
|
||||||
"earlyAccessTooltip": "アーリーアクセスが必要",
|
"earlyAccessTooltip": "アーリーアクセスが必要",
|
||||||
"inLibrary": "ライブラリ内",
|
"inLibrary": "ライブラリ内",
|
||||||
|
"downloaded": "ダウンロード済み",
|
||||||
|
"downloadedTooltip": "以前にダウンロード済みですが、現在はライブラリにありません。",
|
||||||
"alreadyInLibrary": "既にライブラリ内",
|
"alreadyInLibrary": "既にライブラリ内",
|
||||||
"autoOrganizedPath": "[パステンプレートによる自動整理]",
|
"autoOrganizedPath": "[パステンプレートによる自動整理]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "{count}日後"
|
"days": "{count}日後"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "現在のバージョン",
|
"current": "開いたバージョン",
|
||||||
|
"currentTooltip": "このモーダルを開くために選択したバージョンです",
|
||||||
"inLibrary": "ライブラリにあります",
|
"inLibrary": "ライブラリにあります",
|
||||||
|
"inLibraryTooltip": "このバージョンはローカルライブラリに存在します",
|
||||||
|
"downloaded": "ダウンロード済み",
|
||||||
|
"downloadedTooltip": "このバージョンは以前ダウンロードされましたが、現在はライブラリにありません",
|
||||||
"newer": "新しいバージョン",
|
"newer": "新しいバージョン",
|
||||||
|
"newerTooltip": "このバージョンはローカルの最新バージョンより新しいです",
|
||||||
"earlyAccess": "早期アクセス",
|
"earlyAccess": "早期アクセス",
|
||||||
"ignored": "無視中"
|
"earlyAccessTooltip": "このバージョンは現在 Civitai の早期アクセスが必要です",
|
||||||
|
"ignored": "無視中",
|
||||||
|
"ignoredTooltip": "このバージョンの更新通知は無効です"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "ダウンロード",
|
"download": "ダウンロード",
|
||||||
|
"downloadTooltip": "このバージョンをダウンロード",
|
||||||
|
"downloadEarlyAccessTooltip": "Civitai からこの早期アクセス版をダウンロード",
|
||||||
"delete": "削除",
|
"delete": "削除",
|
||||||
|
"deleteTooltip": "このローカルバージョンを削除",
|
||||||
"ignore": "無視",
|
"ignore": "無視",
|
||||||
"unignore": "無視を解除",
|
"unignore": "無視を解除",
|
||||||
|
"ignoreTooltip": "このバージョンの更新通知を無視",
|
||||||
|
"unignoreTooltip": "このバージョンの更新通知を再開",
|
||||||
|
"viewVersionOnCivitai": "Civitai でバージョンを表示",
|
||||||
"earlyAccessTooltip": "早期アクセス購入が必要",
|
"earlyAccessTooltip": "早期アクセス購入が必要",
|
||||||
"resumeModelUpdates": "このモデルの更新を再開",
|
"resumeModelUpdates": "このモデルの更新を再開",
|
||||||
"ignoreModelUpdates": "このモデルの更新を無視",
|
"ignoreModelUpdates": "このモデルの更新を無視",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "얼리 액세스",
|
"earlyAccess": "얼리 액세스",
|
||||||
"earlyAccessTooltip": "얼리 액세스 필요",
|
"earlyAccessTooltip": "얼리 액세스 필요",
|
||||||
"inLibrary": "라이브러리에 있음",
|
"inLibrary": "라이브러리에 있음",
|
||||||
|
"downloaded": "다운로드됨",
|
||||||
|
"downloadedTooltip": "이전에 다운로드했지만 현재 라이브러리에 없습니다.",
|
||||||
"alreadyInLibrary": "이미 라이브러리에 있음",
|
"alreadyInLibrary": "이미 라이브러리에 있음",
|
||||||
"autoOrganizedPath": "[경로 템플릿으로 자동 정리됨]",
|
"autoOrganizedPath": "[경로 템플릿으로 자동 정리됨]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "{count}일 후"
|
"days": "{count}일 후"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "현재 버전",
|
"current": "열린 버전",
|
||||||
|
"currentTooltip": "이 모달을 열 때 사용한 버전입니다",
|
||||||
"inLibrary": "라이브러리에 있음",
|
"inLibrary": "라이브러리에 있음",
|
||||||
|
"inLibraryTooltip": "이 버전은 로컬 라이브러리에 있습니다",
|
||||||
|
"downloaded": "다운로드됨",
|
||||||
|
"downloadedTooltip": "이 버전은 이전에 다운로드되었지만 현재는 라이브러리에 없습니다",
|
||||||
"newer": "최신 버전",
|
"newer": "최신 버전",
|
||||||
|
"newerTooltip": "이 버전은 로컬의 최신 버전보다 더 새롭습니다",
|
||||||
"earlyAccess": "얼리 액세스",
|
"earlyAccess": "얼리 액세스",
|
||||||
"ignored": "무시됨"
|
"earlyAccessTooltip": "이 버전은 현재 Civitai 얼리 액세스가 필요합니다",
|
||||||
|
"ignored": "무시됨",
|
||||||
|
"ignoredTooltip": "이 버전은 업데이트 알림이 비활성화되어 있습니다"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "다운로드",
|
"download": "다운로드",
|
||||||
|
"downloadTooltip": "이 버전 다운로드",
|
||||||
|
"downloadEarlyAccessTooltip": "Civitai에서 이 얼리 액세스 버전 다운로드",
|
||||||
"delete": "삭제",
|
"delete": "삭제",
|
||||||
|
"deleteTooltip": "이 로컬 버전 삭제",
|
||||||
"ignore": "무시",
|
"ignore": "무시",
|
||||||
"unignore": "무시 해제",
|
"unignore": "무시 해제",
|
||||||
|
"ignoreTooltip": "이 버전의 업데이트 알림 무시",
|
||||||
|
"unignoreTooltip": "이 버전의 업데이트 알림 다시 받기",
|
||||||
|
"viewVersionOnCivitai": "Civitai에서 버전 보기",
|
||||||
"earlyAccessTooltip": "얼리 액세스 구매 필요",
|
"earlyAccessTooltip": "얼리 액세스 구매 필요",
|
||||||
"resumeModelUpdates": "이 모델 업데이트 재개",
|
"resumeModelUpdates": "이 모델 업데이트 재개",
|
||||||
"ignoreModelUpdates": "이 모델 업데이트 무시",
|
"ignoreModelUpdates": "이 모델 업데이트 무시",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "Ранний доступ",
|
"earlyAccess": "Ранний доступ",
|
||||||
"earlyAccessTooltip": "Требуется ранний доступ",
|
"earlyAccessTooltip": "Требуется ранний доступ",
|
||||||
"inLibrary": "В библиотеке",
|
"inLibrary": "В библиотеке",
|
||||||
|
"downloaded": "Загружено",
|
||||||
|
"downloadedTooltip": "Ранее загружено, но сейчас этого нет в вашей библиотеке.",
|
||||||
"alreadyInLibrary": "Уже в библиотеке",
|
"alreadyInLibrary": "Уже в библиотеке",
|
||||||
"autoOrganizedPath": "[Автоматически организовано по шаблону пути]",
|
"autoOrganizedPath": "[Автоматически организовано по шаблону пути]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "через {count}д"
|
"days": "через {count}д"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "Текущая версия",
|
"current": "Открытая версия",
|
||||||
|
"currentTooltip": "Это версия, с которой было открыто это окно",
|
||||||
"inLibrary": "В библиотеке",
|
"inLibrary": "В библиотеке",
|
||||||
|
"inLibraryTooltip": "Эта версия есть в вашей локальной библиотеке",
|
||||||
|
"downloaded": "Загружено",
|
||||||
|
"downloadedTooltip": "Эта версия уже загружалась, но сейчас отсутствует в вашей библиотеке",
|
||||||
"newer": "Более новая версия",
|
"newer": "Более новая версия",
|
||||||
|
"newerTooltip": "Эта версия новее вашей последней локальной версии",
|
||||||
"earlyAccess": "Ранний доступ",
|
"earlyAccess": "Ранний доступ",
|
||||||
"ignored": "Игнорируется"
|
"earlyAccessTooltip": "Для этой версии сейчас требуется ранний доступ Civitai",
|
||||||
|
"ignored": "Игнорируется",
|
||||||
|
"ignoredTooltip": "Уведомления об обновлениях для этой версии отключены"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "Скачать",
|
"download": "Скачать",
|
||||||
|
"downloadTooltip": "Скачать эту версию",
|
||||||
|
"downloadEarlyAccessTooltip": "Скачать эту версию раннего доступа с Civitai",
|
||||||
"delete": "Удалить",
|
"delete": "Удалить",
|
||||||
|
"deleteTooltip": "Удалить эту локальную версию",
|
||||||
"ignore": "Игнорировать",
|
"ignore": "Игнорировать",
|
||||||
"unignore": "Перестать игнорировать",
|
"unignore": "Перестать игнорировать",
|
||||||
|
"ignoreTooltip": "Игнорировать уведомления об обновлениях для этой версии",
|
||||||
|
"unignoreTooltip": "Возобновить уведомления об обновлениях для этой версии",
|
||||||
|
"viewVersionOnCivitai": "Посмотреть версию на Civitai",
|
||||||
"earlyAccessTooltip": "Требуется покупка раннего доступа",
|
"earlyAccessTooltip": "Требуется покупка раннего доступа",
|
||||||
"resumeModelUpdates": "Возобновить обновления для этой модели",
|
"resumeModelUpdates": "Возобновить обновления для этой модели",
|
||||||
"ignoreModelUpdates": "Игнорировать обновления для этой модели",
|
"ignoreModelUpdates": "Игнорировать обновления для этой модели",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "早期访问",
|
"earlyAccess": "早期访问",
|
||||||
"earlyAccessTooltip": "需要早期访问权限",
|
"earlyAccessTooltip": "需要早期访问权限",
|
||||||
"inLibrary": "已在库中",
|
"inLibrary": "已在库中",
|
||||||
|
"downloaded": "已下载",
|
||||||
|
"downloadedTooltip": "之前已下载,但当前不在你的库中。",
|
||||||
"alreadyInLibrary": "已存在于库中",
|
"alreadyInLibrary": "已存在于库中",
|
||||||
"autoOrganizedPath": "【已按路径模板自动整理】",
|
"autoOrganizedPath": "【已按路径模板自动整理】",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "{count}天后"
|
"days": "{count}天后"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "当前版本",
|
"current": "已打开版本",
|
||||||
|
"currentTooltip": "这是你用来打开此弹窗的版本",
|
||||||
"inLibrary": "已在库中",
|
"inLibrary": "已在库中",
|
||||||
|
"inLibraryTooltip": "此版本已存在于你的本地库中",
|
||||||
|
"downloaded": "已下载",
|
||||||
|
"downloadedTooltip": "此版本之前下载过,但当前不在你的本地库中",
|
||||||
"newer": "较新的版本",
|
"newer": "较新的版本",
|
||||||
|
"newerTooltip": "此版本比你本地的最新版本更新",
|
||||||
"earlyAccess": "抢先体验",
|
"earlyAccess": "抢先体验",
|
||||||
"ignored": "已忽略"
|
"earlyAccessTooltip": "此版本当前需要 Civitai 抢先体验权限",
|
||||||
|
"ignored": "已忽略",
|
||||||
|
"ignoredTooltip": "此版本已关闭更新通知"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "下载",
|
"download": "下载",
|
||||||
|
"downloadTooltip": "下载此版本",
|
||||||
|
"downloadEarlyAccessTooltip": "从 Civitai 下载此抢先体验版本",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
|
"deleteTooltip": "删除此本地版本",
|
||||||
"ignore": "忽略",
|
"ignore": "忽略",
|
||||||
"unignore": "取消忽略",
|
"unignore": "取消忽略",
|
||||||
|
"ignoreTooltip": "忽略此版本的更新通知",
|
||||||
|
"unignoreTooltip": "恢复此版本的更新通知",
|
||||||
|
"viewVersionOnCivitai": "在 Civitai 上查看版本",
|
||||||
"earlyAccessTooltip": "需要购买抢先体验",
|
"earlyAccessTooltip": "需要购买抢先体验",
|
||||||
"resumeModelUpdates": "继续跟踪该模型的更新",
|
"resumeModelUpdates": "继续跟踪该模型的更新",
|
||||||
"ignoreModelUpdates": "忽略该模型的更新",
|
"ignoreModelUpdates": "忽略该模型的更新",
|
||||||
|
|||||||
@@ -957,6 +957,8 @@
|
|||||||
"earlyAccess": "早期存取",
|
"earlyAccess": "早期存取",
|
||||||
"earlyAccessTooltip": "需要早期存取",
|
"earlyAccessTooltip": "需要早期存取",
|
||||||
"inLibrary": "已在庫存",
|
"inLibrary": "已在庫存",
|
||||||
|
"downloaded": "已下載",
|
||||||
|
"downloadedTooltip": "先前已下載,但目前不在你的庫中。",
|
||||||
"alreadyInLibrary": "已在庫存",
|
"alreadyInLibrary": "已在庫存",
|
||||||
"autoOrganizedPath": "[依路徑範本自動整理]",
|
"autoOrganizedPath": "[依路徑範本自動整理]",
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1226,17 +1228,30 @@
|
|||||||
"days": "{count}天後"
|
"days": "{count}天後"
|
||||||
},
|
},
|
||||||
"badges": {
|
"badges": {
|
||||||
"current": "目前版本",
|
"current": "已開啟版本",
|
||||||
|
"currentTooltip": "這是你用來開啟此彈窗的版本",
|
||||||
"inLibrary": "已在庫中",
|
"inLibrary": "已在庫中",
|
||||||
|
"inLibraryTooltip": "此版本已存在於你的本地庫中",
|
||||||
|
"downloaded": "已下載",
|
||||||
|
"downloadedTooltip": "此版本之前下載過,但目前不在你的本地庫中",
|
||||||
"newer": "較新版本",
|
"newer": "較新版本",
|
||||||
|
"newerTooltip": "此版本比你本地的最新版本更新",
|
||||||
"earlyAccess": "搶先體驗",
|
"earlyAccess": "搶先體驗",
|
||||||
"ignored": "已忽略"
|
"earlyAccessTooltip": "此版本目前需要 Civitai 搶先體驗權限",
|
||||||
|
"ignored": "已忽略",
|
||||||
|
"ignoredTooltip": "此版本已關閉更新通知"
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
"download": "下載",
|
"download": "下載",
|
||||||
|
"downloadTooltip": "下載此版本",
|
||||||
|
"downloadEarlyAccessTooltip": "從 Civitai 下載此搶先體驗版本",
|
||||||
"delete": "刪除",
|
"delete": "刪除",
|
||||||
|
"deleteTooltip": "刪除此本地版本",
|
||||||
"ignore": "忽略",
|
"ignore": "忽略",
|
||||||
"unignore": "取消忽略",
|
"unignore": "取消忽略",
|
||||||
|
"ignoreTooltip": "忽略此版本的更新通知",
|
||||||
|
"unignoreTooltip": "恢復此版本的更新通知",
|
||||||
|
"viewVersionOnCivitai": "在 Civitai 上查看版本",
|
||||||
"earlyAccessTooltip": "需要購買搶先體驗",
|
"earlyAccessTooltip": "需要購買搶先體驗",
|
||||||
"resumeModelUpdates": "恢復追蹤此模型的更新",
|
"resumeModelUpdates": "恢復追蹤此模型的更新",
|
||||||
"ignoreModelUpdates": "忽略此模型的更新",
|
"ignoreModelUpdates": "忽略此模型的更新",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from ...services.download_coordinator import DownloadCoordinator
|
|||||||
from ...services.metadata_sync_service import MetadataSyncService
|
from ...services.metadata_sync_service import MetadataSyncService
|
||||||
from ...services.model_file_service import ModelMoveService
|
from ...services.model_file_service import ModelMoveService
|
||||||
from ...services.preview_asset_service import PreviewAssetService
|
from ...services.preview_asset_service import PreviewAssetService
|
||||||
|
from ...services.service_registry import ServiceRegistry
|
||||||
from ...services.settings_manager import SettingsManager, get_settings_manager
|
from ...services.settings_manager import SettingsManager, get_settings_manager
|
||||||
from ...services.tag_update_service import TagUpdateService
|
from ...services.tag_update_service import TagUpdateService
|
||||||
from ...services.use_cases import (
|
from ...services.use_cases import (
|
||||||
@@ -1531,6 +1532,20 @@ class ModelCivitaiHandler:
|
|||||||
|
|
||||||
cache = await self._service.scanner.get_cached_data()
|
cache = await self._service.scanner.get_cached_data()
|
||||||
version_index = cache.version_index
|
version_index = cache.version_index
|
||||||
|
downloaded_version_ids: set[int] = set()
|
||||||
|
try:
|
||||||
|
history_service = await ServiceRegistry.get_downloaded_version_history_service()
|
||||||
|
downloaded_version_ids = set(
|
||||||
|
await history_service.get_downloaded_version_ids(
|
||||||
|
self._service.model_type,
|
||||||
|
model_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as exc: # pragma: no cover - defensive logging
|
||||||
|
self._logger.debug(
|
||||||
|
"Failed to load download history for CivitAI versions: %s",
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
|
||||||
for version in versions:
|
for version in versions:
|
||||||
version_id = None
|
version_id = None
|
||||||
@@ -1547,6 +1562,9 @@ class ModelCivitaiHandler:
|
|||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
version["existsLocally"] = cache_entry is not None
|
version["existsLocally"] = cache_entry is not None
|
||||||
|
version["hasBeenDownloaded"] = (
|
||||||
|
version_id in downloaded_version_ids if version_id is not None else False
|
||||||
|
)
|
||||||
if cache_entry and isinstance(cache_entry, Mapping):
|
if cache_entry and isinstance(cache_entry, Mapping):
|
||||||
local_path = cache_entry.get("file_path")
|
local_path = cache_entry.get("file_path")
|
||||||
if local_path:
|
if local_path:
|
||||||
@@ -2265,7 +2283,7 @@ class ModelUpdateHandler:
|
|||||||
self,
|
self,
|
||||||
record,
|
record,
|
||||||
*,
|
*,
|
||||||
version_context: Optional[Dict[int, Dict[str, Optional[str]]]] = None,
|
version_context: Optional[Dict[int, Dict[str, Any]]] = None,
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
context = version_context or {}
|
context = version_context or {}
|
||||||
# Check user setting for hiding early access versions
|
# Check user setting for hiding early access versions
|
||||||
@@ -2294,7 +2312,7 @@ class ModelUpdateHandler:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _serialize_version(
|
def _serialize_version(
|
||||||
version, context: Optional[Dict[str, Optional[str]]]
|
version, context: Optional[Dict[str, Any]]
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
context = context or {}
|
context = context or {}
|
||||||
preview_override = context.get("preview_override")
|
preview_override = context.get("preview_override")
|
||||||
@@ -2328,6 +2346,7 @@ class ModelUpdateHandler:
|
|||||||
"sizeBytes": version.size_bytes,
|
"sizeBytes": version.size_bytes,
|
||||||
"previewUrl": preview_url,
|
"previewUrl": preview_url,
|
||||||
"isInLibrary": version.is_in_library,
|
"isInLibrary": version.is_in_library,
|
||||||
|
"hasBeenDownloaded": bool(context.get("has_been_downloaded", False)),
|
||||||
"shouldIgnore": version.should_ignore,
|
"shouldIgnore": version.should_ignore,
|
||||||
"earlyAccessEndsAt": version.early_access_ends_at,
|
"earlyAccessEndsAt": version.early_access_ends_at,
|
||||||
"isEarlyAccess": is_early_access,
|
"isEarlyAccess": is_early_access,
|
||||||
@@ -2337,8 +2356,31 @@ class ModelUpdateHandler:
|
|||||||
|
|
||||||
async def _build_version_context(
|
async def _build_version_context(
|
||||||
self, record
|
self, record
|
||||||
) -> Dict[int, Dict[str, Optional[str]]]:
|
) -> Dict[int, Dict[str, Any]]:
|
||||||
context: Dict[int, Dict[str, Optional[str]]] = {}
|
context: Dict[int, Dict[str, Any]] = {}
|
||||||
|
downloaded_version_ids: set[int] = set()
|
||||||
|
try:
|
||||||
|
history_service = await ServiceRegistry.get_downloaded_version_history_service()
|
||||||
|
downloaded_version_ids = set(
|
||||||
|
await history_service.get_downloaded_version_ids(
|
||||||
|
record.model_type,
|
||||||
|
record.model_id,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as exc: # pragma: no cover - defensive logging
|
||||||
|
self._logger.debug(
|
||||||
|
"Failed to load download history while building version context: %s",
|
||||||
|
exc,
|
||||||
|
)
|
||||||
|
|
||||||
|
for version in record.versions:
|
||||||
|
context[version.version_id] = {
|
||||||
|
"file_path": None,
|
||||||
|
"file_name": None,
|
||||||
|
"preview_override": None,
|
||||||
|
"has_been_downloaded": version.version_id in downloaded_version_ids,
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cache = await self._service.scanner.get_cached_data()
|
cache = await self._service.scanner.get_cached_data()
|
||||||
except Exception as exc: # pragma: no cover - defensive logging
|
except Exception as exc: # pragma: no cover - defensive logging
|
||||||
@@ -2357,16 +2399,21 @@ class ModelUpdateHandler:
|
|||||||
cache_entry = version_index.get(version.version_id)
|
cache_entry = version_index.get(version.version_id)
|
||||||
if isinstance(cache_entry, Mapping):
|
if isinstance(cache_entry, Mapping):
|
||||||
preview = cache_entry.get("preview_url")
|
preview = cache_entry.get("preview_url")
|
||||||
context_entry: Dict[str, Optional[str]] = {
|
context_entry = context.setdefault(
|
||||||
"file_path": cache_entry.get("file_path"),
|
version.version_id,
|
||||||
"file_name": cache_entry.get("file_name"),
|
{
|
||||||
"preview_override": None,
|
"file_path": None,
|
||||||
}
|
"file_name": None,
|
||||||
|
"preview_override": None,
|
||||||
|
"has_been_downloaded": version.version_id in downloaded_version_ids,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
context_entry["file_path"] = cache_entry.get("file_path")
|
||||||
|
context_entry["file_name"] = cache_entry.get("file_name")
|
||||||
if isinstance(preview, str) and preview:
|
if isinstance(preview, str) and preview:
|
||||||
context_entry["preview_override"] = config.get_preview_static_url(
|
context_entry["preview_override"] = config.get_preview_static_url(
|
||||||
preview
|
preview
|
||||||
)
|
)
|
||||||
context[version.version_id] = context_entry
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -163,6 +163,18 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-version-row.is-clickable .version-actions,
|
||||||
|
.model-version-row.is-clickable .version-badges,
|
||||||
|
.model-version-row.is-clickable .version-action,
|
||||||
|
.model-version-row.is-clickable .version-civitai-link {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-version-row.is-clickable .version-action,
|
||||||
|
.model-version-row.is-clickable .version-civitai-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.model-version-row.is-current {
|
.model-version-row.is-current {
|
||||||
border-color: var(--lora-accent);
|
border-color: var(--lora-accent);
|
||||||
box-shadow: 0 0 0 1px color-mix(in oklch, var(--lora-accent) 65%, transparent),
|
box-shadow: 0 0 0 1px color-mix(in oklch, var(--lora-accent) 65%, transparent),
|
||||||
@@ -217,6 +229,7 @@
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.versions-tab-version-name {
|
.versions-tab-version-name {
|
||||||
@@ -226,6 +239,27 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.version-civitai-link {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 999px;
|
||||||
|
color: var(--text-muted);
|
||||||
|
text-decoration: none;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
transition: color 0.2s ease, background-color 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version-civitai-link:hover,
|
||||||
|
.version-civitai-link:focus-visible {
|
||||||
|
color: var(--lora-accent);
|
||||||
|
background: color-mix(in oklch, var(--lora-accent) 12%, transparent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
.version-badges {
|
.version-badges {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -21,6 +21,27 @@
|
|||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.downloaded-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: color-mix(in oklch, var(--badge-update-bg, #4a90e2) 22%, transparent);
|
||||||
|
color: var(--badge-update-bg, #4a90e2);
|
||||||
|
border: 1px solid color-mix(in oklch, var(--badge-update-bg, #4a90e2) 50%, transparent);
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: var(--border-radius-xs);
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transform: translateZ(0);
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.downloaded-badge i {
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
/* Early Access Badge */
|
/* Early Access Badge */
|
||||||
.early-access-badge {
|
.early-access-badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|||||||
@@ -220,8 +220,31 @@ function buildMetaMarkup(version, options = {}) {
|
|||||||
.join('<span class="version-meta-separator">•</span>');
|
.join('<span class="version-meta-separator">•</span>');
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildBadge(label, tone) {
|
function buildBadge(label, tone, options = {}) {
|
||||||
return `<span class="version-badge version-badge-${tone}">${escapeHtml(label)}</span>`;
|
const attributes = [];
|
||||||
|
if (options.title) {
|
||||||
|
attributes.push(`title="${escapeHtml(options.title)}"`);
|
||||||
|
}
|
||||||
|
if (options.ariaLabel) {
|
||||||
|
attributes.push(`aria-label="${escapeHtml(options.ariaLabel)}"`);
|
||||||
|
}
|
||||||
|
const suffix = attributes.length ? ` ${attributes.join(' ')}` : '';
|
||||||
|
return `<span class="version-badge version-badge-${tone}"${suffix}>${escapeHtml(label)}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildActionButton(label, variant, action, options = {}) {
|
||||||
|
const attributes = [
|
||||||
|
`class="version-action ${variant}"`,
|
||||||
|
`data-version-action="${escapeHtml(action)}"`,
|
||||||
|
];
|
||||||
|
if (options.title) {
|
||||||
|
attributes.push(`title="${escapeHtml(options.title)}"`);
|
||||||
|
attributes.push(`aria-label="${escapeHtml(options.title)}"`);
|
||||||
|
}
|
||||||
|
if (options.extraAttributes) {
|
||||||
|
attributes.push(options.extraAttributes);
|
||||||
|
}
|
||||||
|
return `<button ${attributes.join(' ')}>${options.iconMarkup || ''}${escapeHtml(label)}</button>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DISPLAY_FILTER_MODES = Object.freeze({
|
const DISPLAY_FILTER_MODES = Object.freeze({
|
||||||
@@ -426,23 +449,72 @@ function renderRow(version, options) {
|
|||||||
version.versionId > latestLibraryVersionId;
|
version.versionId > latestLibraryVersionId;
|
||||||
const isEarlyAccess = isEarlyAccessActive(version);
|
const isEarlyAccess = isEarlyAccessActive(version);
|
||||||
const badges = [];
|
const badges = [];
|
||||||
|
const openedBadgeLabel = translate('modals.model.versions.badges.current', {}, 'Opened Version');
|
||||||
|
const inLibraryBadgeLabel = translate('modals.model.versions.badges.inLibrary', {}, 'In Library');
|
||||||
|
const downloadedBadgeLabel = translate('modals.model.versions.badges.downloaded', {}, 'Downloaded');
|
||||||
|
const newerBadgeLabel = translate('modals.model.versions.badges.newer', {}, 'Newer Version');
|
||||||
|
const earlyAccessBadgeLabel = translate('modals.model.versions.badges.earlyAccess', {}, 'Early Access');
|
||||||
|
const ignoredBadgeLabel = translate('modals.model.versions.badges.ignored', {}, 'Ignored');
|
||||||
|
const versionName = version.name || translate('modals.model.versions.labels.unnamed', {}, 'Untitled Version');
|
||||||
|
|
||||||
if (isCurrent) {
|
if (isCurrent) {
|
||||||
badges.push(buildBadge(translate('modals.model.versions.badges.current', {}, 'Current Version'), 'current'));
|
badges.push(buildBadge(openedBadgeLabel, 'current', {
|
||||||
|
title: translate(
|
||||||
|
'modals.model.versions.badges.currentTooltip',
|
||||||
|
{},
|
||||||
|
'This is the version you opened this modal from'
|
||||||
|
),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version.isInLibrary) {
|
if (version.isInLibrary) {
|
||||||
badges.push(buildBadge(translate('modals.model.versions.badges.inLibrary', {}, 'In Library'), 'success'));
|
badges.push(buildBadge(inLibraryBadgeLabel, 'success', {
|
||||||
} else if (isNewer && !version.shouldIgnore) {
|
title: translate(
|
||||||
badges.push(buildBadge(translate('modals.model.versions.badges.newer', {}, 'Newer Version'), 'info'));
|
'modals.model.versions.badges.inLibraryTooltip',
|
||||||
|
{},
|
||||||
|
'This version exists in your local library'
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!version.isInLibrary && version.hasBeenDownloaded) {
|
||||||
|
badges.push(buildBadge(downloadedBadgeLabel, 'info', {
|
||||||
|
title: translate(
|
||||||
|
'modals.model.versions.badges.downloadedTooltip',
|
||||||
|
{},
|
||||||
|
'This version was downloaded before, but is not currently in your library'
|
||||||
|
),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!version.isInLibrary && isNewer && !version.shouldIgnore) {
|
||||||
|
badges.push(buildBadge(newerBadgeLabel, 'info', {
|
||||||
|
title: translate(
|
||||||
|
'modals.model.versions.badges.newerTooltip',
|
||||||
|
{},
|
||||||
|
'This version is newer than your latest local version'
|
||||||
|
),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEarlyAccess) {
|
if (isEarlyAccess) {
|
||||||
badges.push(buildBadge(translate('modals.model.versions.badges.earlyAccess', {}, 'Early Access'), 'early-access'));
|
badges.push(buildBadge(earlyAccessBadgeLabel, 'early-access', {
|
||||||
|
title: translate(
|
||||||
|
'modals.model.versions.badges.earlyAccessTooltip',
|
||||||
|
{},
|
||||||
|
'This version currently requires Civitai early access'
|
||||||
|
),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version.shouldIgnore) {
|
if (version.shouldIgnore) {
|
||||||
badges.push(buildBadge(translate('modals.model.versions.badges.ignored', {}, 'Ignored'), 'muted'));
|
badges.push(buildBadge(ignoredBadgeLabel, 'muted', {
|
||||||
|
title: translate(
|
||||||
|
'modals.model.versions.badges.ignoredTooltip',
|
||||||
|
{},
|
||||||
|
'Update notifications are disabled for this version'
|
||||||
|
),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadLabel = translate('modals.model.versions.actions.download', {}, 'Download');
|
const downloadLabel = translate('modals.model.versions.actions.download', {}, 'Download');
|
||||||
@@ -459,29 +531,82 @@ function renderRow(version, options) {
|
|||||||
if (!version.isInLibrary) {
|
if (!version.isInLibrary) {
|
||||||
// Download button with optional EA bolt icon
|
// Download button with optional EA bolt icon
|
||||||
const downloadIcon = isEarlyAccess ? '<i class="fas fa-bolt"></i> ' : '';
|
const downloadIcon = isEarlyAccess ? '<i class="fas fa-bolt"></i> ' : '';
|
||||||
actions.push(
|
actions.push(buildActionButton(
|
||||||
`<button class="version-action version-action-primary" data-version-action="download">${downloadIcon}${escapeHtml(downloadLabel)}</button>`
|
downloadLabel,
|
||||||
);
|
'version-action-primary',
|
||||||
|
'download',
|
||||||
|
{
|
||||||
|
title: isEarlyAccess
|
||||||
|
? translate(
|
||||||
|
'modals.model.versions.actions.downloadEarlyAccessTooltip',
|
||||||
|
{},
|
||||||
|
'Download this early access version from Civitai'
|
||||||
|
)
|
||||||
|
: translate(
|
||||||
|
'modals.model.versions.actions.downloadTooltip',
|
||||||
|
{},
|
||||||
|
'Download this version'
|
||||||
|
),
|
||||||
|
iconMarkup: downloadIcon,
|
||||||
|
}
|
||||||
|
));
|
||||||
} else if (version.filePath) {
|
} else if (version.filePath) {
|
||||||
actions.push(
|
actions.push(buildActionButton(
|
||||||
`<button class="version-action version-action-danger" data-version-action="delete">${escapeHtml(deleteLabel)}</button>`
|
deleteLabel,
|
||||||
);
|
'version-action-danger',
|
||||||
|
'delete',
|
||||||
|
{
|
||||||
|
title: translate(
|
||||||
|
'modals.model.versions.actions.deleteTooltip',
|
||||||
|
{},
|
||||||
|
'Delete this local version'
|
||||||
|
),
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
actions.push(
|
actions.push(buildActionButton(
|
||||||
`<button class="version-action version-action-ghost" data-version-action="toggle-ignore" data-ignore-state="${
|
ignoreLabel,
|
||||||
version.shouldIgnore ? 'ignored' : 'active'
|
'version-action-ghost',
|
||||||
}">${escapeHtml(ignoreLabel)}</button>`
|
'toggle-ignore',
|
||||||
);
|
{
|
||||||
|
title: version.shouldIgnore
|
||||||
|
? translate(
|
||||||
|
'modals.model.versions.actions.unignoreTooltip',
|
||||||
|
{},
|
||||||
|
'Resume update notifications for this version'
|
||||||
|
)
|
||||||
|
: translate(
|
||||||
|
'modals.model.versions.actions.ignoreTooltip',
|
||||||
|
{},
|
||||||
|
'Ignore update notifications for this version'
|
||||||
|
),
|
||||||
|
extraAttributes: `data-ignore-state="${version.shouldIgnore ? 'ignored' : 'active'}"`,
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
const linkTarget = buildCivitaiVersionUrl(
|
const linkTarget = buildCivitaiVersionUrl(
|
||||||
version.modelId || parentModelId,
|
version.modelId || parentModelId,
|
||||||
version.versionId
|
version.versionId
|
||||||
);
|
);
|
||||||
const civitaiTooltip = translate(
|
const civitaiTooltip = translate(
|
||||||
'modals.model.actions.viewOnCivitai',
|
'modals.model.versions.actions.viewVersionOnCivitai',
|
||||||
{},
|
{},
|
||||||
'View on Civitai'
|
'View version on Civitai'
|
||||||
);
|
);
|
||||||
|
const civitaiLinkMarkup = linkTarget
|
||||||
|
? `
|
||||||
|
<a
|
||||||
|
class="version-civitai-link"
|
||||||
|
href="${escapeHtml(linkTarget)}"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
title="${escapeHtml(civitaiTooltip)}"
|
||||||
|
aria-label="${escapeHtml(civitaiTooltip)}"
|
||||||
|
>
|
||||||
|
<i class="fas fa-arrow-up-right-from-square" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
`
|
||||||
|
: '';
|
||||||
|
|
||||||
const rowAttributes = [
|
const rowAttributes = [
|
||||||
`class="model-version-row${isCurrent ? ' is-current' : ''}${linkTarget ? ' is-clickable' : ''}${isEarlyAccess ? ' is-early-access' : ''}"`,
|
`class="model-version-row${isCurrent ? ' is-current' : ''}${linkTarget ? ' is-clickable' : ''}${isEarlyAccess ? ' is-early-access' : ''}"`,
|
||||||
@@ -489,7 +614,6 @@ function renderRow(version, options) {
|
|||||||
];
|
];
|
||||||
if (linkTarget) {
|
if (linkTarget) {
|
||||||
rowAttributes.push(`data-civitai-url="${escapeHtml(linkTarget)}"`);
|
rowAttributes.push(`data-civitai-url="${escapeHtml(linkTarget)}"`);
|
||||||
rowAttributes.push(`title="${escapeHtml(civitaiTooltip)}"`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
@@ -497,7 +621,8 @@ function renderRow(version, options) {
|
|||||||
${renderMediaMarkup(version)}
|
${renderMediaMarkup(version)}
|
||||||
<div class="version-details">
|
<div class="version-details">
|
||||||
<div class="version-title">
|
<div class="version-title">
|
||||||
<span class="versions-tab-version-name">${escapeHtml(version.name || translate('modals.model.versions.labels.unnamed', {}, 'Untitled Version'))}</span>
|
<span class="versions-tab-version-name">${escapeHtml(versionName)}</span>
|
||||||
|
${civitaiLinkMarkup}
|
||||||
</div>
|
</div>
|
||||||
<div class="version-badges">${badges.join('')}</div>
|
<div class="version-badges">${badges.join('')}</div>
|
||||||
<div class="version-meta">
|
<div class="version-meta">
|
||||||
@@ -1230,6 +1355,7 @@ export function initVersionsTab({
|
|||||||
if (!row) {
|
if (!row) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.target.closest('button')) {
|
if (event.target.closest('button')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ export class DownloadManager {
|
|||||||
(version.files[0]?.sizeKB / 1024).toFixed(2);
|
(version.files[0]?.sizeKB / 1024).toFixed(2);
|
||||||
|
|
||||||
const existsLocally = version.existsLocally;
|
const existsLocally = version.existsLocally;
|
||||||
|
const hasBeenDownloaded = version.hasBeenDownloaded && !existsLocally;
|
||||||
const localPath = version.localPath;
|
const localPath = version.localPath;
|
||||||
const isEarlyAccess = version.availability === 'EarlyAccess';
|
const isEarlyAccess = version.availability === 'EarlyAccess';
|
||||||
|
|
||||||
@@ -262,11 +263,22 @@ export class DownloadManager {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const localStatus = existsLocally ?
|
let localStatus = '';
|
||||||
`<div class="local-badge">
|
if (existsLocally) {
|
||||||
|
localStatus = `<div class="local-badge">
|
||||||
<i class="fas fa-check"></i> ${translate('modals.download.inLibrary')}
|
<i class="fas fa-check"></i> ${translate('modals.download.inLibrary')}
|
||||||
<div class="local-path">${localPath || ''}</div>
|
<div class="local-path">${localPath || ''}</div>
|
||||||
</div>` : '';
|
</div>`;
|
||||||
|
} else if (hasBeenDownloaded) {
|
||||||
|
const downloadedTooltip = translate(
|
||||||
|
'modals.download.downloadedTooltip',
|
||||||
|
{},
|
||||||
|
'Previously downloaded, but it is not currently in your library.'
|
||||||
|
);
|
||||||
|
localStatus = `<div class="downloaded-badge" title="${downloadedTooltip.replace(/"/g, '"')}">
|
||||||
|
<i class="fas fa-history"></i> ${translate('modals.download.downloaded', {}, 'Downloaded')}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="version-item ${this.currentVersion?.id === version.id ? 'selected' : ''}
|
<div class="version-item ${this.currentVersion?.id === version.id ? 'selected' : ''}
|
||||||
|
|||||||
@@ -349,4 +349,59 @@ describe('ModelVersionsTab media rendering', () => {
|
|||||||
);
|
);
|
||||||
expect(firstBadges).toContain('Newer Version');
|
expect(firstBadges).toContain('Newer Version');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows downloaded badge only for previously downloaded versions that are not in library', async () => {
|
||||||
|
fetchModelUpdateVersions.mockResolvedValue({
|
||||||
|
success: true,
|
||||||
|
record: {
|
||||||
|
shouldIgnore: false,
|
||||||
|
inLibraryVersionIds: [8],
|
||||||
|
versions: [
|
||||||
|
{
|
||||||
|
versionId: 9,
|
||||||
|
name: 'History only',
|
||||||
|
baseModel: 'SDXL',
|
||||||
|
previewUrl: '/api/lm/previews/v9.png',
|
||||||
|
sizeBytes: 1024,
|
||||||
|
isInLibrary: false,
|
||||||
|
hasBeenDownloaded: true,
|
||||||
|
shouldIgnore: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versionId: 8,
|
||||||
|
name: 'Local copy',
|
||||||
|
baseModel: 'SDXL',
|
||||||
|
previewUrl: '/api/lm/previews/v8.png',
|
||||||
|
sizeBytes: 2048,
|
||||||
|
isInLibrary: true,
|
||||||
|
hasBeenDownloaded: true,
|
||||||
|
shouldIgnore: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { initVersionsTab } = await import(MODEL_VERSIONS_MODULE);
|
||||||
|
const controller = initVersionsTab({
|
||||||
|
modalId: 'model-versions-modal',
|
||||||
|
modelType: 'loras',
|
||||||
|
modelId: 654,
|
||||||
|
currentVersionId: 8,
|
||||||
|
});
|
||||||
|
|
||||||
|
await controller.load();
|
||||||
|
|
||||||
|
const rows = document.querySelectorAll('.model-version-row');
|
||||||
|
const historyBadges = Array.from(rows[0].querySelectorAll('.version-badge')).map(
|
||||||
|
badge => badge.textContent?.trim()
|
||||||
|
);
|
||||||
|
const localBadges = Array.from(rows[1].querySelectorAll('.version-badge')).map(
|
||||||
|
badge => badge.textContent?.trim()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(historyBadges).toContain('Downloaded');
|
||||||
|
expect(historyBadges).not.toContain('In Library');
|
||||||
|
expect(localBadges).toContain('In Library');
|
||||||
|
expect(localBadges).not.toContain('Downloaded');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
139
tests/frontend/managers/downloadManager.history.test.js
Normal file
139
tests/frontend/managers/downloadManager.history.test.js
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
const {
|
||||||
|
DOWNLOAD_MANAGER_MODULE,
|
||||||
|
MODAL_MANAGER_MODULE,
|
||||||
|
UI_HELPERS_MODULE,
|
||||||
|
STATE_MODULE,
|
||||||
|
LOADING_MANAGER_MODULE,
|
||||||
|
API_FACTORY_MODULE,
|
||||||
|
STORAGE_HELPERS_MODULE,
|
||||||
|
FOLDER_TREE_MANAGER_MODULE,
|
||||||
|
I18N_HELPERS_MODULE,
|
||||||
|
} = vi.hoisted(() => ({
|
||||||
|
DOWNLOAD_MANAGER_MODULE: new URL('../../../static/js/managers/DownloadManager.js', import.meta.url).pathname,
|
||||||
|
MODAL_MANAGER_MODULE: new URL('../../../static/js/managers/ModalManager.js', import.meta.url).pathname,
|
||||||
|
UI_HELPERS_MODULE: new URL('../../../static/js/utils/uiHelpers.js', import.meta.url).pathname,
|
||||||
|
STATE_MODULE: new URL('../../../static/js/state/index.js', import.meta.url).pathname,
|
||||||
|
LOADING_MANAGER_MODULE: new URL('../../../static/js/managers/LoadingManager.js', import.meta.url).pathname,
|
||||||
|
API_FACTORY_MODULE: new URL('../../../static/js/api/modelApiFactory.js', import.meta.url).pathname,
|
||||||
|
STORAGE_HELPERS_MODULE: new URL('../../../static/js/utils/storageHelpers.js', import.meta.url).pathname,
|
||||||
|
FOLDER_TREE_MANAGER_MODULE: new URL('../../../static/js/components/FolderTreeManager.js', import.meta.url).pathname,
|
||||||
|
I18N_HELPERS_MODULE: new URL('../../../static/js/utils/i18nHelpers.js', import.meta.url).pathname,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(MODAL_MANAGER_MODULE, () => ({
|
||||||
|
modalManager: {
|
||||||
|
showModal: vi.fn(),
|
||||||
|
closeModal: vi.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(UI_HELPERS_MODULE, () => ({
|
||||||
|
showToast: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(STATE_MODULE, () => ({
|
||||||
|
state: {
|
||||||
|
global: {
|
||||||
|
settings: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(LOADING_MANAGER_MODULE, () => ({
|
||||||
|
LoadingManager: vi.fn(() => ({
|
||||||
|
showSimpleLoading: vi.fn(),
|
||||||
|
hide: vi.fn(),
|
||||||
|
restoreProgressBar: vi.fn(),
|
||||||
|
showDownloadProgress: vi.fn(() => vi.fn()),
|
||||||
|
setStatus: vi.fn(),
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(API_FACTORY_MODULE, () => ({
|
||||||
|
getModelApiClient: vi.fn(() => ({
|
||||||
|
apiConfig: {
|
||||||
|
config: {
|
||||||
|
displayName: 'LoRA',
|
||||||
|
singularName: 'lora',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
resetAndReload: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(STORAGE_HELPERS_MODULE, () => ({
|
||||||
|
getStorageItem: vi.fn((_key, defaultValue) => defaultValue),
|
||||||
|
setStorageItem: vi.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(FOLDER_TREE_MANAGER_MODULE, () => ({
|
||||||
|
FolderTreeManager: vi.fn(() => ({
|
||||||
|
clearSelection: vi.fn(),
|
||||||
|
init: vi.fn(),
|
||||||
|
})),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock(I18N_HELPERS_MODULE, () => ({
|
||||||
|
translate: vi.fn((_, __, fallback) => fallback ?? ''),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('DownloadManager version history badges', () => {
|
||||||
|
let DownloadManager;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
vi.resetModules();
|
||||||
|
document.body.innerHTML = `
|
||||||
|
<div id="urlStep"></div>
|
||||||
|
<div id="versionStep"></div>
|
||||||
|
<div id="versionList"></div>
|
||||||
|
<button id="nextFromVersion"></button>
|
||||||
|
`;
|
||||||
|
({ DownloadManager } = await import(DOWNLOAD_MANAGER_MODULE));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.innerHTML = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows downloaded badge only for versions missing locally', () => {
|
||||||
|
const manager = new DownloadManager();
|
||||||
|
manager.versions = [
|
||||||
|
{
|
||||||
|
id: 101,
|
||||||
|
name: 'History only',
|
||||||
|
images: [],
|
||||||
|
files: [{ sizeKB: 2048 }],
|
||||||
|
createdAt: '2026-01-01T00:00:00Z',
|
||||||
|
existsLocally: false,
|
||||||
|
hasBeenDownloaded: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 102,
|
||||||
|
name: 'Still local',
|
||||||
|
images: [],
|
||||||
|
files: [{ sizeKB: 2048 }],
|
||||||
|
createdAt: '2026-01-01T00:00:00Z',
|
||||||
|
existsLocally: true,
|
||||||
|
hasBeenDownloaded: true,
|
||||||
|
localPath: '/models/still-local.safetensors',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
manager.showVersionStep();
|
||||||
|
|
||||||
|
const items = document.querySelectorAll('.version-item');
|
||||||
|
expect(items).toHaveLength(2);
|
||||||
|
|
||||||
|
expect(items[0].querySelector('.downloaded-badge')?.textContent).toContain('Downloaded');
|
||||||
|
expect(items[0].querySelector('.downloaded-badge')?.getAttribute('title')).toContain(
|
||||||
|
'Previously downloaded, but it is not currently in your library.'
|
||||||
|
);
|
||||||
|
expect(items[0].querySelector('.local-badge')).toBeNull();
|
||||||
|
|
||||||
|
expect(items[1].querySelector('.local-badge')).not.toBeNull();
|
||||||
|
expect(items[1].querySelector('.local-path')?.textContent).toContain('/models/still-local.safetensors');
|
||||||
|
expect(items[1].querySelector('.downloaded-badge')).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -6,7 +6,8 @@ from types import SimpleNamespace
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from py.config import config
|
from py.config import config
|
||||||
from py.routes.handlers.model_handlers import ModelUpdateHandler
|
from py.routes.handlers.model_handlers import ModelCivitaiHandler, ModelUpdateHandler
|
||||||
|
from py.services.service_registry import ServiceRegistry
|
||||||
from py.utils.metadata_manager import MetadataManager
|
from py.utils.metadata_manager import MetadataManager
|
||||||
from py.services.model_update_service import ModelUpdateRecord, ModelVersionRecord
|
from py.services.model_update_service import ModelUpdateRecord, ModelVersionRecord
|
||||||
|
|
||||||
@@ -91,7 +92,131 @@ async def test_build_version_context_includes_static_urls():
|
|||||||
|
|
||||||
overrides = await handler._build_version_context(record)
|
overrides = await handler._build_version_context(record)
|
||||||
expected = config.get_preview_static_url("/tmp/previews/example.png")
|
expected = config.get_preview_static_url("/tmp/previews/example.png")
|
||||||
assert overrides == {123: {"file_path": None, "file_name": None, "preview_override": expected}}
|
assert overrides == {
|
||||||
|
123: {
|
||||||
|
"file_path": None,
|
||||||
|
"file_name": None,
|
||||||
|
"preview_override": expected,
|
||||||
|
"has_been_downloaded": False,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_build_version_context_includes_download_history(monkeypatch):
|
||||||
|
cache = SimpleNamespace(version_index={})
|
||||||
|
service = DummyService(cache)
|
||||||
|
handler = ModelUpdateHandler(
|
||||||
|
service=service,
|
||||||
|
update_service=SimpleNamespace(),
|
||||||
|
metadata_provider_selector=lambda *_: None,
|
||||||
|
settings_service=SimpleNamespace(get=lambda *_: False),
|
||||||
|
logger=logging.getLogger(__name__),
|
||||||
|
)
|
||||||
|
|
||||||
|
class DummyHistoryService:
|
||||||
|
async def get_downloaded_version_ids(self, model_type, model_id):
|
||||||
|
assert model_type == "lora"
|
||||||
|
assert model_id == 42
|
||||||
|
return [123]
|
||||||
|
|
||||||
|
async def fake_history_service_factory():
|
||||||
|
return DummyHistoryService()
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
ServiceRegistry,
|
||||||
|
"get_downloaded_version_history_service",
|
||||||
|
staticmethod(fake_history_service_factory),
|
||||||
|
)
|
||||||
|
|
||||||
|
record = ModelUpdateRecord(
|
||||||
|
model_type="lora",
|
||||||
|
model_id=42,
|
||||||
|
versions=[
|
||||||
|
ModelVersionRecord(
|
||||||
|
version_id=123,
|
||||||
|
name="Downloaded",
|
||||||
|
base_model=None,
|
||||||
|
released_at=None,
|
||||||
|
size_bytes=None,
|
||||||
|
preview_url=None,
|
||||||
|
is_in_library=False,
|
||||||
|
should_ignore=False,
|
||||||
|
),
|
||||||
|
ModelVersionRecord(
|
||||||
|
version_id=124,
|
||||||
|
name="Fresh",
|
||||||
|
base_model=None,
|
||||||
|
released_at=None,
|
||||||
|
size_bytes=None,
|
||||||
|
preview_url=None,
|
||||||
|
is_in_library=False,
|
||||||
|
should_ignore=False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
last_checked_at=None,
|
||||||
|
should_ignore_model=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
overrides = await handler._build_version_context(record)
|
||||||
|
assert overrides[123]["has_been_downloaded"] is True
|
||||||
|
assert overrides[124]["has_been_downloaded"] is False
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_civitai_versions_degrades_when_download_history_unavailable(monkeypatch):
|
||||||
|
cache = SimpleNamespace(version_index={})
|
||||||
|
service = DummyService(cache)
|
||||||
|
|
||||||
|
class DummyProvider:
|
||||||
|
async def get_model_versions(self, model_id):
|
||||||
|
assert model_id == "42"
|
||||||
|
return {
|
||||||
|
"type": "lora",
|
||||||
|
"modelVersions": [
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"name": "Version 7",
|
||||||
|
"files": [],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
async def fake_history_service_factory():
|
||||||
|
raise RuntimeError("download history unavailable")
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
ServiceRegistry,
|
||||||
|
"get_downloaded_version_history_service",
|
||||||
|
staticmethod(fake_history_service_factory),
|
||||||
|
)
|
||||||
|
|
||||||
|
async def metadata_provider_factory():
|
||||||
|
return DummyProvider()
|
||||||
|
|
||||||
|
handler = ModelCivitaiHandler(
|
||||||
|
service=service,
|
||||||
|
settings_service=SimpleNamespace(get=lambda *_: False),
|
||||||
|
ws_manager=SimpleNamespace(),
|
||||||
|
logger=logging.getLogger(__name__),
|
||||||
|
metadata_provider_factory=metadata_provider_factory,
|
||||||
|
validate_model_type=lambda *_: True,
|
||||||
|
expected_model_types=lambda: "LoRA",
|
||||||
|
find_model_file=lambda *_: None,
|
||||||
|
metadata_sync=SimpleNamespace(),
|
||||||
|
metadata_refresh_use_case=SimpleNamespace(),
|
||||||
|
metadata_progress_callback=lambda *_args, **_kwargs: None,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = await handler.get_civitai_versions(
|
||||||
|
SimpleNamespace(match_info={"model_id": "42"})
|
||||||
|
)
|
||||||
|
payload = json.loads(response.text)
|
||||||
|
|
||||||
|
assert response.status == 200
|
||||||
|
assert payload[0]["id"] == 7
|
||||||
|
assert payload[0]["existsLocally"] is False
|
||||||
|
assert payload[0]["hasBeenDownloaded"] is False
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
|
|||||||
Reference in New Issue
Block a user