Categorized tags in info panel with color coding
- Artist (gold), Character (green), Copyright (purple), Species (red), General, Meta/Lore (gray) - Danbooru and e621 provide categories from API - Gelbooru/Moebooru fall back to flat tag list
This commit is contained in:
parent
9f636532c0
commit
b6c6a6222a
@ -25,6 +25,7 @@ class Post:
|
||||
source: str | None
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
tag_categories: dict[str, list[str]] = field(default_factory=dict)
|
||||
|
||||
@property
|
||||
def tag_list(self) -> list[str]:
|
||||
|
||||
@ -51,6 +51,7 @@ class DanbooruClient(BooruClient):
|
||||
source=item.get("source"),
|
||||
width=item.get("image_width", 0),
|
||||
height=item.get("image_height", 0),
|
||||
tag_categories=self._extract_tag_categories(item),
|
||||
)
|
||||
)
|
||||
return posts
|
||||
@ -105,3 +106,19 @@ class DanbooruClient(BooruClient):
|
||||
if key in item and item[key]:
|
||||
parts.append(item[key])
|
||||
return " ".join(parts) if parts else ""
|
||||
|
||||
@staticmethod
|
||||
def _extract_tag_categories(item: dict) -> dict[str, list[str]]:
|
||||
cats: dict[str, list[str]] = {}
|
||||
mapping = {
|
||||
"tag_string_artist": "Artist",
|
||||
"tag_string_character": "Character",
|
||||
"tag_string_copyright": "Copyright",
|
||||
"tag_string_general": "General",
|
||||
"tag_string_meta": "Meta",
|
||||
}
|
||||
for key, label in mapping.items():
|
||||
val = item.get(key, "")
|
||||
if val and val.strip():
|
||||
cats[label] = val.split()
|
||||
return cats
|
||||
|
||||
@ -67,6 +67,7 @@ class E621Client(BooruClient):
|
||||
source=self._get_source(item),
|
||||
width=self._get_nested(item, "file", "width") or 0,
|
||||
height=self._get_nested(item, "file", "height") or 0,
|
||||
tag_categories=self._extract_tag_categories(item),
|
||||
)
|
||||
)
|
||||
return posts
|
||||
@ -156,6 +157,23 @@ class E621Client(BooruClient):
|
||||
return tags_obj
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def _extract_tag_categories(item: dict) -> dict[str, list[str]]:
|
||||
tags_obj = item.get("tags")
|
||||
if not isinstance(tags_obj, dict):
|
||||
return {}
|
||||
cats: dict[str, list[str]] = {}
|
||||
mapping = {
|
||||
"artist": "Artist", "character": "Character",
|
||||
"copyright": "Copyright", "species": "Species",
|
||||
"general": "General", "meta": "Meta", "lore": "Lore",
|
||||
}
|
||||
for key, label in mapping.items():
|
||||
tag_list = tags_obj.get(key, [])
|
||||
if isinstance(tag_list, list) and tag_list:
|
||||
cats[label] = tag_list
|
||||
return cats
|
||||
|
||||
@staticmethod
|
||||
def _get_score(item: dict) -> int:
|
||||
"""e621 score is a dict with up/down/total."""
|
||||
|
||||
@ -136,7 +136,41 @@ class InfoPanel(QWidget):
|
||||
item = self._tags_flow.takeAt(0)
|
||||
if item.widget():
|
||||
item.widget().deleteLater()
|
||||
# Add clickable tags
|
||||
|
||||
# Tag category colors
|
||||
_CAT_COLORS = {
|
||||
"Artist": "#f2ac08",
|
||||
"Character": "#0a0",
|
||||
"Copyright": "#c0f",
|
||||
"Species": "#e44",
|
||||
"General": "",
|
||||
"Meta": "#888",
|
||||
"Lore": "#888",
|
||||
}
|
||||
|
||||
if post.tag_categories:
|
||||
# Display tags grouped by category
|
||||
for category, tags in post.tag_categories.items():
|
||||
color = _CAT_COLORS.get(category, "")
|
||||
header = QLabel(f"{category}:")
|
||||
header.setStyleSheet(
|
||||
f"font-weight: bold; margin-top: 6px; margin-bottom: 2px;"
|
||||
+ (f" color: {color};" if color else "")
|
||||
)
|
||||
self._tags_flow.addWidget(header)
|
||||
for tag in tags[:50]:
|
||||
btn = QPushButton(tag)
|
||||
btn.setFlat(True)
|
||||
btn.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
style = "QPushButton { text-align: left; padding: 1px 4px; border: none;"
|
||||
if color:
|
||||
style += f" color: {color};"
|
||||
style += " }"
|
||||
btn.setStyleSheet(style)
|
||||
btn.clicked.connect(lambda checked, t=tag: self.tag_clicked.emit(t))
|
||||
self._tags_flow.addWidget(btn)
|
||||
else:
|
||||
# Fallback: flat tag list (Gelbooru, Moebooru)
|
||||
for tag in post.tag_list[:100]:
|
||||
btn = QPushButton(tag)
|
||||
btn.setFlat(True)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user