fix(jobs): keep saved text files below visual media in preview priority

This commit is contained in:
DeniDoman 2026-07-17 01:02:45 +02:00
parent 28890f0be8
commit 65afbcee66
2 changed files with 82 additions and 7 deletions

View File

@ -170,6 +170,19 @@ def is_previewable(media_type: str, item: dict) -> bool:
return False
def is_text_preview(media_type: str, item: dict) -> bool:
"""
Check if a previewable output item is textual rather than visual media.
Saved text files (SaveText's .txt/.md/.json) are real outputs but must not
outrank visual media when picking the job preview.
"""
if media_type == 'text':
return True
filename = item.get('filename', '').lower()
return any(filename.endswith(ext) for ext in TEXT_EXTENSIONS)
def normalize_queue_item(item: tuple, status: str) -> dict:
"""Convert queue item tuple to unified job dict.
@ -259,13 +272,14 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
Returns (outputs_count, preview_output).
Preview priority (matching frontend):
1. type="output" media (saved images/video/audio/3d)
2. any other previewable media (e.g. temp/preview images)
3. text (only when the job produced no media output)
1. type="output" visual media (saved images/video/audio/3d)
2. any other previewable visual media (e.g. temp/preview images)
3. saved text file (e.g. SaveText's .txt/.md/.json)
4. raw text (only when the job produced nothing else previewable)
Text is kept in its own slot so node/execution order can't let a text
Text is kept in its own slots so node/execution order can't let a text
output mask a visual one (e.g. a text node that runs before an image).
Text content entries (strings under 'text') are preview-only metadata,
matching the frontend's METADATA_KEYS: they can serve as the fallback
preview but are not counted as outputs.
@ -273,6 +287,7 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
count = 0
preview_output = None
fallback_preview = None
text_file_fallback = None
text_fallback = None
for node_id, node_outputs in outputs.items():
@ -319,12 +334,15 @@ def get_outputs_summary(outputs: dict) -> tuple[int, Optional[dict]]:
}
if 'mediaType' not in item:
enriched['mediaType'] = media_type
if item.get('type') == 'output':
if is_text_preview(media_type, item):
if text_file_fallback is None:
text_file_fallback = enriched
elif item.get('type') == 'output':
preview_output = enriched
elif fallback_preview is None:
fallback_preview = enriched
return count, preview_output or fallback_preview or text_fallback
return count, preview_output or fallback_preview or text_file_fallback or text_fallback
def apply_sorting(jobs: list[dict], sort_by: str, sort_order: str) -> list[dict]:

View File

@ -303,6 +303,63 @@ class TestGetOutputsSummary:
assert preview['mediaType'] == 'text'
assert preview['content'] == 'hello world'
def test_media_preview_preferred_over_saved_text_file(self):
"""A visual output wins the preview over a saved text file (SaveText),
even a temp/preview image iterated after the text node."""
outputs = {
'save_text': {
'text': ['the text'],
'files': [{'filename': 'ComfyUI_00001.txt', 'subfolder': '', 'type': 'output'}],
},
'preview_image': {'images': [{'filename': 'preview.png', 'type': 'temp'}]},
}
count, preview = get_outputs_summary(outputs)
assert count == 2 # the .txt file and the image; raw text is metadata
assert preview['filename'] == 'preview.png'
assert preview['mediaType'] == 'images'
def test_saved_media_preferred_over_saved_text_file(self):
outputs = {
'save_text': {
'text': ['the text'],
'files': [{'filename': 'ComfyUI_00001.txt', 'subfolder': '', 'type': 'output'}],
},
'save_image': {'images': [{'filename': 'result.png', 'type': 'output'}]},
}
count, preview = get_outputs_summary(outputs)
assert count == 2
assert preview['filename'] == 'result.png'
def test_mime_format_file_preferred_over_saved_text_file(self):
"""Custom-node outputs previewable via MIME format (e.g. VHS videos
under arbitrary keys) rank as visual media, above saved text files."""
outputs = {
'save_text': {
'files': [{'filename': 'notes.md', 'subfolder': '', 'type': 'output'}],
},
'video_node': {
'files': [{'filename': 'clip.webm', 'format': 'video/webm', 'type': 'output'}],
},
}
count, preview = get_outputs_summary(outputs)
assert count == 2
assert preview['filename'] == 'clip.webm'
def test_saved_text_file_preferred_over_raw_text(self):
"""With no media in the job, the saved text file (a real, counted
output) is the preview rather than the raw text metadata."""
outputs = {
'save_text': {
'text': ['the text'],
'files': [{'filename': 'ComfyUI_00001.txt', 'subfolder': '', 'type': 'output'}],
},
}
count, preview = get_outputs_summary(outputs)
assert count == 1
assert preview['filename'] == 'ComfyUI_00001.txt'
assert preview['mediaType'] == 'files'
class TestHas3DExtension:
"""Unit tests for has_3d_extension()"""