feat(stats): enhance plugin contribution tracking and update statistics display
This commit is contained in:
@@ -89,12 +89,15 @@ class OpenWebUIStats:
|
|||||||
"action",
|
"action",
|
||||||
"filter",
|
"filter",
|
||||||
"pipe",
|
"pipe",
|
||||||
|
"pipeline",
|
||||||
"tool",
|
"tool",
|
||||||
"function",
|
"function",
|
||||||
"prompt",
|
"prompt",
|
||||||
"model",
|
"model",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
NON_PLUGIN_TYPES = {"post", "review", "comment"}
|
||||||
|
|
||||||
TYPE_ALIASES = {
|
TYPE_ALIASES = {
|
||||||
"tools": "tool",
|
"tools": "tool",
|
||||||
}
|
}
|
||||||
@@ -104,6 +107,11 @@ class OpenWebUIStats:
|
|||||||
normalized = str(post_type or "").strip().lower()
|
normalized = str(post_type or "").strip().lower()
|
||||||
return self.TYPE_ALIASES.get(normalized, normalized)
|
return self.TYPE_ALIASES.get(normalized, normalized)
|
||||||
|
|
||||||
|
def _is_published_plugin(self, post_type: str, downloads: int) -> bool:
|
||||||
|
"""Treat marketplace items with downloads > 0 as published plugins."""
|
||||||
|
normalized = self._normalize_post_type(post_type)
|
||||||
|
return downloads > 0 and normalized not in self.NON_PLUGIN_TYPES
|
||||||
|
|
||||||
def load_history(self) -> list:
|
def load_history(self) -> list:
|
||||||
"""Load history records (merge Gist + local file, keep the one with more records)"""
|
"""Load history records (merge Gist + local file, keep the one with more records)"""
|
||||||
gist_history = []
|
gist_history = []
|
||||||
@@ -199,7 +207,10 @@ class OpenWebUIStats:
|
|||||||
"total_saves": stats["total_saves"],
|
"total_saves": stats["total_saves"],
|
||||||
"followers": stats.get("user", {}).get("followers", 0),
|
"followers": stats.get("user", {}).get("followers", 0),
|
||||||
"points": stats.get("user", {}).get("total_points", 0),
|
"points": stats.get("user", {}).get("total_points", 0),
|
||||||
"contributions": stats.get("user", {}).get("contributions", 0),
|
"contributions": stats.get(
|
||||||
|
"plugin_contributions",
|
||||||
|
stats.get("user", {}).get("contributions", 0),
|
||||||
|
),
|
||||||
"posts": {p["slug"]: p["downloads"] for p in stats.get("posts", [])},
|
"posts": {p["slug"]: p["downloads"] for p in stats.get("posts", [])},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,8 +279,11 @@ class OpenWebUIStats:
|
|||||||
- prev.get("followers", 0),
|
- prev.get("followers", 0),
|
||||||
"points": stats.get("user", {}).get("total_points", 0)
|
"points": stats.get("user", {}).get("total_points", 0)
|
||||||
- prev.get("points", 0),
|
- prev.get("points", 0),
|
||||||
"contributions": stats.get("user", {}).get("contributions", 0)
|
"contributions": stats.get(
|
||||||
- prev.get("contributions", 0),
|
"plugin_contributions",
|
||||||
|
stats.get("user", {}).get("contributions", 0),
|
||||||
|
)
|
||||||
|
- prev.get("contributions", prev.get("plugin_contributions", 0)),
|
||||||
"posts": {
|
"posts": {
|
||||||
p["slug"]: p["downloads"]
|
p["slug"]: p["downloads"]
|
||||||
- prev.get("posts", {}).get(p["slug"], p["downloads"])
|
- prev.get("posts", {}).get(p["slug"], p["downloads"])
|
||||||
@@ -601,6 +615,7 @@ class OpenWebUIStats:
|
|||||||
"total_downvotes": 0,
|
"total_downvotes": 0,
|
||||||
"total_saves": 0,
|
"total_saves": 0,
|
||||||
"total_comments": 0,
|
"total_comments": 0,
|
||||||
|
"plugin_contributions": 0,
|
||||||
"by_type": {},
|
"by_type": {},
|
||||||
"posts": [],
|
"posts": [],
|
||||||
"user": {}, # User info
|
"user": {}, # User info
|
||||||
@@ -629,19 +644,21 @@ class OpenWebUIStats:
|
|||||||
meta = plugin_obj.get("meta", {}) or {}
|
meta = plugin_obj.get("meta", {}) or {}
|
||||||
manifest = meta.get("manifest", {}) or {}
|
manifest = meta.get("manifest", {}) or {}
|
||||||
|
|
||||||
# Accumulate statistics
|
|
||||||
post_downloads = post.get("downloads", 0)
|
post_downloads = post.get("downloads", 0)
|
||||||
post_views = post.get("views", 0)
|
post_views = post.get("views", 0)
|
||||||
|
post_saves = post.get("saveCount", 0)
|
||||||
|
is_published_plugin = self._is_published_plugin(post_type, post_downloads)
|
||||||
|
|
||||||
stats["total_downloads"] += post_downloads
|
|
||||||
stats["total_upvotes"] += post.get("upvotes", 0)
|
stats["total_upvotes"] += post.get("upvotes", 0)
|
||||||
stats["total_downvotes"] += post.get("downvotes", 0)
|
stats["total_downvotes"] += post.get("downvotes", 0)
|
||||||
stats["total_saves"] += post.get("saveCount", 0)
|
|
||||||
stats["total_comments"] += post.get("commentCount", 0)
|
stats["total_comments"] += post.get("commentCount", 0)
|
||||||
|
|
||||||
# Key: only count views for posts with actual downloads (exclude post/review types)
|
# Plugin-only marketplace totals: published items with downloads > 0.
|
||||||
if post_type not in ("post", "review") and post_downloads > 0:
|
if is_published_plugin:
|
||||||
|
stats["total_downloads"] += post_downloads
|
||||||
stats["total_views"] += post_views
|
stats["total_views"] += post_views
|
||||||
|
stats["total_saves"] += post_saves
|
||||||
|
stats["plugin_contributions"] += 1
|
||||||
if post_type not in stats["by_type"]:
|
if post_type not in stats["by_type"]:
|
||||||
stats["by_type"][post_type] = 0
|
stats["by_type"][post_type] = 0
|
||||||
stats["by_type"][post_type] += 1
|
stats["by_type"][post_type] += 1
|
||||||
@@ -661,8 +678,9 @@ class OpenWebUIStats:
|
|||||||
"downloads": post.get("downloads", 0),
|
"downloads": post.get("downloads", 0),
|
||||||
"views": post.get("views", 0),
|
"views": post.get("views", 0),
|
||||||
"upvotes": post.get("upvotes", 0),
|
"upvotes": post.get("upvotes", 0),
|
||||||
"saves": post.get("saveCount", 0),
|
"saves": post_saves,
|
||||||
"comments": post.get("commentCount", 0),
|
"comments": post.get("commentCount", 0),
|
||||||
|
"is_published_plugin": is_published_plugin,
|
||||||
"created_at": created_at.strftime("%Y-%m-%d"),
|
"created_at": created_at.strftime("%Y-%m-%d"),
|
||||||
"updated_at": updated_at.strftime("%Y-%m-%d"),
|
"updated_at": updated_at.strftime("%Y-%m-%d"),
|
||||||
"url": f"https://openwebui.com/posts/{post.get('slug', '')}",
|
"url": f"https://openwebui.com/posts/{post.get('slug', '')}",
|
||||||
@@ -688,10 +706,11 @@ class OpenWebUIStats:
|
|||||||
print("📈 Overview")
|
print("📈 Overview")
|
||||||
print("-" * 40)
|
print("-" * 40)
|
||||||
print(f" 📝 Posts: {stats['total_posts']}")
|
print(f" 📝 Posts: {stats['total_posts']}")
|
||||||
print(f" ⬇️ Total Downloads: {stats['total_downloads']}")
|
print(f" 🧩 Published Plugins: {stats['plugin_contributions']}")
|
||||||
print(f" 👁️ Total Views: {stats['total_views']}")
|
print(f" ⬇️ Plugin Downloads: {stats['total_downloads']}")
|
||||||
|
print(f" 👁️ Plugin Views: {stats['total_views']}")
|
||||||
print(f" 👍 Total Upvotes: {stats['total_upvotes']}")
|
print(f" 👍 Total Upvotes: {stats['total_upvotes']}")
|
||||||
print(f" 💾 Total Saves: {stats['total_saves']}")
|
print(f" 💾 Plugin Saves: {stats['total_saves']}")
|
||||||
print(f" 💬 Total Comments: {stats['total_comments']}")
|
print(f" 💬 Total Comments: {stats['total_comments']}")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
@@ -745,13 +764,14 @@ class OpenWebUIStats:
|
|||||||
"overview_title": "## 📈 总览",
|
"overview_title": "## 📈 总览",
|
||||||
"overview_header": "| 指标 | 数值 |",
|
"overview_header": "| 指标 | 数值 |",
|
||||||
"posts": "📝 发布数量",
|
"posts": "📝 发布数量",
|
||||||
"downloads": "⬇️ 总下载量",
|
"downloads": "⬇️ 插件总下载量",
|
||||||
"views": "👁️ 总浏览量",
|
"views": "👁️ 插件总浏览量",
|
||||||
"upvotes": "👍 总点赞数",
|
"upvotes": "👍 总点赞数",
|
||||||
"saves": "💾 总收藏数",
|
"saves": "💾 插件总收藏数",
|
||||||
"comments": "💬 总评论数",
|
"comments": "💬 总评论数",
|
||||||
"author_points": "⭐ 作者总积分",
|
"author_points": "⭐ 作者总积分",
|
||||||
"author_followers": "👥 粉丝数量",
|
"author_followers": "👥 粉丝数量",
|
||||||
|
"author_contributions": "🧩 已发布插件数",
|
||||||
"type_title": "## 📂 按类型分类",
|
"type_title": "## 📂 按类型分类",
|
||||||
"list_title": "## 📋 发布列表",
|
"list_title": "## 📋 发布列表",
|
||||||
"list_header": "| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |",
|
"list_header": "| 排名 | 标题 | 类型 | 版本 | 下载 | 浏览 | 点赞 | 收藏 | 更新日期 |",
|
||||||
@@ -762,13 +782,14 @@ class OpenWebUIStats:
|
|||||||
"overview_title": "## 📈 Overview",
|
"overview_title": "## 📈 Overview",
|
||||||
"overview_header": "| Metric | Value |",
|
"overview_header": "| Metric | Value |",
|
||||||
"posts": "📝 Total Posts",
|
"posts": "📝 Total Posts",
|
||||||
"downloads": "⬇️ Total Downloads",
|
"downloads": "⬇️ Total Plugin Downloads",
|
||||||
"views": "👁️ Total Views",
|
"views": "👁️ Total Plugin Views",
|
||||||
"upvotes": "👍 Total Upvotes",
|
"upvotes": "👍 Total Upvotes",
|
||||||
"saves": "💾 Total Saves",
|
"saves": "💾 Total Plugin Saves",
|
||||||
"comments": "💬 Total Comments",
|
"comments": "💬 Total Comments",
|
||||||
"author_points": "⭐ Author Points",
|
"author_points": "⭐ Author Points",
|
||||||
"author_followers": "👥 Followers",
|
"author_followers": "👥 Followers",
|
||||||
|
"author_contributions": "🧩 Published Plugins",
|
||||||
"type_title": "## 📂 By Type",
|
"type_title": "## 📂 By Type",
|
||||||
"list_title": "## 📋 Posts List",
|
"list_title": "## 📋 Posts List",
|
||||||
"list_header": "| Rank | Title | Type | Version | Downloads | Views | Upvotes | Saves | Updated |",
|
"list_header": "| Rank | Title | Type | Version | Downloads | Views | Upvotes | Saves | Updated |",
|
||||||
@@ -815,6 +836,9 @@ class OpenWebUIStats:
|
|||||||
md.append(
|
md.append(
|
||||||
f"| {t['author_followers']} | {self.get_badge('followers', stats, user, delta)} |"
|
f"| {t['author_followers']} | {self.get_badge('followers', stats, user, delta)} |"
|
||||||
)
|
)
|
||||||
|
md.append(
|
||||||
|
f"| {t['author_contributions']} | {self.get_badge('contributions', stats, user, delta)} |"
|
||||||
|
)
|
||||||
|
|
||||||
md.append("")
|
md.append("")
|
||||||
|
|
||||||
@@ -914,6 +938,12 @@ class OpenWebUIStats:
|
|||||||
"color": "blue",
|
"color": "blue",
|
||||||
"namedLogo": "openwebui",
|
"namedLogo": "openwebui",
|
||||||
},
|
},
|
||||||
|
"views": {
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"label": "views",
|
||||||
|
"message": format_number(stats["total_views"]),
|
||||||
|
"color": "blueviolet",
|
||||||
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"label": "plugins",
|
"label": "plugins",
|
||||||
@@ -932,6 +962,18 @@ class OpenWebUIStats:
|
|||||||
"message": format_number(stats.get("user", {}).get("total_points", 0)),
|
"message": format_number(stats.get("user", {}).get("total_points", 0)),
|
||||||
"color": "orange",
|
"color": "orange",
|
||||||
},
|
},
|
||||||
|
"saves": {
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"label": "saves",
|
||||||
|
"message": format_number(stats["total_saves"]),
|
||||||
|
"color": "lightgrey",
|
||||||
|
},
|
||||||
|
"contributions": {
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"label": "contributions",
|
||||||
|
"message": str(stats.get("plugin_contributions", 0)),
|
||||||
|
"color": "green",
|
||||||
|
},
|
||||||
"upvotes": {
|
"upvotes": {
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"label": "upvotes",
|
"label": "upvotes",
|
||||||
@@ -960,8 +1002,6 @@ class OpenWebUIStats:
|
|||||||
if not (self.gist_token and self.gist_id):
|
if not (self.gist_token and self.gist_id):
|
||||||
return
|
return
|
||||||
|
|
||||||
delta = self.get_stat_delta(stats)
|
|
||||||
|
|
||||||
# Define badge config {key: (label, value, color)}
|
# Define badge config {key: (label, value, color)}
|
||||||
badges_config = {
|
badges_config = {
|
||||||
"downloads": ("Downloads", stats["total_downloads"], "brightgreen"),
|
"downloads": ("Downloads", stats["total_downloads"], "brightgreen"),
|
||||||
@@ -980,7 +1020,7 @@ class OpenWebUIStats:
|
|||||||
),
|
),
|
||||||
"contributions": (
|
"contributions": (
|
||||||
"Contributions",
|
"Contributions",
|
||||||
stats.get("user", {}).get("contributions", 0),
|
stats.get("plugin_contributions", 0),
|
||||||
"green",
|
"green",
|
||||||
),
|
),
|
||||||
"posts": ("Posts", stats["total_posts"], "informational"),
|
"posts": ("Posts", stats["total_posts"], "informational"),
|
||||||
@@ -988,22 +1028,12 @@ class OpenWebUIStats:
|
|||||||
|
|
||||||
files_payload = {}
|
files_payload = {}
|
||||||
for key, (label, val, color) in badges_config.items():
|
for key, (label, val, color) in badges_config.items():
|
||||||
diff = delta.get(key, 0)
|
|
||||||
if isinstance(diff, dict):
|
|
||||||
diff = 0 # Avoid dict vs int comparison error with 'posts' key
|
|
||||||
|
|
||||||
message = f"{val}"
|
|
||||||
if diff > 0:
|
|
||||||
message += f" (+{diff}🚀)"
|
|
||||||
elif diff < 0:
|
|
||||||
message += f" ({diff})"
|
|
||||||
|
|
||||||
# Build Shields.io endpoint JSON
|
# Build Shields.io endpoint JSON
|
||||||
# 参考: https://shields.io/badges/endpoint-badge
|
# 参考: https://shields.io/badges/endpoint-badge
|
||||||
badge_data = {
|
badge_data = {
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"label": label,
|
"label": label,
|
||||||
"message": message,
|
"message": f"{val}",
|
||||||
"color": color,
|
"color": color,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1013,22 +1043,18 @@ class OpenWebUIStats:
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Generate top 6 plugins badges (based on slots p1, p2...)
|
# Generate top 6 plugins badges (based on slots p1, p2...)
|
||||||
post_deltas = delta.get("posts", {})
|
top_plugin_posts = [
|
||||||
for i, post in enumerate(stats.get("posts", [])[:6]):
|
post for post in stats.get("posts", []) if post.get("is_published_plugin")
|
||||||
|
][:6]
|
||||||
|
for i, post in enumerate(top_plugin_posts):
|
||||||
idx = i + 1
|
idx = i + 1
|
||||||
diff = post_deltas.get(post["slug"], 0)
|
|
||||||
|
|
||||||
# Downloads badge
|
|
||||||
dl_msg = f"{post['downloads']}"
|
|
||||||
if diff > 0:
|
|
||||||
dl_msg += f" (+{diff}🚀)"
|
|
||||||
|
|
||||||
files_payload[f"badge_p{idx}_dl.json"] = {
|
files_payload[f"badge_p{idx}_dl.json"] = {
|
||||||
"content": json.dumps(
|
"content": json.dumps(
|
||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"label": "Downloads",
|
"label": "Downloads",
|
||||||
"message": dl_msg,
|
"message": f"{post['downloads']}",
|
||||||
"color": "brightgreen",
|
"color": "brightgreen",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1062,19 +1088,13 @@ class OpenWebUIStats:
|
|||||||
# 生成所有帖子的个体徽章 (用于详细报表)
|
# 生成所有帖子的个体徽章 (用于详细报表)
|
||||||
for post in stats.get("posts", []):
|
for post in stats.get("posts", []):
|
||||||
slug_hash = self._safe_key(post["slug"])
|
slug_hash = self._safe_key(post["slug"])
|
||||||
diff = post_deltas.get(post["slug"], 0)
|
|
||||||
|
|
||||||
# 1. Downloads
|
|
||||||
dl_msg = f"{post['downloads']}"
|
|
||||||
if diff > 0:
|
|
||||||
dl_msg += f" (+{diff}🚀)"
|
|
||||||
|
|
||||||
files_payload[f"badge_post_{slug_hash}_dl.json"] = {
|
files_payload[f"badge_post_{slug_hash}_dl.json"] = {
|
||||||
"content": json.dumps(
|
"content": json.dumps(
|
||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"label": "Downloads",
|
"label": "Downloads",
|
||||||
"message": dl_msg,
|
"message": f"{post['downloads']}",
|
||||||
"color": "brightgreen",
|
"color": "brightgreen",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1163,19 +1183,11 @@ class OpenWebUIStats:
|
|||||||
is_post: bool = False,
|
is_post: bool = False,
|
||||||
style: str = "flat",
|
style: str = "flat",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""获取 Shields.io 徽章 URL (包含增量显示)"""
|
"""获取 Shields.io 徽章 URL。"""
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
gist_user = "Fu-Jie"
|
gist_user = "Fu-Jie"
|
||||||
|
|
||||||
def _fmt_delta(k: str) -> str:
|
|
||||||
val = delta.get(k, 0)
|
|
||||||
if isinstance(val, dict):
|
|
||||||
return ""
|
|
||||||
if val > 0:
|
|
||||||
return f" <br><sub>(+{val}🚀)</sub>"
|
|
||||||
return ""
|
|
||||||
|
|
||||||
if not self.gist_id:
|
if not self.gist_id:
|
||||||
if is_post:
|
if is_post:
|
||||||
return "**-**"
|
return "**-**"
|
||||||
@@ -1185,14 +1197,14 @@ class OpenWebUIStats:
|
|||||||
if key == "points":
|
if key == "points":
|
||||||
val = user.get("total_points", 0)
|
val = user.get("total_points", 0)
|
||||||
if key == "contributions":
|
if key == "contributions":
|
||||||
val = user.get("contributions", 0)
|
val = stats.get("plugin_contributions", user.get("contributions", 0))
|
||||||
if key == "posts":
|
if key == "posts":
|
||||||
val = stats.get("total_posts", 0)
|
val = stats.get("total_posts", 0)
|
||||||
if key == "saves":
|
if key == "saves":
|
||||||
val = stats.get("total_saves", 0)
|
val = stats.get("total_saves", 0)
|
||||||
if key.startswith("updated"):
|
if key.startswith("updated"):
|
||||||
return f"🕐 {get_beijing_time().strftime('%Y-%m-%d %H:%M')}"
|
return f"🕐 {get_beijing_time().strftime('%Y-%m-%d %H:%M')}"
|
||||||
return f"**{val}**{_fmt_delta(key)}"
|
return f"**{val}**"
|
||||||
|
|
||||||
raw_url = f"https://gist.githubusercontent.com/{gist_user}/{self.gist_id}/raw/badge_{key}.json"
|
raw_url = f"https://gist.githubusercontent.com/{gist_user}/{self.gist_id}/raw/badge_{key}.json"
|
||||||
encoded_url = urllib.parse.quote(raw_url, safe="")
|
encoded_url = urllib.parse.quote(raw_url, safe="")
|
||||||
@@ -1208,30 +1220,26 @@ class OpenWebUIStats:
|
|||||||
stats: 统计数据
|
stats: 统计数据
|
||||||
lang: 语言 ("zh" 中文, "en" 英文)
|
lang: 语言 ("zh" 中文, "en" 英文)
|
||||||
"""
|
"""
|
||||||
# 获取 Top 6 插件
|
# 获取 Top 6 已发布插件
|
||||||
top_plugins = stats["posts"][:6]
|
top_plugins = [
|
||||||
|
post for post in stats["posts"] if post.get("is_published_plugin")
|
||||||
|
][:6]
|
||||||
delta = self.get_stat_delta(stats)
|
delta = self.get_stat_delta(stats)
|
||||||
|
|
||||||
def fmt_delta(key: str) -> str:
|
|
||||||
val = delta.get(key, 0)
|
|
||||||
if val > 0:
|
|
||||||
return f" <br><sub>(+{val}🚀)</sub>"
|
|
||||||
return ""
|
|
||||||
|
|
||||||
# 中英文文本
|
# 中英文文本
|
||||||
texts = {
|
texts = {
|
||||||
"zh": {
|
"zh": {
|
||||||
"title": "## 📊 社区统计",
|
"title": "## 📊 社区统计",
|
||||||
"author_header": "| 👤 作者 | 👥 粉丝 | ⭐ 积分 | 🏆 贡献 |",
|
"author_header": "| 👤 作者 | 👥 粉丝 | ⭐ 积分 | 🧩 插件贡献 |",
|
||||||
"header": "| 📝 发布 | ⬇️ 下载 | 👁️ 浏览 | 👍 点赞 | 💾 收藏 |",
|
"header": "| 📝 发布 | ⬇️ 插件下载 | 👁️ 插件浏览 | 👍 点赞 | 💾 插件收藏 |",
|
||||||
"top6_title": "### 🔥 热门插件 Top 6",
|
"top6_title": "### 🔥 热门插件 Top 6",
|
||||||
"top6_header": "| 排名 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 |",
|
"top6_header": "| 排名 | 插件 | 版本 | 下载 | 浏览 | 📅 更新 |",
|
||||||
"full_stats": "*完整统计与趋势图请查看 [社区统计报告](./docs/community-stats.zh.md)*",
|
"full_stats": "*完整统计与趋势图请查看 [社区统计报告](./docs/community-stats.zh.md)*",
|
||||||
},
|
},
|
||||||
"en": {
|
"en": {
|
||||||
"title": "## 📊 Community Stats",
|
"title": "## 📊 Community Stats",
|
||||||
"author_header": "| 👤 Author | 👥 Followers | ⭐ Points | 🏆 Contributions |",
|
"author_header": "| 👤 Author | 👥 Followers | ⭐ Points | 🧩 Plugin Contributions |",
|
||||||
"header": "| 📝 Posts | ⬇️ Downloads | 👁️ Views | 👍 Upvotes | 💾 Saves |",
|
"header": "| 📝 Posts | ⬇️ Plugin Downloads | 👁️ Plugin Views | 👍 Upvotes | 💾 Plugin Saves |",
|
||||||
"top6_title": "### 🔥 Top 6 Popular Plugins",
|
"top6_title": "### 🔥 Top 6 Popular Plugins",
|
||||||
"top6_header": "| Rank | Plugin | Version | Downloads | Views | 📅 Updated |",
|
"top6_header": "| Rank | Plugin | Version | Downloads | Views | 📅 Updated |",
|
||||||
"full_stats": "*See full stats and charts in [Community Stats Report](./docs/community-stats.md)*",
|
"full_stats": "*See full stats and charts in [Community Stats Report](./docs/community-stats.md)*",
|
||||||
|
|||||||
Reference in New Issue
Block a user